Commit 922c8b834e7792befbb1564de44cb6820bcf6dc9
1 parent
605e11bf
fix(bpm): 使用流程变量发起人 ID计算部门负责人
- 新增 FlowableUtils 发起人 ID 变量读取方法 - 发起人部门负责人策略优先使用 PROCESS_START_USER_ID - 补充流程变量优先场景单测
Showing
7 changed files
with
85 additions
and
12 deletions
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(), | ... | ... |