Commit 922c8b834e7792befbb1564de44cb6820bcf6dc9

Authored by YunaiV
1 parent 605e11bf

fix(bpm): 使用流程变量发起人 ID计算部门负责人

- 新增 FlowableUtils 发起人 ID 变量读取方法
- 发起人部门负责人策略优先使用 PROCESS_START_USER_ID
- 补充流程变量优先场景单测
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/AbstractBpmTaskCandidateDeptLeaderStrategy.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.d
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.lang.Assert;
5 5 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
  6 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
6 7 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
7 8 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
8 9 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
... ... @@ -88,4 +89,19 @@ public abstract class AbstractBpmTaskCandidateDeptLeaderStrategy implements BpmT
88 89 return deptApi.getDept(startUser.getDeptId());
89 90 }
90 91  
  92 + /**
  93 + * 获取发起人的部门(优先使用流程变量中的发起人编号)
  94 + *
  95 + * @param startUserId 发起人 Id(流程变量不存在时使用)
  96 + * @param processVariables 流程变量
  97 + * @return 发起人的部门
  98 + */
  99 + protected DeptRespDTO getStartUserDept(Long startUserId, Map<String, Object> processVariables) {
  100 + Long processStartUserId = FlowableUtils.getProcessInstanceStartUserId(processVariables);
  101 + if (processStartUserId != null && processStartUserId > 0) {
  102 + startUserId = processStartUserId;
  103 + }
  104 + return getStartUserDept(startUserId);
  105 + }
  106 +
91 107 }
... ...
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserDeptLeaderMultiStrategy.java
... ... @@ -49,7 +49,7 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends AbstractBp
49 49 ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
50 50 Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
51 51 // 获取发起人的 multi 部门负责人
52   - DeptRespDTO dept = super.getStartUserDept(startUserId);
  52 + DeptRespDTO dept = super.getStartUserDept(startUserId, processInstance.getProcessVariables());
53 53 if (dept == null) {
54 54 return new HashSet<>();
55 55 }
... ... @@ -60,7 +60,7 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends AbstractBp
60 60 public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
61 61 Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
62 62 int level = Integer.parseInt(param); // 参数是部门的层级
63   - DeptRespDTO dept = super.getStartUserDept(startUserId);
  63 + DeptRespDTO dept = super.getStartUserDept(startUserId, processVariables);
64 64 if (dept == null) {
65 65 return new HashSet<>();
66 66 }
... ...
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserDeptLeaderStrategy.java
... ... @@ -48,19 +48,20 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategy extends AbstractBpmTask
48 48 ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
49 49 Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
50 50 // 获取发起人的部门负责人
51   - return getStartUserDeptLeader(startUserId, param);
  51 + return getStartUserDeptLeader(startUserId, param, processInstance.getProcessVariables());
52 52 }
53 53  
54 54 @Override
55 55 public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
56 56 Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
57 57 // 获取发起人的部门负责人
58   - return getStartUserDeptLeader(startUserId, param);
  58 + return getStartUserDeptLeader(startUserId, param, processVariables);
59 59 }
60 60  
61   - private Set<Long> getStartUserDeptLeader(Long startUserId, String param) {
  61 + private Set<Long> getStartUserDeptLeader(Long startUserId, String param,
  62 + Map<String, Object> processVariables) {
62 63 int level = Integer.parseInt(param); // 参数是部门的层级
63   - DeptRespDTO dept = super.getStartUserDept(startUserId);
  64 + DeptRespDTO dept = super.getStartUserDept(startUserId, processVariables);
64 65 if (dept == null) {
65 66 return new HashSet<>();
66 67 }
... ...
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
2 2  
  3 +import cn.hutool.core.convert.Convert;
3 4 import cn.hutool.core.map.MapUtil;
4 5 import cn.hutool.core.util.ObjectUtil;
5 6 import cn.hutool.core.util.StrUtil;
... ... @@ -134,6 +135,17 @@ public class FlowableUtils {
134 135 }
135 136  
136 137 /**
  138 + * 获得流程实例的发起用户 ID
  139 + *
  140 + * @param processVariables 流程实例的 variables
  141 + * @return 发起用户 ID
  142 + */
  143 + public static Long getProcessInstanceStartUserId(Map<String, Object> processVariables) {
  144 + return processVariables == null ? null : Convert.toLong(
  145 + processVariables.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID));
  146 + }
  147 +
  148 + /**
137 149 * 获得流程实例的审批原因
138 150 *
139 151 * @param processInstance 流程实例
... ...
yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
2 2  
3 3 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  4 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
4 5 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
5 6 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
6 7 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
... ... @@ -14,6 +15,8 @@ import org.mockito.InjectMocks;
14 15 import org.mockito.Mock;
15 16 import org.mockito.stubbing.Answer;
16 17  
  18 +import java.util.HashMap;
  19 +import java.util.Map;
17 20 import java.util.Set;
18 21  
19 22 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
... ... @@ -42,12 +45,16 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest extends BaseMo
42 45 String param = "2";
43 46 // mock 方法(获得流程发起人)
44 47 Long startUserId = 1L;
  48 + Long processVariableStartUserId = 2L;
45 49 ProcessInstance processInstance = mock(ProcessInstance.class);
46 50 DelegateExecution execution = mock(DelegateExecution.class);
47 51 when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
48 52 when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
  53 + Map<String, Object> processVariables = new HashMap<>();
  54 + processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
  55 + when(processInstance.getProcessVariables()).thenReturn(processVariables);
49 56 // mock 方法(获取发起人的 multi 部门负责人)
50   - mockGetStartUserDept(startUserId);
  57 + mockGetStartUserDept(processVariableStartUserId);
51 58  
52 59 // 调用
53 60 Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
... ... @@ -61,11 +68,14 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest extends BaseMo
61 68 String param = "2";
62 69 // mock 方法
63 70 Long startUserId = 1L;
64   - mockGetStartUserDept(startUserId);
  71 + Long processVariableStartUserId = 2L;
  72 + Map<String, Object> processVariables = new HashMap<>();
  73 + processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
  74 + mockGetStartUserDept(processVariableStartUserId);
65 75  
66 76 // 调用
67 77 Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
68   - startUserId, null, null);
  78 + startUserId, null, processVariables);
69 79 // 断言
70 80 assertEquals(Sets.newLinkedHashSet(11L, 1001L), userIds);
71 81 }
... ...
yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserDeptLeaderStrategyTest.java
1 1 package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
2 2  
3 3 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  4 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
4 5 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
5 6 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
6 7 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
... ... @@ -14,6 +15,8 @@ import org.mockito.InjectMocks;
14 15 import org.mockito.Mock;
15 16 import org.mockito.stubbing.Answer;
16 17  
  18 +import java.util.HashMap;
  19 +import java.util.Map;
17 20 import java.util.Set;
18 21  
19 22 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
... ... @@ -42,12 +45,16 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategyTest extends BaseMockito
42 45 String param = "2";
43 46 // mock 方法(获得流程发起人)
44 47 Long startUserId = 1L;
  48 + Long processVariableStartUserId = 2L;
45 49 ProcessInstance processInstance = mock(ProcessInstance.class);
46 50 DelegateExecution execution = mock(DelegateExecution.class);
47 51 when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
48 52 when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
  53 + Map<String, Object> processVariables = new HashMap<>();
  54 + processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
  55 + when(processInstance.getProcessVariables()).thenReturn(processVariables);
49 56 // mock 方法(获取发起人的部门负责人)
50   - mockGetStartUserDeptLeader(startUserId);
  57 + mockGetStartUserDeptLeader(processVariableStartUserId);
51 58  
52 59 // 调用
53 60 Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
... ... @@ -61,11 +68,14 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategyTest extends BaseMockito
61 68 String param = "2";
62 69 // mock 方法
63 70 Long startUserId = 1L;
64   - mockGetStartUserDeptLeader(startUserId);
  71 + Long processVariableStartUserId = 2L;
  72 + Map<String, Object> processVariables = new HashMap<>();
  73 + processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
  74 + mockGetStartUserDeptLeader(processVariableStartUserId);
65 75  
66 76 // 调用
67 77 Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
68   - startUserId, null, null);
  78 + startUserId, null, processVariables);
69 79 // 断言
70 80 assertEquals(Sets.newLinkedHashSet(1001L), userIds);
71 81 }
... ...
yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtilsTest.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
4 4 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
5 5 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
6 6 import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
  7 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
7 8 import org.junit.jupiter.api.Test;
8 9  
9 10 import java.util.Arrays;
... ... @@ -23,6 +24,29 @@ import static org.junit.jupiter.api.Assertions.assertNull;
23 24 class FlowableUtilsTest {
24 25  
25 26 @Test
  27 + public void testGetProcessInstanceStartUserId() {
  28 + // 准备参数
  29 + Map<String, Object> processVariables = new HashMap<>();
  30 + processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, "1");
  31 +
  32 + // 调用
  33 + Long startUserId = FlowableUtils.getProcessInstanceStartUserId(processVariables);
  34 +
  35 + // 断言
  36 + assertEquals(1L, startUserId);
  37 + }
  38 +
  39 + @Test
  40 + public void testGetProcessInstanceStartUserId_empty() {
  41 + // 准备参数
  42 + Map<String, Object> processVariables = new HashMap<>();
  43 +
  44 + // 调用 & 断言
  45 + assertNull(FlowableUtils.getProcessInstanceStartUserId(processVariables));
  46 + assertNull(FlowableUtils.getProcessInstanceStartUserId(null));
  47 + }
  48 +
  49 + @Test
26 50 public void testGetSummary_customSummary_parseDbFormFields() {
27 51 // 准备参数:模拟 DB 中 form_fields 字段,列表里每个元素都是一个 form-create 字段 JSON。
28 52 BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionInfo(dbFormFields(),
... ...