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

- 新增 FlowableUtils 发起人 ID 变量读取方法
- 发起人部门负责人策略优先使用 PROCESS_START_USER_ID
- 补充流程变量优先场景单测
This commit is contained in:
YunaiV
2026-08-30 17:23:01 +08:00
parent 605e11bf5f
commit 922c8b834e
7 changed files with 85 additions and 12 deletions
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.d
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -88,4 +89,19 @@ public abstract class AbstractBpmTaskCandidateDeptLeaderStrategy implements BpmT
return deptApi.getDept(startUser.getDeptId());
}
/**
* 获取发起人的部门(优先使用流程变量中的发起人编号)
*
* @param startUserId 发起人 Id(流程变量不存在时使用)
* @param processVariables 流程变量
* @return 发起人的部门
*/
protected DeptRespDTO getStartUserDept(Long startUserId, Map<String, Object> processVariables) {
Long processStartUserId = FlowableUtils.getProcessInstanceStartUserId(processVariables);
if (processStartUserId != null && processStartUserId > 0) {
startUserId = processStartUserId;
}
return getStartUserDept(startUserId);
}
}
@@ -49,7 +49,7 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends AbstractBp
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
// 获取发起人的 multi 部门负责人
DeptRespDTO dept = super.getStartUserDept(startUserId);
DeptRespDTO dept = super.getStartUserDept(startUserId, processInstance.getProcessVariables());
if (dept == null) {
return new HashSet<>();
}
@@ -60,7 +60,7 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends AbstractBp
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
int level = Integer.parseInt(param); // 参数是部门的层级
DeptRespDTO dept = super.getStartUserDept(startUserId);
DeptRespDTO dept = super.getStartUserDept(startUserId, processVariables);
if (dept == null) {
return new HashSet<>();
}
@@ -48,19 +48,20 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategy extends AbstractBpmTask
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
// 获取发起人的部门负责人
return getStartUserDeptLeader(startUserId, param);
return getStartUserDeptLeader(startUserId, param, processInstance.getProcessVariables());
}
@Override
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
// 获取发起人的部门负责人
return getStartUserDeptLeader(startUserId, param);
return getStartUserDeptLeader(startUserId, param, processVariables);
}
private Set<Long> getStartUserDeptLeader(Long startUserId, String param) {
private Set<Long> getStartUserDeptLeader(Long startUserId, String param,
Map<String, Object> processVariables) {
int level = Integer.parseInt(param); // 参数是部门的层级
DeptRespDTO dept = super.getStartUserDept(startUserId);
DeptRespDTO dept = super.getStartUserDept(startUserId, processVariables);
if (dept == null) {
return new HashSet<>();
}
@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
@@ -133,6 +134,17 @@ public class FlowableUtils {
return (Integer) processVariables.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
}
/**
* 获得流程实例的发起用户 ID
*
* @param processVariables 流程实例的 variables
* @return 发起用户 ID
*/
public static Long getProcessInstanceStartUserId(Map<String, Object> processVariables) {
return processVariables == null ? null : Convert.toLong(
processVariables.get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID));
}
/**
* 获得流程实例的审批原因
*
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
@@ -14,6 +15,8 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
@@ -42,12 +45,16 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest extends BaseMo
String param = "2";
// mock 方法(获得流程发起人)
Long startUserId = 1L;
Long processVariableStartUserId = 2L;
ProcessInstance processInstance = mock(ProcessInstance.class);
DelegateExecution execution = mock(DelegateExecution.class);
when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
when(processInstance.getProcessVariables()).thenReturn(processVariables);
// mock 方法(获取发起人的 multi 部门负责人)
mockGetStartUserDept(startUserId);
mockGetStartUserDept(processVariableStartUserId);
// 调用
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
@@ -61,11 +68,14 @@ public class BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest extends BaseMo
String param = "2";
// mock 方法
Long startUserId = 1L;
mockGetStartUserDept(startUserId);
Long processVariableStartUserId = 2L;
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
mockGetStartUserDept(processVariableStartUserId);
// 调用
Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
startUserId, null, null);
startUserId, null, processVariables);
// 断言
assertEquals(Sets.newLinkedHashSet(11L, 1001L), userIds);
}
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
@@ -14,6 +15,8 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
@@ -42,12 +45,16 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategyTest extends BaseMockito
String param = "2";
// mock 方法(获得流程发起人)
Long startUserId = 1L;
Long processVariableStartUserId = 2L;
ProcessInstance processInstance = mock(ProcessInstance.class);
DelegateExecution execution = mock(DelegateExecution.class);
when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
when(processInstance.getProcessVariables()).thenReturn(processVariables);
// mock 方法(获取发起人的部门负责人)
mockGetStartUserDeptLeader(startUserId);
mockGetStartUserDeptLeader(processVariableStartUserId);
// 调用
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
@@ -61,11 +68,14 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategyTest extends BaseMockito
String param = "2";
// mock 方法
Long startUserId = 1L;
mockGetStartUserDeptLeader(startUserId);
Long processVariableStartUserId = 2L;
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, processVariableStartUserId);
mockGetStartUserDeptLeader(processVariableStartUserId);
// 调用
Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
startUserId, null, null);
startUserId, null, processVariables);
// 断言
assertEquals(Sets.newLinkedHashSet(1001L), userIds);
}
@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
@@ -22,6 +23,29 @@ import static org.junit.jupiter.api.Assertions.assertNull;
*/
class FlowableUtilsTest {
@Test
public void testGetProcessInstanceStartUserId() {
// 准备参数
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, "1");
// 调用
Long startUserId = FlowableUtils.getProcessInstanceStartUserId(processVariables);
// 断言
assertEquals(1L, startUserId);
}
@Test
public void testGetProcessInstanceStartUserId_empty() {
// 准备参数
Map<String, Object> processVariables = new HashMap<>();
// 调用 & 断言
assertNull(FlowableUtils.getProcessInstanceStartUserId(processVariables));
assertNull(FlowableUtils.getProcessInstanceStartUserId(null));
}
@Test
public void testGetSummary_customSummary_parseDbFormFields() {
// 准备参数:模拟 DB 中 form_fields 字段,列表里每个元素都是一个 form-create 字段 JSON。