【代码重构】工作流:BpmTaskCandidateStrategy 拆分成 calculateUsers、calculateUsersByTask、calculateUsersByActivity,定位更明确

This commit is contained in:
YunaiV 2024-10-31 09:55:52 +08:00
parent 0c7fd9e1db
commit c73d7fe32b
41 changed files with 814 additions and 400 deletions

View File

@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConver
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept.BpmTaskCandidateStartUserSelectStrategy;
import cn.iocoder.yudao.module.bpm.service.definition.BpmCategoryService;
import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;

View File

@ -17,7 +17,7 @@ import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConver
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
import cn.iocoder.yudao.module.bpm.event.BpmProcessInstanceStatusEvent;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept.BpmTaskCandidateStartUserSelectStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO;

View File

@ -53,7 +53,7 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav
@SuppressWarnings("unchecked")
Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
if (assigneeUserIds == null) {
assigneeUserIds = taskCandidateInvoker.calculateUsers(execution);
assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
execution.setVariable(super.collectionVariable, assigneeUserIds);
if (CollUtil.isEmpty(assigneeUserIds)) {
// 特殊如果没有处理人的情况下至少有一个 null 空元素避免自动通过

View File

@ -46,7 +46,7 @@ public class BpmSequentialMultiInstanceBehavior extends SequentialMultiInstanceB
@SuppressWarnings("unchecked")
Set<Long> assigneeUserIds = (Set<Long>) execution.getVariable(super.collectionVariable, Set.class);
if (assigneeUserIds == null) {
assigneeUserIds = taskCandidateInvoker.calculateUsers(execution);
assigneeUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
execution.setVariable(super.collectionVariable, assigneeUserIds);
if (CollUtil.isEmpty(assigneeUserIds)) {
// 特殊如果没有处理人的情况下至少有一个 null 空元素避免自动通过

View File

@ -57,7 +57,7 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior {
// 情况二如果非多实例的任务则计算任务处理人
// 第一步先计算可处理该任务的处理人们
Set<Long> candidateUserIds = taskCandidateInvoker.calculateUsers(execution);
Set<Long> candidateUserIds = taskCandidateInvoker.calculateUsersByTask(execution);
if (CollUtil.isEmpty(candidateUserIds)) {
return null;
}

View File

@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
@ -89,31 +90,66 @@ public class BpmTaskCandidateInvoker {
* @return 用户编号集合
*/
@DataPermission(enable = false) // 忽略数据权限避免因为过滤导致找不到候选人
public Set<Long> calculateUsers(DelegateExecution execution) {
public Set<Long> calculateUsersByTask(DelegateExecution execution) {
// 审批类型非人工审核时不进行计算候选人原因是后续会自动通过不通过
Integer approveType = BpmnModelUtils.parseApproveType(execution.getCurrentFlowElement());
FlowElement flowElement = execution.getCurrentFlowElement();
Integer approveType = BpmnModelUtils.parseApproveType(flowElement);
if (ObjectUtils.equalsAny(approveType,
BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType(),
BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
return new HashSet<>();
}
Integer strategy = BpmnModelUtils.parseCandidateStrategy(execution.getCurrentFlowElement());
String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
Integer strategy = BpmnModelUtils.parseCandidateStrategy(flowElement);
String param = BpmnModelUtils.parseCandidateParam(flowElement);
// 1.1 计算任务的候选人
Set<Long> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
// 1.2 移除被禁用的用户 TODO @芋艿 calculateUsers 方法中默认已经移除了被禁用的用户, 这里还需要移除被禁用的用户吗?
Set<Long> userIds = getCandidateStrategy(strategy).calculateUsersByTask(execution, param);
// 1.2 移除被禁用的用户
removeDisableUsers(userIds);
// 2. 候选人为空时根据审批人为空的配置补充
if (CollUtil.isEmpty(userIds)) {
userIds = getCandidateStrategy(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY.getStrategy())
.calculateUsers(execution, param);
.calculateUsersByTask(execution, param);
// ASSIGN_EMPTY 策略不需要移除被禁用的用户原因是再移除可能会出现更没审批人了
}
// 3. 移除发起人的用户
removeStartUserIfSkip(execution, userIds);
ProcessInstance processInstance = SpringUtil.getBean(BpmProcessInstanceService.class)
.getProcessInstance(execution.getProcessInstanceId());
Assert.notNull(processInstance, "流程实例({}) 不存在", execution.getProcessInstanceId());
removeStartUserIfSkip(userIds, flowElement, Long.valueOf(processInstance.getStartUserId()));
return userIds;
}
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
// 审批类型非人工审核时不进行计算候选人原因是后续会自动通过不通过
FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
Integer approveType = BpmnModelUtils.parseApproveType(flowElement);
if (ObjectUtils.equalsAny(approveType,
BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType(),
BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
return new HashSet<>();
}
Integer strategy = BpmnModelUtils.parseCandidateStrategy(flowElement);
String param = BpmnModelUtils.parseCandidateParam(flowElement);
// 1.1 计算任务的候选人
Set<Long> userIds = getCandidateStrategy(strategy).calculateUsersByActivity(bpmnModel, activityId, param,
startUserId, processDefinitionId, processVariables);
// 1.2 移除被禁用的用户
removeDisableUsers(userIds);
// 2. 候选人为空时根据审批人为空的配置补充
if (CollUtil.isEmpty(userIds)) {
userIds = getCandidateStrategy(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY.getStrategy())
.calculateUsersByActivity(bpmnModel, activityId, param, startUserId, processDefinitionId, processVariables);
// ASSIGN_EMPTY 策略不需要移除被禁用的用户原因是再移除可能会出现更没审批人了
}
// 3. 移除发起人的用户
removeStartUserIfSkip(userIds, flowElement, startUserId);
return userIds;
}
@ -134,25 +170,23 @@ public class BpmTaskCandidateInvoker {
*
* 注意如果只有一个候选人则不处理避免无法审批
*
* @param execution 执行中的任务
* @param assigneeUserIds 当前分配的候选人
* @param flowElement 当前节点
* @param startUserId 发起人
*/
@VisibleForTesting
void removeStartUserIfSkip(DelegateExecution execution, Set<Long> assigneeUserIds) {
void removeStartUserIfSkip(Set<Long> assigneeUserIds, FlowElement flowElement, Long startUserId) {
if (CollUtil.size(assigneeUserIds) <= 1) {
return;
}
Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(execution.getCurrentFlowElement());
Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(flowElement);
if (ObjectUtil.notEqual(assignStartUserHandlerType, BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP.getType())) {
return;
}
ProcessInstance processInstance = SpringUtil.getBean(BpmProcessInstanceService.class)
.getProcessInstance(execution.getProcessInstanceId());
Assert.notNull(processInstance, "流程实例({}) 不存在", execution.getProcessInstanceId());
assigneeUserIds.remove(Long.valueOf(processInstance.getStartUserId()));
assigneeUserIds.remove(startUserId);
}
public BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy);
Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy);
BpmTaskCandidateStrategy strategyObj = strategyMap.get(strategyEnum);

View File

@ -1,10 +1,10 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
@ -42,47 +42,44 @@ public interface BpmTaskCandidateStrategy {
/**
* 基于候选人参数获得任务的候选用户们
*
* 注意实现 calculateUsers 系列方法时有两种选择
* 1. 只重写 calculateUsers 默认方法
* 2. 都重写 calculateUsersByTask calculateUsersByActivity 两个方法
*
* @param param 执行任务
* @return 用户编号集合
*/
default Set<Long> calculateUsers(String param) {
return Collections.emptySet();
throw new UnsupportedOperationException("该分配方法未实现,请检查!");
}
/**
* 基于执行任务获得任务的候选用户们
* 基于执行任务获得任务的候选用户们
*
* @param execution 执行任务
* @return 用户编号集合
*/
default Set<Long> calculateUsers(DelegateExecution execution, String param) {
Set<Long> users = calculateUsers(param);
removeDisableUsers(users);
return users;
default Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
return calculateUsers(param);
}
/**
* 基于流程实例获得任务的候选用户们
* 基于流程活动获得任务的候选用户们
* <p>
* 目的用于获取未执行节点的候选用户们
*
* @param startUserId 流程发起人编号
* @param processInstance 流程实例编号
* @param activityId 活动 Id (对应 Bpmn XML id)
* @param bpmnModel 流程图
* @param activityId 活动 ID (对应 Bpmn XML id)
* @param param 节点的参数
* @param startUserId 流程发起人编号
* @param processDefinitionId 流程定义编号
* @param processVariables 流程变量
* @return 用户编号集合
*/
default Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
Set<Long> users = calculateUsers(param);
removeDisableUsers(users);
return users;
@SuppressWarnings("unused")
default Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
return calculateUsers(param);
}
/**
* 移除被禁用的用户
*
* @param users 用户 Ids
*/
void removeDisableUsers(Set<Long> users);
}

View File

@ -1,37 +0,0 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import java.util.Map;
import java.util.Set;
/**
* {@link BpmTaskCandidateStrategy} 抽象类
*
* @author jason
*/
public abstract class BpmTaskCandidateAbstractStrategy implements BpmTaskCandidateStrategy {
protected AdminUserApi adminUserApi;
public BpmTaskCandidateAbstractStrategy(AdminUserApi adminUserApi) {
this.adminUserApi = adminUserApi;
}
@Override
public void removeDisableUsers(Set<Long> users) {
if (CollUtil.isEmpty(users)) {
return;
}
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(users);
users.removeIf(id -> {
AdminUserRespDTO user = userMap.get(id);
return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
});
}
}

View File

@ -1,92 +0,0 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
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;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Set;
import static cn.hutool.core.collection.ListUtil.toList;
/**
* 发起人连续多级部门的负责人 {@link BpmTaskCandidateStrategy} 实现类
*
* @author jason
*/
@Component
public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
@Resource
@Lazy
private BpmProcessInstanceService processInstanceService;
public BpmTaskCandidateStartUserDeptLeaderMultiStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
super(adminUserApi, deptApi);
}
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER_MULTI;
}
@Override
public void validateParam(String param) {
// 参数是部门的层级
Assert.isTrue(Integer.parseInt(param) > 0, "部门的层级必须大于 0");
}
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
// 获得流程发起人
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
// 获取发起人的 multi 部门负责人
DeptRespDTO dept = getStartUserDept(startUserId);
if (dept == null) {
return new HashSet<>();
}
Set<Long> users = getMultiLevelDeptLeaderIds(toList(dept.getId()), Integer.valueOf(param)); // 参数是部门的层级
// TODO @jason这里 removeDisableUsers 的原因是啥呀
// TODO @芋艿 calculateUsers(execution, param) calculateUsers(startUserId, processInstance, activityId, param) 现在这两个方法, 默认都移除了被禁用的用户
// TODO @芋艿 因为被禁用的用户是不能审批任务 在这里移除是不是好一点 代码可以重用
removeDisableUsers(users);
return users;
}
@Override
public Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
DeptRespDTO dept = getStartUserDept(startUserId);
if (dept == null) {
return new HashSet<>();
}
Set<Long> users = getMultiLevelDeptLeaderIds(toList(dept.getId()), Integer.valueOf(param)); // 参数是部门的层级
removeDisableUsers(users);
return users;
}
/**
* 获取发起人的部门
*
* @param startUserId 发起人 Id
*/
protected DeptRespDTO getStartUserDept(Long startUserId) {
AdminUserRespDTO startUser = adminUserApi.getUser(startUserId);
if (startUser.getDeptId() == null) { // 找不到部门
return null;
}
return deptApi.getDept(startUser.getDeptId());
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCand
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;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import java.util.*;
@ -14,14 +16,12 @@ import java.util.*;
*
* @author jason
*/
public abstract class BpmTaskCandidateAbstractDeptLeaderStrategy extends BpmTaskCandidateAbstractStrategy {
public abstract class AbstractBpmTaskCandidateDeptLeaderStrategy implements BpmTaskCandidateStrategy {
@Resource
protected DeptApi deptApi;
public BpmTaskCandidateAbstractDeptLeaderStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
super(adminUserApi);
this.deptApi = deptApi;
}
@Resource
protected AdminUserApi adminUserApi;
/**
* 获得指定层级的部门负责人只有第 level 的负责人
@ -75,4 +75,17 @@ public abstract class BpmTaskCandidateAbstractDeptLeaderStrategy extends BpmTas
return deptLeaderIds;
}
/**
* 获取发起人的部门
*
* @param startUserId 发起人 Id
*/
protected DeptRespDTO getStartUserDept(Long startUserId) {
AdminUserRespDTO startUser = adminUserApi.getUser(startUserId);
if (startUser.getDeptId() == null) { // 找不到部门
return null;
}
return deptApi.getDept(startUser.getDeptId());
}
}

View File

@ -1,13 +1,12 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Set;
/**
@ -16,11 +15,7 @@ import java.util.Set;
* @author jason
*/
@Component
public class BpmTaskCandidateDeptLeaderMultiStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
public BpmTaskCandidateDeptLeaderMultiStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
super(adminUserApi, deptApi);
}
public class BpmTaskCandidateDeptLeaderMultiStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
@ -32,14 +27,19 @@ public class BpmTaskCandidateDeptLeaderMultiStrategy extends BpmTaskCandidateAbs
// 参数格式: | 分隔1左边为部门多个部门用 , 分隔2右边为部门层级
String[] params = param.split("\\|");
Assert.isTrue(params.length == 2, "参数格式不匹配");
deptApi.validateDeptList(StrUtils.splitToLong(params[0], ","));
Assert.isTrue(Integer.parseInt(params[1]) > 0, "部门层级必须大于 0");
List<Long> deptIds = StrUtils.splitToLong(params[0], ",");
int level = Integer.parseInt(params[1]);
// 校验部门存在
deptApi.validateDeptList(deptIds);
Assert.isTrue(level > 0, "部门层级必须大于 0");
}
@Override
public Set<Long> calculateUsers(String param) {
String[] params = param.split("\\|");
return getMultiLevelDeptLeaderIds(StrUtils.splitToLong(params[0], ","), Integer.valueOf(params[1]));
List<Long> deptIds = StrUtils.splitToLong(params[0], ",");
int level = Integer.parseInt(params[1]);
return super.getMultiLevelDeptLeaderIds(deptIds, level);
}
}

View File

@ -1,11 +1,11 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
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;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.List;
@ -19,14 +19,10 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
* @author kyle
*/
@Component
public class BpmTaskCandidateDeptLeaderStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidateDeptLeaderStrategy implements BpmTaskCandidateStrategy {
private final DeptApi deptApi;
public BpmTaskCandidateDeptLeaderStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
super(adminUserApi);
this.deptApi = deptApi;
}
@Resource
private DeptApi deptApi;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidat
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.List;
@ -19,14 +20,12 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
* @author kyle
*/
@Component
public class BpmTaskCandidateDeptMemberStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidateDeptMemberStrategy implements BpmTaskCandidateStrategy {
private final DeptApi deptApi;
public BpmTaskCandidateDeptMemberStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
super(adminUserApi);
this.deptApi = deptApi;
}
@Resource
private DeptApi deptApi;
@Resource
private AdminUserApi adminUserApi;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {

View File

@ -0,0 +1,70 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import jakarta.annotation.Resource;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static cn.hutool.core.collection.ListUtil.toList;
/**
* 发起人连续多级部门的负责人 {@link BpmTaskCandidateStrategy} 实现类
*
* @author jason
*/
@Component
public class BpmTaskCandidateStartUserDeptLeaderMultiStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
@Resource
@Lazy
private BpmProcessInstanceService processInstanceService;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER_MULTI;
}
@Override
public void validateParam(String param) {
int level = Integer.parseInt(param); // 参数是部门的层级
Assert.isTrue(level > 0, "部门的层级必须大于 0");
}
@Override
public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
int level = Integer.parseInt(param); // 参数是部门的层级
// 获得流程发起人
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
// 获取发起人的 multi 部门负责人
DeptRespDTO dept = super.getStartUserDept(startUserId);
if (dept == null) {
return new HashSet<>();
}
return super.getMultiLevelDeptLeaderIds(toList(dept.getId()), level);
}
@Override
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);
if (dept == null) {
return new HashSet<>();
}
return super.getMultiLevelDeptLeaderIds(toList(dept.getId()), level);
}
}

View File

@ -1,21 +1,20 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
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;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
@ -26,7 +25,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
* @author jason
*/
@Component
public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidateAbstractDeptLeaderStrategy {
public class BpmTaskCandidateStartUserDeptLeaderStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
@Resource
@Lazy // 避免循环依赖
@ -37,10 +36,6 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidat
return BpmTaskCandidateStrategyEnum.START_USER_DEPT_LEADER;
}
public BpmTaskCandidateStartUserDeptLeaderStrategy(AdminUserApi adminUserApi, DeptApi deptApi) {
super(adminUserApi, deptApi);
}
@Override
public void validateParam(String param) {
// 参数是部门的层级
@ -48,44 +43,29 @@ public class BpmTaskCandidateStartUserDeptLeaderStrategy extends BpmTaskCandidat
}
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
// 获得流程发起人
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId());
// 获取发起人的部门负责人
Set<Long> users = getStartUserDeptLeader(startUserId, param);
removeDisableUsers(users);
return users;
return getStartUserDeptLeader(startUserId, param);
}
@Override
public Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
// 获取发起人的部门负责人
Set<Long> users = getStartUserDeptLeader(startUserId, param);
removeDisableUsers(users);
return users;
return getStartUserDeptLeader(startUserId, param);
}
private Set<Long> getStartUserDeptLeader(Long startUserId, String param) {
DeptRespDTO dept = getStartUserDept(startUserId);
int level = Integer.parseInt(param); // 参数是部门的层级
DeptRespDTO dept = super.getStartUserDept(startUserId);
if (dept == null) {
return new HashSet<>();
}
Long deptLeaderId = getAssignLevelDeptLeaderId(dept, Integer.valueOf(param)); // 参数是部门的层级
Long deptLeaderId = super.getAssignLevelDeptLeaderId(dept, level);
return deptLeaderId != null ? asSet(deptLeaderId) : new HashSet<>();
}
/**
* 获取发起人的部门
*
* @param startUserId 发起人 Id
*/
protected DeptRespDTO getStartUserDept(Long startUserId) {
AdminUserRespDTO startUser = adminUserApi.getUser(startUserId);
if (startUser.getDeptId() == null) { // 找不到部门
return null;
}
return deptApi.getDept(startUser.getDeptId());
}
}

View File

@ -1,12 +1,13 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.google.common.collect.Sets;
import jakarta.annotation.Resource;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.UserTask;
@ -23,16 +24,12 @@ import java.util.*;
* @author 芋道源码
*/
@Component
public class BpmTaskCandidateStartUserSelectStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCandidateDeptLeaderStrategy {
@Resource
@Lazy // 延迟加载避免循环依赖
private BpmProcessInstanceService processInstanceService;
public BpmTaskCandidateStartUserSelectStrategy(AdminUserApi adminUserApi) {
super(adminUserApi);
}
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.START_USER_SELECT;
@ -42,7 +39,12 @@ public class BpmTaskCandidateStartUserSelectStrategy extends BpmTaskCandidateAbs
public void validateParam(String param) {}
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
public boolean isParamRequired() {
return false;
}
@Override
public LinkedHashSet<Long> calculateUsersByTask(DelegateExecution execution, String param) {
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Assert.notNull(processInstance, "流程实例({})不能为空", execution.getProcessInstanceId());
Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance);
@ -50,28 +52,22 @@ public class BpmTaskCandidateStartUserSelectStrategy extends BpmTaskCandidateAbs
execution.getProcessInstanceId());
// 获得审批人
List<Long> assignees = startUserSelectAssignees.get(execution.getCurrentActivityId());
Set<Long> users = new LinkedHashSet<>(assignees);
removeDisableUsers(users);
return users;
return new LinkedHashSet<>(assignees);
}
@Override
public Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
if (processInstance == null) {
return Collections.emptySet();
public LinkedHashSet<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
if (processVariables == null) {
return Sets.newLinkedHashSet();
}
Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processVariables);
if (startUserSelectAssignees == null) {
return Sets.newLinkedHashSet();
}
Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance);
Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空", processInstance.getId());
// 获得审批人
List<Long> assignees = startUserSelectAssignees.get(activityId);
Set<Long> users = new LinkedHashSet<>(assignees);
removeDisableUsers(users);
return users;
}
@Override
public boolean isParamRequired() {
return false;
return new LinkedHashSet<>(assignees);
}
/**

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
@ -7,13 +7,15 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCand
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@ -23,16 +25,12 @@ import java.util.Set;
* @author kyle
*/
@Component
public class BpmTaskCandidateAssignEmptyStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidateAssignEmptyStrategy implements BpmTaskCandidateStrategy {
@Resource
@Lazy // 延迟加载避免循环依赖
private BpmProcessDefinitionService processDefinitionService;
public BpmTaskCandidateAssignEmptyStrategy(AdminUserApi adminUserApi) {
super(adminUserApi);
}
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY;
@ -43,19 +41,28 @@ public class BpmTaskCandidateAssignEmptyStrategy extends BpmTaskCandidateAbstrac
}
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
return getCandidateUsers(execution.getProcessDefinitionId(), execution.getCurrentFlowElement());
}
@Override
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
return getCandidateUsers(processDefinitionId, flowElement);
}
private Set<Long> getCandidateUsers(String processDefinitionId, FlowElement flowElement) {
// 情况一指定人员审批
Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(execution.getCurrentFlowElement());
Integer assignEmptyHandlerType = BpmnModelUtils.parseAssignEmptyHandlerType(flowElement);
if (Objects.equals(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_USER.getType())) {
Set<Long> users = new HashSet<>(BpmnModelUtils.parseAssignEmptyHandlerUserIds(execution.getCurrentFlowElement()));
removeDisableUsers(users);
return users;
return new HashSet<>(BpmnModelUtils.parseAssignEmptyHandlerUserIds(flowElement));
}
// 情况二流程管理员
if (Objects.equals(assignEmptyHandlerType, BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_ADMIN.getType())) {
BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(execution.getProcessDefinitionId());
Assert.notNull(processDefinition, "流程定义({})不存在", execution.getProcessDefinitionId());
BpmProcessDefinitionInfoDO processDefinition = processDefinitionService.getProcessDefinitionInfo(processDefinitionId);
Assert.notNull(processDefinition, "流程定义({})不存在", processDefinitionId);
return new HashSet<>(processDefinition.getManagerUserIds());
}

View File

@ -1,13 +1,14 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other;
import cn.hutool.core.convert.Convert;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
/**
@ -16,11 +17,7 @@ import java.util.Set;
* @author 芋道源码
*/
@Component
public class BpmTaskCandidateExpressionStrategy extends BpmTaskCandidateAbstractStrategy {
public BpmTaskCandidateExpressionStrategy(AdminUserApi adminUserApi) {
super(adminUserApi);
}
public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrategy {
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
@ -33,11 +30,16 @@ public class BpmTaskCandidateExpressionStrategy extends BpmTaskCandidateAbstract
}
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
Object result = FlowableUtils.getExpressionValue(execution, param);
Set<Long> users = Convert.toSet(Long.class, result);
removeDisableUsers(users);
return users;
return Convert.toSet(Long.class, result);
}
@Override
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
Object result = FlowableUtils.getExpressionValue(processVariables, param);
return Convert.toSet(Long.class, result);
}
}

View File

@ -1,11 +1,11 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.Collection;
@ -20,14 +20,10 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
* @author kyle
*/
@Component
public class BpmTaskCandidateGroupStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidateGroupStrategy implements BpmTaskCandidateStrategy {
private final BpmUserGroupService userGroupService;
public BpmTaskCandidateGroupStrategy(AdminUserApi adminUserApi, BpmUserGroupService userGroupService) {
super(adminUserApi);
this.userGroupService = userGroupService;
}
@Resource
private BpmUserGroupService userGroupService;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
@ -37,7 +33,7 @@ public class BpmTaskCandidateGroupStrategy extends BpmTaskCandidateAbstractStrat
@Override
public void validateParam(String param) {
Set<Long> groupIds = StrUtils.splitToLongSet(param);
userGroupService.getUserGroupList(groupIds);
userGroupService.validUserGroups(groupIds);
}
@Override

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidat
import cn.iocoder.yudao.module.system.api.dept.PostApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.List;
@ -19,14 +20,12 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
* @author kyle
*/
@Component
public class BpmTaskCandidatePostStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidatePostStrategy implements BpmTaskCandidateStrategy {
private final PostApi postApi;
public BpmTaskCandidatePostStrategy(AdminUserApi adminUserApi, PostApi postApi) {
super(adminUserApi);
this.postApi = postApi;
}
@Resource
private PostApi postApi;
@Resource
private AdminUserApi adminUserApi;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {

View File

@ -1,11 +1,10 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
@ -17,17 +16,13 @@ import java.util.Set;
* @author kyle
*/
@Component
public class BpmTaskCandidateRoleStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidateRoleStrategy implements BpmTaskCandidateStrategy {
@Resource
private RoleApi roleApi;
@Resource
private PermissionApi permissionApi;
public BpmTaskCandidateRoleStrategy(AdminUserApi adminUserApi) {
super(adminUserApi);
}
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.ROLE;

View File

@ -1,15 +1,17 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
/**
@ -20,16 +22,12 @@ import java.util.Set;
* @author jason
*/
@Component
public class BpmTaskCandidateStartUserStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidateStartUserStrategy implements BpmTaskCandidateStrategy {
@Resource
@Lazy // 延迟加载避免循环依赖
private BpmProcessInstanceService processInstanceService;
public BpmTaskCandidateStartUserStrategy(AdminUserApi adminUserApi) {
super(adminUserApi);
}
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
return BpmTaskCandidateStrategyEnum.START_USER;
@ -45,18 +43,15 @@ public class BpmTaskCandidateStartUserStrategy extends BpmTaskCandidateAbstractS
}
@Override
public Set<Long> calculateUsers(DelegateExecution execution, String param) {
public Set<Long> calculateUsersByTask(DelegateExecution execution, String param) {
ProcessInstance processInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId());
Set<Long> users = SetUtils.asSet(Long.valueOf(processInstance.getStartUserId()));
removeDisableUsers(users);
return users;
return SetUtils.asSet(Long.valueOf(processInstance.getStartUserId()));
}
@Override
public Set<Long> calculateUsers(Long startUserId, ProcessInstance processInstance, String activityId, String param) {
Set<Long> users = SetUtils.asSet(startUserId);
removeDisableUsers(users);
return users;
public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId, String param,
Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
return SetUtils.asSet(startUserId);
}
}

View File

@ -1,14 +1,14 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.hutool.core.text.StrPool;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* 用户 {@link BpmTaskCandidateStrategy} 实现类
@ -16,11 +16,10 @@ import java.util.Set;
* @author kyle
*/
@Component
public class BpmTaskCandidateUserStrategy extends BpmTaskCandidateAbstractStrategy {
public class BpmTaskCandidateUserStrategy implements BpmTaskCandidateStrategy {
public BpmTaskCandidateUserStrategy(AdminUserApi adminUserApi) {
super(adminUserApi);
}
@Resource
private AdminUserApi adminUserApi;
@Override
public BpmTaskCandidateStrategyEnum getStrategy() {
@ -33,7 +32,7 @@ public class BpmTaskCandidateUserStrategy extends BpmTaskCandidateAbstractStrate
}
@Override
public Set<Long> calculateUsers(String param) {
public LinkedHashSet<Long> calculateUsers(String param) {
return new LinkedHashSet<>(StrUtils.splitToLong(param, StrPool.COMMA));
}

View File

@ -34,7 +34,7 @@ public class BpmCopyTaskDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
// 1. 获得抄送人
Set<Long> userIds = taskCandidateInvoker.calculateUsers(execution);
Set<Long> userIds = taskCandidateInvoker.calculateUsersByTask(execution);
if (CollUtil.isEmpty(userIds)) {
return;
}

View File

@ -5,7 +5,6 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
@ -23,7 +22,6 @@ import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.impl.util.io.BytesStreamSource;
import org.flowable.engine.ManagementService;
import java.util.*;
@ -773,20 +771,16 @@ public class BpmnModelUtils {
* @return 是否满足条件
*/
public static boolean evalConditionExpress(Map<String, Object> variables, String express) {
ManagementService managementService = SpringUtil.getBean(ManagementService.class);
if (express == null) {
return Boolean.FALSE;
}
// TODO @jason疑问为啥这里要在 managementService 里执行哈
Object result = managementService.executeCommand(context -> {
try {
return FlowableUtils.getExpressionValue(variables, express);
} catch (FlowableException ex) {
log.error("[evalConditionExpress][条件表达式({}) 解析报错", express, ex);
return Boolean.FALSE;
}
});
return Boolean.TRUE.equals(result);
try {
Object result = FlowableUtils.getExpressionValue(variables, express);
return Boolean.TRUE.equals(result);
} catch (FlowableException ex) {
log.error("[evalConditionExpress][条件表达式({}) 变量({}) 解析报错", express, variables, ex);
return Boolean.FALSE;
}
}
@SuppressWarnings("PatternVariableCanBeUsed")

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.util;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants;
@ -9,6 +10,7 @@ import org.flowable.common.engine.api.variable.VariableContainer;
import org.flowable.common.engine.impl.el.ExpressionManager;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.variable.MapDelegateVariableContainer;
import org.flowable.engine.ManagementService;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
@ -146,9 +148,22 @@ public class FlowableUtils {
* @param processInstance 流程实例
* @return 发起用户选择的审批人 Map
*/
@SuppressWarnings("unchecked")
public static Map<String, List<Long>> getStartUserSelectAssignees(ProcessInstance processInstance) {
return (Map<String, List<Long>>) processInstance.getProcessVariables().get(
return processInstance != null ? getStartUserSelectAssignees(processInstance.getProcessVariables()) : null;
}
/**
* 获得流程实例的发起用户选择的审批人 Map
*
* @param processVariables 流程变量
* @return 发起用户选择的审批人 Map
*/
@SuppressWarnings("unchecked")
public static Map<String, List<Long>> getStartUserSelectAssignees(Map<String, Object> processVariables) {
if (processVariables == null) {
return null;
}
return (Map<String, List<Long>>) processVariables.get(
BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES);
}
@ -202,18 +217,29 @@ public class FlowableUtils {
// ========== Expression 相关的工具方法 ==========
public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) {
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
assert processEngineConfiguration != null;
private static Object getExpressionValue(VariableContainer variableContainer, String expressionString,
ProcessEngineConfigurationImpl processEngineConfiguration) {
assert processEngineConfiguration!= null;
ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
assert expressionManager != null;
assert expressionManager!= null;
Expression expression = expressionManager.createExpression(expressionString);
return expression.getValue(variableContainer);
}
public static Object getExpressionValue(VariableContainer variableContainer, String expressionString) {
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration();
if (processEngineConfiguration != null) {
return getExpressionValue(variableContainer, expressionString, processEngineConfiguration);
}
// 如果 ProcessEngineConfigurationImpl 获取不到则需要通过 ManagementService 来获取
ManagementService managementService = SpringUtil.getBean(ManagementService.class);
assert managementService != null;
return managementService.executeCommand(context ->
getExpressionValue(variableContainer, expressionString, CommandContextUtil.getProcessEngineConfiguration()));
}
public static Object getExpressionValue(Map<String, Object> variable, String expressionString) {
VariableContainer variableContainer = new MapDelegateVariableContainer(variable,
VariableContainer.empty());
VariableContainer variableContainer = new MapDelegateVariableContainer(variable, VariableContainer.empty());
return getExpressionValue(variableContainer, expressionString);
}

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateUserStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -47,13 +47,13 @@ public class BpmTaskCandidateInvokerTest extends BaseMockitoUnitTest {
@BeforeEach
public void setUp() {
strategy = new BpmTaskCandidateUserStrategy(adminUserApi); // 创建strategy实例
strategy = new BpmTaskCandidateUserStrategy(); // 创建strategy实例
strategyList = Collections.singletonList(strategy); // 创建strategyList
taskCandidateInvoker = new BpmTaskCandidateInvoker(strategyList, adminUserApi);
}
@Test
public void testCalculateUsers() {
public void testCalculateUsersByTask() {
// 准备参数
String param = "1,2";
DelegateExecution execution = mock(DelegateExecution.class);
@ -74,7 +74,7 @@ public class BpmTaskCandidateInvokerTest extends BaseMockitoUnitTest {
when(adminUserApi.getUserMap(eq(asSet(1L, 2L)))).thenReturn(userMap);
// 调用
Set<Long> results = taskCandidateInvoker.calculateUsers(execution);
Set<Long> results = taskCandidateInvoker.calculateUsersByTask(execution);
// 断言
assertEquals(asSet(1L, 2L), results);
}

View File

@ -0,0 +1,43 @@
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.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import org.assertj.core.util.Sets;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import java.util.Set;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
public class BpmTaskCandidateDeptLeaderMultiStrategyTest extends BaseMockitoUnitTest {
@InjectMocks
private BpmTaskCandidateDeptLeaderMultiStrategy strategy;
@Mock
private DeptApi deptApi;
@Test
public void testCalculateUsers() {
// 准备参数
String param = "10,20|2";
// mock 方法
when(deptApi.getDept(any())).thenAnswer((Answer<DeptRespDTO>) invocationOnMock -> {
Long deptId = invocationOnMock.getArgument(0);
return randomPojo(DeptRespDTO.class, o -> o.setId(deptId).setParentId(deptId * 100).setLeaderUserId(deptId + 1));
});
// 调用
Set<Long> userIds = strategy.calculateUsers(param);
// 断言结果
assertEquals(Sets.newLinkedHashSet(11L, 1001L, 21L, 2001L), userIds);
}
}

View File

@ -1,15 +1,16 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import org.assertj.core.util.Sets;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -27,16 +28,16 @@ public class BpmTaskCandidateDeptLeaderStrategyTest extends BaseMockitoUnitTest
@Test
public void testCalculateUsers() {
// 准备参数
String param = "1,2";
String param = "10,20";
// mock 方法
DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L));
DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L));
when(deptApi.getDeptList(eq(asSet(1L, 2L)))).thenReturn(asList(dept1, dept2));
when(deptApi.getDeptList(eq(SetUtils.asSet(10L, 20L)))).thenReturn(asList(
randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(10L).setLeaderUserId(11L)),
randomPojo(DeptRespDTO.class, o -> o.setId(20L).setParentId(20L).setLeaderUserId(21L))));
// 调用
Set<Long> results = strategy.calculateUsers(null, param);
// 断言
assertEquals(asSet(11L, 22L), results);
Set<Long> userIds = strategy.calculateUsers(param);
// 断言结果
assertEquals(Sets.newLinkedHashSet(11L, 21L), userIds);
}
}

View File

@ -1,17 +1,19 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.assertj.core.util.Sets;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.List;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@ -21,22 +23,24 @@ public class BpmTaskCandidateDeptMemberStrategyTest extends BaseMockitoUnitTest
@InjectMocks
private BpmTaskCandidateDeptMemberStrategy strategy;
@Mock
private DeptApi deptApi;
@Mock
private AdminUserApi adminUserApi;
@Test
public void testCalculateUsers() {
// 准备参数
String param = "11,22";
String param = "10,20";
// mock 方法
List<AdminUserRespDTO> users = convertList(asSet(11L, 22L),
id -> new AdminUserRespDTO().setId(id));
when(adminUserApi.getUserListByDeptIds(eq(asSet(11L, 22L)))).thenReturn(users);
when(adminUserApi.getUserListByDeptIds(eq(SetUtils.asSet(10L, 20L)))).thenReturn(asList(
randomPojo(AdminUserRespDTO.class, o -> o.setId(11L)),
randomPojo(AdminUserRespDTO.class, o -> o.setId(21L))));
// 调用
Set<Long> results = strategy.calculateUsers(null, param);
// 断言
assertEquals(asSet(11L, 22L), results);
Set<Long> userIds = strategy.calculateUsers(param);
// 断言结果
assertEquals(Sets.newLinkedHashSet(11L, 21L), userIds);
}
}

View File

@ -0,0 +1,82 @@
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.service.task.BpmProcessInstanceService;
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;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.assertj.core.util.Sets;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import java.util.Set;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class BpmTaskCandidateStartUserDeptLeaderMultiStrategyTest extends BaseMockitoUnitTest {
@InjectMocks
private BpmTaskCandidateStartUserDeptLeaderMultiStrategy strategy;
@Mock
private BpmProcessInstanceService processInstanceService;
@Mock
private AdminUserApi adminUserApi;
@Mock
private DeptApi deptApi;
@Test
public void testCalculateUsersByTask() {
// 准备参数
String param = "2";
// mock 方法获得流程发起人
Long startUserId = 1L;
ProcessInstance processInstance = mock(ProcessInstance.class);
DelegateExecution execution = mock(DelegateExecution.class);
when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
// mock 方法获取发起人的 multi 部门负责人
mockGetStartUserDept(startUserId);
// 调用
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
// 断言
assertEquals(Sets.newLinkedHashSet(11L, 1001L), userIds);
}
@Test
public void testCalculateUsersByActivity() {
// 准备参数
String param = "2";
// mock 方法
Long startUserId = 1L;
mockGetStartUserDept(startUserId);
// 调用
Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
startUserId, null, null);
// 断言
assertEquals(Sets.newLinkedHashSet(11L, 1001L), userIds);
}
private void mockGetStartUserDept(Long startUserId) {
when(adminUserApi.getUser(eq(startUserId))).thenReturn(
randomPojo(AdminUserRespDTO.class, o -> o.setId(startUserId).setDeptId(10L)));
when(deptApi.getDept(any())).thenAnswer((Answer<DeptRespDTO>) invocationOnMock -> {
Long deptId = invocationOnMock.getArgument(0);
return randomPojo(DeptRespDTO.class, o -> o.setId(deptId).setParentId(deptId * 100).setLeaderUserId(deptId + 1));
});
}
}

View File

@ -0,0 +1,82 @@
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.service.task.BpmProcessInstanceService;
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;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.assertj.core.util.Sets;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import java.util.Set;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class BpmTaskCandidateStartUserDeptLeaderStrategyTest extends BaseMockitoUnitTest {
@InjectMocks
private BpmTaskCandidateStartUserDeptLeaderStrategy strategy;
@Mock
private BpmProcessInstanceService processInstanceService;
@Mock
private AdminUserApi adminUserApi;
@Mock
private DeptApi deptApi;
@Test
public void testCalculateUsersByTask() {
// 准备参数
String param = "2";
// mock 方法获得流程发起人
Long startUserId = 1L;
ProcessInstance processInstance = mock(ProcessInstance.class);
DelegateExecution execution = mock(DelegateExecution.class);
when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
// mock 方法获取发起人的部门负责人
mockGetStartUserDeptLeader(startUserId);
// 调用
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
// 断言
assertEquals(Sets.newLinkedHashSet(1001L), userIds);
}
@Test
public void testGetStartUserDeptLeader() {
// 准备参数
String param = "2";
// mock 方法
Long startUserId = 1L;
mockGetStartUserDeptLeader(startUserId);
// 调用
Set<Long> userIds = strategy.calculateUsersByActivity(null, null, param,
startUserId, null, null);
// 断言
assertEquals(Sets.newLinkedHashSet(1001L), userIds);
}
private void mockGetStartUserDeptLeader(Long startUserId) {
when(adminUserApi.getUser(eq(startUserId))).thenReturn(
randomPojo(AdminUserRespDTO.class, o -> o.setId(startUserId).setDeptId(10L)));
when(deptApi.getDept(any())).thenAnswer((Answer<DeptRespDTO>) invocationOnMock -> {
Long deptId = invocationOnMock.getArgument(0);
return randomPojo(DeptRespDTO.class, o -> o.setId(deptId).setParentId(deptId * 100).setLeaderUserId(deptId + 1));
});
}
}

View File

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.dept;
import cn.hutool.core.map.MapUtil;
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 org.assertj.core.util.Sets;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class BpmTaskCandidateStartUserSelectStrategyTest extends BaseMockitoUnitTest {
@InjectMocks
private BpmTaskCandidateStartUserSelectStrategy strategy;
@Mock
private BpmProcessInstanceService processInstanceService;
@Test
public void testCalculateUsersByTask() {
// 准备参数
String param = "2";
// mock 方法获得流程发起人
ProcessInstance processInstance = mock(ProcessInstance.class);
DelegateExecution execution = mock(DelegateExecution.class);
when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
when(execution.getCurrentActivityId()).thenReturn("activity_001");
// mock 方法FlowableUtils
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES,
MapUtil.of("activity_001", List.of(1L, 2L)));
when(processInstance.getProcessVariables()).thenReturn(processVariables);
// 调用
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
// 断言
assertEquals(Sets.newLinkedHashSet(1L, 2L), userIds);
}
@Test
public void testCalculateUsersByActivity() {
// 准备参数
String activityId = "activity_001";
Map<String, Object> processVariables = new HashMap<>();
processVariables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES,
MapUtil.of("activity_001", List.of(1L, 2L)));
// 调用
Set<Long> userIds = strategy.calculateUsersByActivity(null, activityId, null,
null, null, processVariables);
// 断言
assertEquals(Sets.newLinkedHashSet(1L, 2L), userIds);
}
}

View File

@ -0,0 +1,88 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other;
import cn.hutool.core.collection.ListUtil;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskAssignEmptyHandlerTypeEnum;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.engine.delegate.DelegateExecution;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import java.util.Set;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
public class BpmTaskCandidateAssignEmptyStrategyTest extends BaseMockitoUnitTest {
@InjectMocks
private BpmTaskCandidateAssignEmptyStrategy strategy;
@Mock
private BpmProcessDefinitionService processDefinitionService;
@Test
public void testCalculateUsersByTask() {
try (MockedStatic<FlowableUtils> flowableUtilMockedStatic = mockStatic(FlowableUtils.class);
MockedStatic<BpmnModelUtils> bpmnModelUtilsMockedStatic = mockStatic(BpmnModelUtils.class)) {
// 准备参数
DelegateExecution execution = mock(DelegateExecution.class);
String param = randomString();
// mock 方法execution
String processDefinitionId = randomString();
when(execution.getProcessDefinitionId()).thenReturn(processDefinitionId);
FlowElement flowElement = mock(FlowElement.class);
when(execution.getCurrentFlowElement()).thenReturn(flowElement);
// mock 方法parseAssignEmptyHandlerType
bpmnModelUtilsMockedStatic.when(() -> BpmnModelUtils.parseAssignEmptyHandlerType(same(flowElement)))
.thenReturn(BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_USER.getType());
bpmnModelUtilsMockedStatic.when(() -> BpmnModelUtils.parseAssignEmptyHandlerUserIds(same(flowElement)))
.thenReturn(ListUtil.of(1L, 2L));
// 调用
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
// 断言
assertEquals(SetUtils.asSet(1L, 2L), userIds);
}
}
@Test
public void testCalculateUsersByActivity() {
try (MockedStatic<BpmnModelUtils> bpmnModelUtilsMockedStatic = mockStatic(BpmnModelUtils.class)) {
// 准备参数
String processDefinitionId = randomString();
String activityId = randomString();
String param = randomString();
// mock 方法getFlowElementById
FlowElement flowElement = mock(FlowElement.class);
BpmnModel bpmnModel = mock(BpmnModel.class);
bpmnModelUtilsMockedStatic.when(() -> BpmnModelUtils.getFlowElementById(same(bpmnModel), eq(activityId)))
.thenReturn(flowElement);
// mock 方法parseAssignEmptyHandlerType
bpmnModelUtilsMockedStatic.when(() -> BpmnModelUtils.parseAssignEmptyHandlerType(same(flowElement)))
.thenReturn(BpmUserTaskAssignEmptyHandlerTypeEnum.ASSIGN_ADMIN.getType());
// mock 方法getProcessDefinitionInfo
BpmProcessDefinitionInfoDO processDefinition = randomPojo(BpmProcessDefinitionInfoDO.class,
o -> o.setManagerUserIds(ListUtil.of(1L, 2L)));
when(processDefinitionService.getProcessDefinitionInfo(eq(processDefinitionId))).thenReturn(processDefinition);
// 调用
Set<Long> userIds = strategy.calculateUsersByActivity(bpmnModel, activityId, param,
null, processDefinitionId, null);
// 断言
assertEquals(SetUtils.asSet(1L, 2L), userIds);
}
}
}

View File

@ -1,12 +1,14 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.other;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
import org.flowable.engine.delegate.DelegateExecution;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.MockedStatic;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
@ -20,7 +22,7 @@ public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest
private BpmTaskCandidateExpressionStrategy strategy;
@Test
public void testCalculateUsers() {
public void testCalculateUsersByTask() {
try (MockedStatic<FlowableUtils> flowableUtilMockedStatic = mockStatic(FlowableUtils.class)) {
// 准备参数
String param = "1,2";
@ -30,7 +32,25 @@ public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest
.thenReturn(asSet(1L, 2L));
// 调用
Set<Long> results = strategy.calculateUsers(execution, param);
Set<Long> results = strategy.calculateUsersByTask(execution, param);
// 断言
assertEquals(asSet(1L, 2L), results);
}
}
@Test
public void testCalculateUsersByActivity() {
try (MockedStatic<FlowableUtils> flowableUtilMockedStatic = mockStatic(FlowableUtils.class)) {
// 准备参数
String param = "1,2";
Map<String, Object> processVariables = new HashMap<>();
// mock 方法
flowableUtilMockedStatic.when(() -> FlowableUtils.getExpressionValue(same(processVariables), eq(param)))
.thenReturn(asSet(1L, 2L));
// 调用
Set<Long> results = strategy.calculateUsersByActivity(null, null, param,
null, null, processVariables);
// 断言
assertEquals(asSet(1L, 2L), results);
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO;
@ -34,9 +34,9 @@ public class BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest {
when(userGroupService.getUserGroupList(eq(asSet(1L, 2L)))).thenReturn(Arrays.asList(userGroup1, userGroup2));
// 调用
Set<Long> results = strategy.calculateUsers(null, param);
Set<Long> userIds = strategy.calculateUsersByTask(null, param);
// 断言
assertEquals(asSet(11L, 12L, 21L, 22L), results);
assertEquals(asSet(11L, 12L, 21L, 22L), userIds);
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.api.dept.PostApi;
@ -37,9 +37,9 @@ public class BpmTaskCandidatePostStrategyTest extends BaseMockitoUnitTest {
when(adminUserApi.getUserListByPostIds(eq(asSet(1L, 2L)))).thenReturn(users);
// 调用
Set<Long> results = strategy.calculateUsers(null, param);
Set<Long> userIds = strategy.calculateUsersByTask(null, param);
// 断言
assertEquals(asSet(11L, 22L), results);
assertEquals(asSet(11L, 22L), userIds);
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
@ -33,9 +33,9 @@ public class BpmTaskCandidateRoleStrategyTest extends BaseMockitoUnitTest {
.thenReturn(asSet(11L, 22L));
// 调用
Set<Long> results = strategy.calculateUsers(null, param);
Set<Long> userIds = strategy.calculateUsersByTask(null, param);
// 断言
assertEquals(asSet(11L, 22L), results);
assertEquals(asSet(11L, 22L), userIds);
}
}

View File

@ -0,0 +1,56 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import org.assertj.core.util.Sets;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.runtime.ProcessInstance;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class BpmTaskCandidateStartUserStrategyTest extends BaseMockitoUnitTest {
@InjectMocks
private BpmTaskCandidateStartUserStrategy strategy;
@Mock
private BpmProcessInstanceService processInstanceService;
@Test
public void testCalculateUsersByTask() {
// 准备参数
String param = "2";
// mock 方法获得流程发起人
Long startUserId = 1L;
ProcessInstance processInstance = mock(ProcessInstance.class);
DelegateExecution execution = mock(DelegateExecution.class);
when(processInstanceService.getProcessInstance(eq(execution.getProcessInstanceId()))).thenReturn(processInstance);
when(processInstance.getStartUserId()).thenReturn(startUserId.toString());
// 调用
Set<Long> userIds = strategy.calculateUsersByTask(execution, param);
// 断言
assertEquals(Sets.newLinkedHashSet(startUserId), userIds);
}
@Test
public void testCalculateUsersByActivity() {
// 准备参数
Long startUserId = 1L;
// 调用
Set<Long> userIds = strategy.calculateUsersByActivity(null, null, null,
startUserId, null, null);
// 断言
assertEquals(Sets.newLinkedHashSet(startUserId), userIds);
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy;
package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import org.junit.jupiter.api.Test;
@ -15,14 +15,15 @@ public class BpmTaskCandidateUserStrategyTest extends BaseMockitoUnitTest {
private BpmTaskCandidateUserStrategy strategy;
@Test
public void testCalculateUsers() {
public void test() {
// 准备参数
String param = "1,2";
// 调用
Set<Long> results = strategy.calculateUsers(null, param);
Set<Long> userIds = strategy.calculateUsersByTask(null, param);
// 断言
assertEquals(asSet(1L, 2L), results);
assertEquals(asSet(1L, 2L), userIds);
}
}