mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-10-31 18:28:43 +08:00 
			
		
		
		
	重构 bpmn 任务的处理人的逻辑,收拢到 BpmTaskAssignRuleService
This commit is contained in:
		| @@ -29,7 +29,7 @@ public class BpmTaskExtDO extends BaseDO { | |||||||
|     private Long id; |     private Long id; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 流程任务key |      * 流程任务key TODO 芋艿,看看这个字段的作用 | ||||||
|      */ |      */ | ||||||
|     private String taskDefKey; |     private String taskDefKey; | ||||||
|     /** |     /** | ||||||
|   | |||||||
| @@ -17,8 +17,6 @@ public enum BpmTaskAssignRuleTypeEnum { | |||||||
|     DEPT_LEADER(21, "部门的负责人"), |     DEPT_LEADER(21, "部门的负责人"), | ||||||
|     POST(22, "岗位"), |     POST(22, "岗位"), | ||||||
|     USER(30, "用户"), |     USER(30, "用户"), | ||||||
|     USER_SIGN(31, "用户---会签"), |  | ||||||
|     USER_OR_SIGN(32, "用户---或签"), |  | ||||||
|     USER_GROUP(40, "用户组"), |     USER_GROUP(40, "用户组"), | ||||||
|     SCRIPT(50, "自定义脚本"), // 例如说,发起人所在部门的领导、发起人所在部门的领导的领导 |     SCRIPT(50, "自定义脚本"), // 例如说,发起人所在部门的领导、发起人所在部门的领导的领导 | ||||||
|     ; |     ; | ||||||
|   | |||||||
| @@ -2,12 +2,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.config; | |||||||
|  |  | ||||||
| import cn.hutool.core.collection.ListUtil; | import cn.hutool.core.collection.ListUtil; | ||||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; | import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; | ||||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; |  | ||||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | ||||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; |  | ||||||
| import cn.iocoder.yudao.module.system.api.dept.DeptApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.permission.PermissionApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |  | ||||||
| import org.flowable.common.engine.api.delegate.event.FlowableEventListener; | import org.flowable.common.engine.api.delegate.event.FlowableEventListener; | ||||||
| import org.flowable.spring.SpringProcessEngineConfiguration; | import org.flowable.spring.SpringProcessEngineConfiguration; | ||||||
| import org.flowable.spring.boot.EngineConfigurationConfigurer; | import org.flowable.spring.boot.EngineConfigurationConfigurer; | ||||||
| @@ -15,8 +10,6 @@ import org.springframework.beans.factory.ObjectProvider; | |||||||
| import org.springframework.context.annotation.Bean; | import org.springframework.context.annotation.Bean; | ||||||
| import org.springframework.context.annotation.Configuration; | import org.springframework.context.annotation.Configuration; | ||||||
|  |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * BPM 模块的 Flowable 配置类 |  * BPM 模块的 Flowable 配置类 | ||||||
|  * |  * | ||||||
| @@ -44,19 +37,10 @@ public class BpmFlowableConfiguration { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Bean |     @Bean | ||||||
|     public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService, |     public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService) { | ||||||
|                                                                  BpmUserGroupService userGroupService, |  | ||||||
|                                                                  PermissionApi permissionApi, |  | ||||||
|                                                                  DeptApi deptApi, |  | ||||||
|                                                                  AdminUserApi adminUserApi, |  | ||||||
|                                                                  List<BpmTaskAssignScript> scripts) { |  | ||||||
|         BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); |         BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); | ||||||
|         bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService); |         bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService); | ||||||
|         bpmActivityBehaviorFactory.setUserGroupService(userGroupService); |  | ||||||
|         bpmActivityBehaviorFactory.setAdminUserApi(adminUserApi); |  | ||||||
|         bpmActivityBehaviorFactory.setPermissionApi(permissionApi); |  | ||||||
|         bpmActivityBehaviorFactory.setDeptApi(deptApi); |  | ||||||
|         bpmActivityBehaviorFactory.setScripts(scripts); |  | ||||||
|         return bpmActivityBehaviorFactory; |         return bpmActivityBehaviorFactory; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,11 +1,6 @@ | |||||||
| package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; | package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; |  | ||||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | ||||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; |  | ||||||
| import cn.iocoder.yudao.module.system.api.dept.DeptApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.permission.PermissionApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |  | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import lombok.EqualsAndHashCode; | import lombok.EqualsAndHashCode; | ||||||
| import lombok.Setter; | import lombok.Setter; | ||||||
| @@ -17,8 +12,6 @@ import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; | |||||||
| import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; | import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; | ||||||
| import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; | import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; | ||||||
|  |  | ||||||
| import java.util.List; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 自定义的 ActivityBehaviorFactory 实现类,目的如下: |  * 自定义的 ActivityBehaviorFactory 实现类,目的如下: | ||||||
|  * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配 |  * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配 | ||||||
| @@ -32,41 +25,18 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { | |||||||
|  |  | ||||||
|     @Setter |     @Setter | ||||||
|     private BpmTaskAssignRuleService bpmTaskRuleService; |     private BpmTaskAssignRuleService bpmTaskRuleService; | ||||||
|     @Setter |  | ||||||
|     private BpmUserGroupService userGroupService; |  | ||||||
|  |  | ||||||
|     @Setter |  | ||||||
|     private PermissionApi permissionApi; |  | ||||||
|     @Setter |  | ||||||
|     private DeptApi deptApi; |  | ||||||
|     @Setter |  | ||||||
|     private AdminUserApi adminUserApi; |  | ||||||
|     @Setter |  | ||||||
|     private List<BpmTaskAssignScript> scripts; |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { |     public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { | ||||||
|         BpmUserTaskActivityBehavior userTaskActivityBehavior = new BpmUserTaskActivityBehavior(userTask); |         return new BpmUserTaskActivityBehavior(userTask) | ||||||
|         userTaskActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService); |                 .setBpmTaskRuleService(bpmTaskRuleService); | ||||||
|         userTaskActivityBehavior.setPermissionApi(permissionApi); |  | ||||||
|         userTaskActivityBehavior.setDeptApi(deptApi); |  | ||||||
|         userTaskActivityBehavior.setUserGroupService(userGroupService); |  | ||||||
|         userTaskActivityBehavior.setAdminUserApi(adminUserApi); |  | ||||||
|         userTaskActivityBehavior.setScripts(scripts); |  | ||||||
|         return userTaskActivityBehavior; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, |     public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, | ||||||
|                                                                              AbstractBpmnActivityBehavior innerActivityBehavior) { |                                                                              AbstractBpmnActivityBehavior innerActivityBehavior) { | ||||||
|         BpmParallelMultiInstanceActivityBehavior bpmParallelMultiInstanceActivityBehavior = |         return new BpmParallelMultiInstanceBehavior(activity, innerActivityBehavior) | ||||||
|             new BpmParallelMultiInstanceActivityBehavior(activity, innerActivityBehavior); |                 .setBpmTaskRuleService(bpmTaskRuleService); | ||||||
|         bpmParallelMultiInstanceActivityBehavior.setBpmTaskRuleService(bpmTaskRuleService); |  | ||||||
|         bpmParallelMultiInstanceActivityBehavior.setPermissionApi(permissionApi); |  | ||||||
|         bpmParallelMultiInstanceActivityBehavior.setDeptApi(deptApi); |  | ||||||
|         bpmParallelMultiInstanceActivityBehavior.setUserGroupService(userGroupService); |  | ||||||
|         bpmParallelMultiInstanceActivityBehavior.setAdminUserApi(adminUserApi); |  | ||||||
|         bpmParallelMultiInstanceActivityBehavior.setScripts(scripts); |  | ||||||
|         return bpmParallelMultiInstanceActivityBehavior; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,194 +0,0 @@ | |||||||
| package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; |  | ||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; |  | ||||||
| import cn.hutool.core.util.StrUtil; |  | ||||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |  | ||||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; |  | ||||||
| import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum; |  | ||||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; |  | ||||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; |  | ||||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; |  | ||||||
| import cn.iocoder.yudao.module.system.api.dept.DeptApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.permission.PermissionApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |  | ||||||
| import com.google.common.annotations.VisibleForTesting; |  | ||||||
| import lombok.Setter; |  | ||||||
| import lombok.extern.slf4j.Slf4j; |  | ||||||
| import org.flowable.bpmn.model.Activity; |  | ||||||
| import org.flowable.common.engine.api.FlowableException; |  | ||||||
| import org.flowable.engine.delegate.DelegateExecution; |  | ||||||
| import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; |  | ||||||
| import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; |  | ||||||
| import org.flowable.engine.impl.util.CommandContextUtil; |  | ||||||
|  |  | ||||||
| import java.util.*; |  | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |  | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; |  | ||||||
| import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |  | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @author kemengkai |  | ||||||
|  * @create 2022-04-21 16:57 |  | ||||||
|  */ |  | ||||||
| @Slf4j |  | ||||||
| public class BpmParallelMultiInstanceActivityBehavior extends ParallelMultiInstanceBehavior { |  | ||||||
|  |  | ||||||
|     @Setter |  | ||||||
|     private BpmTaskAssignRuleService bpmTaskRuleService; |  | ||||||
|     @Setter |  | ||||||
|     private BpmUserGroupService userGroupService; |  | ||||||
|     @Setter |  | ||||||
|     private DeptApi deptApi; |  | ||||||
|     @Setter |  | ||||||
|     private AdminUserApi adminUserApi; |  | ||||||
|     @Setter |  | ||||||
|     private PermissionApi permissionApi; |  | ||||||
|     /** |  | ||||||
|      * EL表达式集合模板 |  | ||||||
|      */ |  | ||||||
|     private final static String EXPRESSION_TEXT_TEMPLATE = "${coll_userList}"; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 任务分配脚本 |  | ||||||
|      */ |  | ||||||
|     private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap(); |  | ||||||
|  |  | ||||||
|     public BpmParallelMultiInstanceActivityBehavior(Activity activity, |  | ||||||
|         AbstractBpmnActivityBehavior innerActivityBehavior) { |  | ||||||
|         super(activity, innerActivityBehavior); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public void setScripts(List<BpmTaskAssignScript> scripts) { |  | ||||||
|         this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 创建并行任务 |  | ||||||
|      * |  | ||||||
|      * @param multiInstanceRootExecution 并行任务入参 |  | ||||||
|      * |  | ||||||
|      * @return 返回结果 |  | ||||||
|      */ |  | ||||||
|     @Override |  | ||||||
|     protected int createInstances(DelegateExecution multiInstanceRootExecution) { |  | ||||||
|         // 查找任务信息 |  | ||||||
|         BpmTaskAssignRuleDO taskRule = getTaskRule(multiInstanceRootExecution); |  | ||||||
|         // 获取任务用户 |  | ||||||
|         Set<Long> assigneeUserIds = calculateTaskCandidateUsers(multiInstanceRootExecution, taskRule); |  | ||||||
|         // 设置任务集合变量 |  | ||||||
|         String expressionText = String.format("%s_userList", taskRule.getTaskDefinitionKey()); |  | ||||||
|         // 设置任务集合变量与任务关系 |  | ||||||
|         multiInstanceRootExecution.setVariable(expressionText, assigneeUserIds); |  | ||||||
|         // 设置任务集合EL表达式 |  | ||||||
|         this.collectionExpression = CommandContextUtil.getProcessEngineConfiguration().getExpressionManager() |  | ||||||
|             .createExpression(String.format("${%s}", expressionText)); |  | ||||||
|         // 根据会签,或签类型,设置会签,或签条件 |  | ||||||
|         if (BpmTaskAssignRuleTypeEnum.USER_SIGN.getType().equals(taskRule.getType())) { |  | ||||||
|             // 会签 |  | ||||||
|             this.completionCondition = "${ nrOfInstances == nrOfCompletedInstances }"; |  | ||||||
|         } else { |  | ||||||
|             // 或签 |  | ||||||
|             this.completionCondition = "${ nrOfCompletedInstances == 1 }"; |  | ||||||
|         } |  | ||||||
|         // 设置取出集合变量 |  | ||||||
|         this.collectionElementVariable = "user"; |  | ||||||
|         return super.createInstances(multiInstanceRootExecution); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     protected Object resolveCollection(DelegateExecution execution) { |  | ||||||
|         Object collection = null; |  | ||||||
|         if (EXPRESSION_TEXT_TEMPLATE.equals(this.collectionExpression.getExpressionText())) { |  | ||||||
|             // 查找任务信息 |  | ||||||
|             BpmTaskAssignRuleDO taskRule = getTaskRule(execution); |  | ||||||
|             // 设置任务集合变量 |  | ||||||
|             String expressionText = String.format("%s_userList", execution.getCurrentActivityId()); |  | ||||||
|             // 获取任务用户 |  | ||||||
|             Set<Long> assigneeUserIds = calculateTaskCandidateUsers(execution, taskRule); |  | ||||||
|             // 设置任务集合变量与任务关系 |  | ||||||
|             execution.setVariable(expressionText, assigneeUserIds); |  | ||||||
|             // 设置任务集合EL表达式 |  | ||||||
|             this.collectionExpression = CommandContextUtil.getProcessEngineConfiguration().getExpressionManager() |  | ||||||
|                 .createExpression(String.format("${%s}", expressionText)); |  | ||||||
|         } |  | ||||||
|         if (this.collectionExpression != null) { |  | ||||||
|             collection = this.collectionExpression.getValue(execution); |  | ||||||
|         } else if (this.collectionVariable != null) { |  | ||||||
|             collection = execution.getVariable(this.collectionVariable); |  | ||||||
|         } else if (this.collectionString != null) { |  | ||||||
|             collection = this.collectionString; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return collection; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private BpmTaskAssignRuleDO getTaskRule(DelegateExecution task) { |  | ||||||
|         List<BpmTaskAssignRuleDO> taskRules = |  | ||||||
|             bpmTaskRuleService.getTaskAssignRuleListByProcessDefinitionId(task.getProcessDefinitionId(), |  | ||||||
|                 task.getCurrentActivityId()); |  | ||||||
|         if (CollUtil.isEmpty(taskRules)) { |  | ||||||
|             throw new FlowableException( |  | ||||||
|                 StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则", task.getId(), task.getProcessDefinitionId(), |  | ||||||
|                     task.getCurrentActivityId())); |  | ||||||
|         } |  | ||||||
|         if (taskRules.size() > 1) { |  | ||||||
|             throw new FlowableException( |  | ||||||
|                 StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})", task.getId(), task.getProcessDefinitionId(), |  | ||||||
|                     task.getCurrentActivityId(), taskRules.size())); |  | ||||||
|         } |  | ||||||
|         return taskRules.get(0); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     Set<Long> calculateTaskCandidateUsers(DelegateExecution task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         Set<Long> assigneeUserIds = null; |  | ||||||
|         //        if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) { |  | ||||||
|         //            assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule); |  | ||||||
|         //        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) { |  | ||||||
|         //            assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule); |  | ||||||
|         //        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { |  | ||||||
|         //            assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule); |  | ||||||
|         //        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) { |  | ||||||
|         //            assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule); |  | ||||||
|         //        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) { |  | ||||||
|         //            assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); |  | ||||||
|         //        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) { |  | ||||||
|         //            assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule); |  | ||||||
|         //        } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) { |  | ||||||
|         //            assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule); |  | ||||||
|         if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersSignByUser(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersSignByUser(task, rule); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 移除被禁用的用户 |  | ||||||
|         removeDisableUsers(assigneeUserIds); |  | ||||||
|         // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人 |  | ||||||
|         if (CollUtil.isEmpty(assigneeUserIds)) { |  | ||||||
|             log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", task.getId(), |  | ||||||
|                 task.getProcessDefinitionId(), task.getCurrentActivityId(), toJsonString(rule)); |  | ||||||
|             throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); |  | ||||||
|         } |  | ||||||
|         return assigneeUserIds; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Set<Long> calculateTaskCandidateUsersSignByUser(DelegateExecution task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         return rule.getOptions(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @VisibleForTesting |  | ||||||
|     void removeDisableUsers(Set<Long> assigneeUserIds) { |  | ||||||
|         if (CollUtil.isEmpty(assigneeUserIds)) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         //TODO 芋艿 这里有数据权限的问题。默认会加上数据权限 dept_id IN (deptId). 导致查询不到数据 |  | ||||||
|         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds); |  | ||||||
|         assigneeUserIds.removeIf(id -> { |  | ||||||
|             AdminUserRespDTO user = userMap.get(id); |  | ||||||
|             return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -0,0 +1,116 @@ | |||||||
|  | package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.collection.CollUtil; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | ||||||
|  | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | ||||||
|  | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | ||||||
|  | import lombok.Setter; | ||||||
|  | import lombok.extern.slf4j.Slf4j; | ||||||
|  | import org.flowable.bpmn.model.Activity; | ||||||
|  | import org.flowable.engine.delegate.DelegateExecution; | ||||||
|  | import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; | ||||||
|  | import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; | ||||||
|  | import org.flowable.engine.impl.util.CommandContextUtil; | ||||||
|  |  | ||||||
|  | import java.util.Set; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | ||||||
|  | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @author kemengkai | ||||||
|  |  * @create 2022-04-21 16:57 | ||||||
|  |  */ | ||||||
|  | @Slf4j | ||||||
|  | public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * EL表达式集合模板 | ||||||
|  |      */ | ||||||
|  |     private final static String EXPRESSION_TEXT_TEMPLATE = "${coll_userList}"; | ||||||
|  |  | ||||||
|  |     @Setter | ||||||
|  |     private BpmTaskAssignRuleService bpmTaskRuleService; | ||||||
|  |  | ||||||
|  |     public BpmParallelMultiInstanceBehavior(Activity activity, | ||||||
|  |                                             AbstractBpmnActivityBehavior innerActivityBehavior) { | ||||||
|  |         super(activity, innerActivityBehavior); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 创建并行任务 | ||||||
|  |      * | ||||||
|  |      * @param multiInstanceRootExecution 并行任务入参 | ||||||
|  |      * | ||||||
|  |      * @return 返回结果 | ||||||
|  |      */ | ||||||
|  |     @Override | ||||||
|  |     protected int createInstances(DelegateExecution multiInstanceRootExecution) { | ||||||
|  |         // 查找任务信息 | ||||||
|  | //        BpmTaskAssignRuleDO taskRule = getTaskRule(multiInstanceRootExecution); | ||||||
|  |         BpmTaskAssignRuleDO taskRule = null; | ||||||
|  |         // 获取任务用户 | ||||||
|  |         Set<Long> assigneeUserIds = calculateTaskCandidateUsers(multiInstanceRootExecution, taskRule); | ||||||
|  |         // 设置任务集合变量 | ||||||
|  |         String expressionText = String.format("%s_userList", taskRule.getTaskDefinitionKey()); | ||||||
|  |         // 设置任务集合变量与任务关系 | ||||||
|  |         multiInstanceRootExecution.setVariable(expressionText, assigneeUserIds); | ||||||
|  |         // 设置任务集合EL表达式 | ||||||
|  |         this.collectionExpression = CommandContextUtil.getProcessEngineConfiguration().getExpressionManager() | ||||||
|  |             .createExpression(String.format("${%s}", expressionText)); | ||||||
|  |         // 根据会签,或签类型,设置会签,或签条件 | ||||||
|  | //        if (BpmTaskAssignRuleTypeEnum.USER_SIGN.getType().equals(taskRule.getType())) { | ||||||
|  | //            // 会签 | ||||||
|  | //            this.completionCondition = "${ nrOfInstances == nrOfCompletedInstances }"; | ||||||
|  | //        } else { | ||||||
|  | //            // 或签 | ||||||
|  | //            this.completionCondition = "${ nrOfCompletedInstances == 1 }"; | ||||||
|  | //        } | ||||||
|  |         // 设置取出集合变量 | ||||||
|  |         this.collectionElementVariable = "user"; | ||||||
|  |         return super.createInstances(multiInstanceRootExecution); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected Object resolveCollection(DelegateExecution execution) { | ||||||
|  |         Object collection = null; | ||||||
|  |         if (EXPRESSION_TEXT_TEMPLATE.equals(this.collectionExpression.getExpressionText())) { | ||||||
|  |             // 查找任务信息 | ||||||
|  | //            BpmTaskAssignRuleDO taskRule = getTaskRule(execution); | ||||||
|  |             BpmTaskAssignRuleDO taskRule = null; | ||||||
|  |             // 设置任务集合变量 | ||||||
|  |             String expressionText = String.format("%s_userList", execution.getCurrentActivityId()); | ||||||
|  |             // 获取任务用户 | ||||||
|  |             Set<Long> assigneeUserIds = calculateTaskCandidateUsers(execution, taskRule); | ||||||
|  |             // 设置任务集合变量与任务关系 | ||||||
|  |             execution.setVariable(expressionText, assigneeUserIds); | ||||||
|  |             // 设置任务集合EL表达式 | ||||||
|  |             this.collectionExpression = CommandContextUtil.getProcessEngineConfiguration().getExpressionManager() | ||||||
|  |                 .createExpression(String.format("${%s}", expressionText)); | ||||||
|  |         } | ||||||
|  |         if (this.collectionExpression != null) { | ||||||
|  |             collection = this.collectionExpression.getValue(execution); | ||||||
|  |         } else if (this.collectionVariable != null) { | ||||||
|  |             collection = execution.getVariable(this.collectionVariable); | ||||||
|  |         } else if (this.collectionString != null) { | ||||||
|  |             collection = this.collectionString; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return collection; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Set<Long> calculateTaskCandidateUsers(DelegateExecution task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         Set<Long> assigneeUserIds = SetUtils.asSet(1L, 104L); | ||||||
|  |  | ||||||
|  |         // 移除被禁用的用户 | ||||||
|  |         // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人 | ||||||
|  |         if (CollUtil.isEmpty(assigneeUserIds)) { | ||||||
|  |             log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", task.getId(), | ||||||
|  |                 task.getProcessDefinitionId(), task.getCurrentActivityId(), toJsonString(rule)); | ||||||
|  |             throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); | ||||||
|  |         } | ||||||
|  |         return assigneeUserIds; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -2,25 +2,11 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; | |||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.hutool.core.util.RandomUtil; | import cn.hutool.core.util.RandomUtil; | ||||||
| import cn.hutool.core.util.StrUtil; |  | ||||||
| import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |  | ||||||
| import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | ||||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; |  | ||||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; |  | ||||||
| import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum; |  | ||||||
| import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; |  | ||||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | ||||||
| import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; |  | ||||||
| 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.permission.PermissionApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |  | ||||||
| import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |  | ||||||
| import com.google.common.annotations.VisibleForTesting; |  | ||||||
| import lombok.Setter; | import lombok.Setter; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.flowable.bpmn.model.UserTask; | import org.flowable.bpmn.model.UserTask; | ||||||
| import org.flowable.common.engine.api.FlowableException; |  | ||||||
| import org.flowable.common.engine.impl.el.ExpressionManager; | import org.flowable.common.engine.impl.el.ExpressionManager; | ||||||
| import org.flowable.engine.delegate.DelegateExecution; | import org.flowable.engine.delegate.DelegateExecution; | ||||||
| import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; | import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; | ||||||
| @@ -29,14 +15,9 @@ import org.flowable.engine.impl.util.TaskHelper; | |||||||
| import org.flowable.task.service.TaskService; | import org.flowable.task.service.TaskService; | ||||||
| import org.flowable.task.service.impl.persistence.entity.TaskEntity; | import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||||||
|  |  | ||||||
| import java.util.*; | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import java.util.Set; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; |  | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |  | ||||||
| import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |  | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_ASSIGN_SCRIPT_NOT_EXISTS; |  | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER; |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * 自定义的流程任务的 assignee 负责人的分配 |  * 自定义的流程任务的 assignee 负责人的分配 | ||||||
| @@ -51,152 +32,23 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { | |||||||
|  |  | ||||||
|     @Setter |     @Setter | ||||||
|     private BpmTaskAssignRuleService bpmTaskRuleService; |     private BpmTaskAssignRuleService bpmTaskRuleService; | ||||||
|     @Setter |  | ||||||
|     private BpmUserGroupService userGroupService; |  | ||||||
|     @Setter |  | ||||||
|     private DeptApi deptApi; |  | ||||||
|     @Setter |  | ||||||
|     private AdminUserApi adminUserApi; |  | ||||||
|     @Setter |  | ||||||
|     private PermissionApi permissionApi; |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 任务分配脚本 |  | ||||||
|      */ |  | ||||||
|     private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap(); |  | ||||||
|  |  | ||||||
|     public BpmUserTaskActivityBehavior(UserTask userTask) { |     public BpmUserTaskActivityBehavior(UserTask userTask) { | ||||||
|         super(userTask); |         super(userTask); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public void setScripts(List<BpmTaskAssignScript> scripts) { |  | ||||||
|         this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     @DataPermission(enable = false) // 不需要处理数据权限, 不然会有问题,查询不到数据 |     @DataPermission(enable = false) // 不需要处理数据权限, 不然会有问题,查询不到数据 | ||||||
|     protected void handleAssignments(TaskService taskService, String assignee, String owner, |     protected void handleAssignments(TaskService taskService, String assignee, String owner, | ||||||
|         List<String> candidateUsers, List<String> candidateGroups, TaskEntity task, ExpressionManager expressionManager, |         List<String> candidateUsers, List<String> candidateGroups, TaskEntity task, ExpressionManager expressionManager, | ||||||
|         DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) { |         DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) { | ||||||
|         /*boolean isMultiInstance = hasMultiInstanceCharacteristics(); |         // 第一步,获得任务的候选用户们 | ||||||
|         if (isMultiInstance) { |         Set<Long> candidateUserIds = bpmTaskRuleService.calculateTaskCandidateUsers(task); | ||||||
|             //多实例 会签/或签,执行多次每个人 待办人都在execution里面获取 |         // 第二步,选择一个作为候选人 | ||||||
|             Integer assigneeUserId = execution.getVariableLocal("user", Integer.class); |  | ||||||
|             TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId)); |  | ||||||
|         } else { |  | ||||||
|             // 第一步,获得任务的规则 |  | ||||||
|             BpmTaskAssignRuleDO rule = getTaskRule(task); |  | ||||||
|             // 第二步,获得任务的候选用户们 |  | ||||||
|             Set<Long> candidateUserIds = calculateTaskCandidateUsers(task, rule); |  | ||||||
|             // 第三步,设置一个作为负责人 |  | ||||||
|         Long assigneeUserId = chooseTaskAssignee(execution, candidateUserIds); |         Long assigneeUserId = chooseTaskAssignee(execution, candidateUserIds); | ||||||
|  |         // 第三步,设置作为负责人 | ||||||
|         TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId)); |         TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId)); | ||||||
|     } |     } | ||||||
|         */ |  | ||||||
|         // 第一步,获得任务的规则 |  | ||||||
|         BpmTaskAssignRuleDO rule = getTaskRule(task); |  | ||||||
|         // 第二步,获得任务的候选用户们 |  | ||||||
|         Set<Long> candidateUserIds = calculateTaskCandidateUsers(task, rule); |  | ||||||
|         // 第三步,设置一个作为负责人 |  | ||||||
|         Long assigneeUserId = chooseTaskAssignee(execution, candidateUserIds); |  | ||||||
|         TaskHelper.changeTaskAssignee(task, String.valueOf(assigneeUserId)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private BpmTaskAssignRuleDO getTaskRule(TaskEntity task) { |  | ||||||
|         List<BpmTaskAssignRuleDO> taskRules = |  | ||||||
|             bpmTaskRuleService.getTaskAssignRuleListByProcessDefinitionId(task.getProcessDefinitionId(), |  | ||||||
|                 task.getTaskDefinitionKey()); |  | ||||||
|         if (CollUtil.isEmpty(taskRules)) { |  | ||||||
|             throw new FlowableException( |  | ||||||
|                 StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则", task.getId(), task.getProcessDefinitionId(), |  | ||||||
|                     task.getTaskDefinitionKey())); |  | ||||||
|         } |  | ||||||
|         if (taskRules.size() > 1) { |  | ||||||
|             throw new FlowableException( |  | ||||||
|                 StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})", task.getId(), task.getProcessDefinitionId(), |  | ||||||
|                     task.getTaskDefinitionKey(), taskRules.size())); |  | ||||||
|         } |  | ||||||
|         return taskRules.get(0); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     Set<Long> calculateTaskCandidateUsers(TaskEntity task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         Set<Long> assigneeUserIds = null; |  | ||||||
|         if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); |  | ||||||
|         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType(), rule.getType())) { |  | ||||||
|             assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // 移除被禁用的用户 |  | ||||||
|         removeDisableUsers(assigneeUserIds); |  | ||||||
|         // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人 |  | ||||||
|         if (CollUtil.isEmpty(assigneeUserIds)) { |  | ||||||
|             log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", task.getId(), |  | ||||||
|                 task.getProcessDefinitionId(), task.getTaskDefinitionKey(), toJsonString(rule)); |  | ||||||
|             throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); |  | ||||||
|         } |  | ||||||
|         return assigneeUserIds; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Set<Long> calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions()); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         List<AdminUserRespDTO> users = adminUserApi.getUsersByDeptIds(rule.getOptions()); |  | ||||||
|         return convertSet(users, AdminUserRespDTO::getId); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         List<DeptRespDTO> depts = deptApi.getDepts(rule.getOptions()); |  | ||||||
|         return convertSet(depts, DeptRespDTO::getLeaderUserId); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions()); |  | ||||||
|         return convertSet(users, AdminUserRespDTO::getId); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Set<Long> calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         return rule.getOptions(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Set<Long> calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions()); |  | ||||||
|         Set<Long> userIds = new HashSet<>(); |  | ||||||
|         userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); |  | ||||||
|         return userIds; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Set<Long> calculateTaskCandidateUsersByScript(TaskEntity task, BpmTaskAssignRuleDO rule) { |  | ||||||
|         // 获得对应的脚本 |  | ||||||
|         List<BpmTaskAssignScript> scripts = new ArrayList<>(rule.getOptions().size()); |  | ||||||
|         rule.getOptions().forEach(id -> { |  | ||||||
|             BpmTaskAssignScript script = scriptMap.get(id); |  | ||||||
|             if (script == null) { |  | ||||||
|                 throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id); |  | ||||||
|             } |  | ||||||
|             scripts.add(script); |  | ||||||
|         }); |  | ||||||
|         // 逐个计算任务 |  | ||||||
|         Set<Long> userIds = new HashSet<>(); |  | ||||||
|         scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(task))); |  | ||||||
|         return userIds; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private Long chooseTaskAssignee(DelegateExecution execution, Set<Long> candidateUserIds) { |     private Long chooseTaskAssignee(DelegateExecution execution, Set<Long> candidateUserIds) { | ||||||
|         // 获取任务变量 |         // 获取任务变量 | ||||||
| @@ -214,16 +66,4 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { | |||||||
|         return CollUtil.get(candidateUserIds, index); |         return CollUtil.get(candidateUserIds, index); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @VisibleForTesting |  | ||||||
|     void removeDisableUsers(Set<Long> assigneeUserIds) { |  | ||||||
|         if (CollUtil.isEmpty(assigneeUserIds)) { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|         //TODO 芋艿 这里有数据权限的问题。默认会加上数据权限 dept_id IN (deptId). 导致查询不到数据 |  | ||||||
|         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds); |  | ||||||
|         assigneeUserIds.removeIf(id -> { |  | ||||||
|             AdminUserRespDTO user = userMap.get(id); |  | ||||||
|             return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,10 +4,12 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAs | |||||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; | ||||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; | ||||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | ||||||
|  | import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||||||
| import org.springframework.lang.Nullable; | import org.springframework.lang.Nullable; | ||||||
|  |  | ||||||
| import javax.validation.Valid; | import javax.validation.Valid; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * BPM 任务分配规则 Service 接口 |  * BPM 任务分配规则 Service 接口 | ||||||
| @@ -84,4 +86,6 @@ public interface BpmTaskAssignRuleService { | |||||||
|      */ |      */ | ||||||
|     void checkTaskAssignRuleAllConfig(String id); |     void checkTaskAssignRuleAllConfig(String id); | ||||||
|  |  | ||||||
|  |     Set<Long> calculateTaskCandidateUsers(TaskEntity task); | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,25 +3,35 @@ package cn.iocoder.yudao.module.bpm.service.definition; | |||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.hutool.core.util.ObjectUtil; | import cn.hutool.core.util.ObjectUtil; | ||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
|  | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||||
| import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | ||||||
|  | import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; | ||||||
| import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; | import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; | ||||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; | ||||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; | ||||||
| import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; | ||||||
| import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert; | import cn.iocoder.yudao.module.bpm.convert.definition.BpmTaskAssignRuleConvert; | ||||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | ||||||
|  | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; | ||||||
| import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; | import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; | ||||||
| import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; |  | ||||||
| import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum; | import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum; | ||||||
|  | import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; | ||||||
|  | import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | ||||||
| import cn.iocoder.yudao.module.system.api.dept.DeptApi; | import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||||||
| import cn.iocoder.yudao.module.system.api.dept.PostApi; | import cn.iocoder.yudao.module.system.api.dept.PostApi; | ||||||
|  | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||||||
| import cn.iocoder.yudao.module.system.api.dict.DictDataApi; | import cn.iocoder.yudao.module.system.api.dict.DictDataApi; | ||||||
|  | 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.permission.RoleApi; | ||||||
| import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||||||
|  | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||||||
|  | import com.google.common.annotations.VisibleForTesting; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.flowable.bpmn.model.BpmnModel; | import org.flowable.bpmn.model.BpmnModel; | ||||||
| import org.flowable.bpmn.model.UserTask; | import org.flowable.bpmn.model.UserTask; | ||||||
|  | import org.flowable.common.engine.api.FlowableException; | ||||||
|  | import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
| @@ -31,6 +41,9 @@ import javax.validation.Valid; | |||||||
| import java.util.*; | import java.util.*; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | ||||||
| import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -61,6 +74,17 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { | |||||||
|     private AdminUserApi adminUserApi; |     private AdminUserApi adminUserApi; | ||||||
|     @Resource |     @Resource | ||||||
|     private DictDataApi dictDataApi; |     private DictDataApi dictDataApi; | ||||||
|  |     @Resource | ||||||
|  |     private PermissionApi permissionApi; | ||||||
|  |     /** | ||||||
|  |      * 任务分配脚本 | ||||||
|  |      */ | ||||||
|  |     private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap(); | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     public void setScripts(List<BpmTaskAssignScript> scripts) { | ||||||
|  |         this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, |     public List<BpmTaskAssignRuleDO> getTaskAssignRuleListByProcessDefinitionId(String processDefinitionId, | ||||||
| @@ -198,10 +222,6 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { | |||||||
|             adminUserApi.validUsers(options); |             adminUserApi.validUsers(options); | ||||||
|         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_GROUP.getType())) { |         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_GROUP.getType())) { | ||||||
|             userGroupService.validUserGroups(options); |             userGroupService.validUserGroups(options); | ||||||
|         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_SIGN.getType())) { |  | ||||||
|             adminUserApi.validUsers(options); |  | ||||||
|         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType())) { |  | ||||||
|             adminUserApi.validUsers(options); |  | ||||||
|         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) { |         } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) { | ||||||
|             dictDataApi.validDictDatas(DictTypeConstants.TASK_ASSIGN_SCRIPT, |             dictDataApi.validDictDatas(DictTypeConstants.TASK_ASSIGN_SCRIPT, | ||||||
|                 CollectionUtils.convertSet(options, String::valueOf)); |                 CollectionUtils.convertSet(options, String::valueOf)); | ||||||
| @@ -209,4 +229,117 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { | |||||||
|             throw new IllegalArgumentException(StrUtil.format("未知的规则类型({})", type)); |             throw new IllegalArgumentException(StrUtil.format("未知的规则类型({})", type)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     @DataPermission(enable = false) // 忽略数据权限,不然分配会存在问题 | ||||||
|  |     public Set<Long> calculateTaskCandidateUsers(TaskEntity task) { | ||||||
|  |         BpmTaskAssignRuleDO rule = getTaskRule(task); | ||||||
|  |         return calculateTaskCandidateUsers(task, rule); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @VisibleForTesting | ||||||
|  |     BpmTaskAssignRuleDO getTaskRule(TaskEntity task) { | ||||||
|  |         List<BpmTaskAssignRuleDO> taskRules = getTaskAssignRuleListByProcessDefinitionId( | ||||||
|  |                 task.getProcessDefinitionId(), task.getTaskDefinitionKey()); | ||||||
|  |         if (CollUtil.isEmpty(taskRules)) { | ||||||
|  |             throw new FlowableException( | ||||||
|  |                     StrUtil.format("流程任务({}/{}/{}) 找不到符合的任务规则", task.getId(), task.getProcessDefinitionId(), | ||||||
|  |                             task.getTaskDefinitionKey())); | ||||||
|  |         } | ||||||
|  |         if (taskRules.size() > 1) { | ||||||
|  |             throw new FlowableException( | ||||||
|  |                     StrUtil.format("流程任务({}/{}/{}) 找到过多任务规则({})", task.getId(), task.getProcessDefinitionId(), | ||||||
|  |                             task.getTaskDefinitionKey(), taskRules.size())); | ||||||
|  |         } | ||||||
|  |         return taskRules.get(0); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @VisibleForTesting | ||||||
|  |     Set<Long> calculateTaskCandidateUsers(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         Set<Long> assigneeUserIds = null; | ||||||
|  |         if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), rule.getType())) { | ||||||
|  |             assigneeUserIds = calculateTaskCandidateUsersByRole(task, rule); | ||||||
|  |         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) { | ||||||
|  |             assigneeUserIds = calculateTaskCandidateUsersByDeptMember(task, rule); | ||||||
|  |         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { | ||||||
|  |             assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(task, rule); | ||||||
|  |         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), rule.getType())) { | ||||||
|  |             assigneeUserIds = calculateTaskCandidateUsersByPost(task, rule); | ||||||
|  |         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), rule.getType())) { | ||||||
|  |             assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); | ||||||
|  |         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) { | ||||||
|  |             assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule); | ||||||
|  |         } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) { | ||||||
|  |             assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // 移除被禁用的用户 | ||||||
|  |         removeDisableUsers(assigneeUserIds); | ||||||
|  |         // 如果候选人为空,抛出异常 TODO 芋艿:没候选人的策略选择。1 - 挂起;2 - 直接结束;3 - 强制一个兜底人 | ||||||
|  |         if (CollUtil.isEmpty(assigneeUserIds)) { | ||||||
|  |             log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}) 找不到候选人]", task.getId(), | ||||||
|  |                     task.getProcessDefinitionId(), task.getTaskDefinitionKey(), toJsonString(rule)); | ||||||
|  |             throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); | ||||||
|  |         } | ||||||
|  |         return assigneeUserIds; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Set<Long> calculateTaskCandidateUsersByRole(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Set<Long> calculateTaskCandidateUsersByDeptMember(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         List<AdminUserRespDTO> users = adminUserApi.getUsersByDeptIds(rule.getOptions()); | ||||||
|  |         return convertSet(users, AdminUserRespDTO::getId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Set<Long> calculateTaskCandidateUsersByDeptLeader(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         List<DeptRespDTO> depts = deptApi.getDepts(rule.getOptions()); | ||||||
|  |         return convertSet(depts, DeptRespDTO::getLeaderUserId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Set<Long> calculateTaskCandidateUsersByPost(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         List<AdminUserRespDTO> users = adminUserApi.getUsersByPostIds(rule.getOptions()); | ||||||
|  |         return convertSet(users, AdminUserRespDTO::getId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Set<Long> calculateTaskCandidateUsersByUser(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         return rule.getOptions(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Set<Long> calculateTaskCandidateUsersByUserGroup(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         List<BpmUserGroupDO> userGroups = userGroupService.getUserGroupList(rule.getOptions()); | ||||||
|  |         Set<Long> userIds = new HashSet<>(); | ||||||
|  |         userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); | ||||||
|  |         return userIds; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private Set<Long> calculateTaskCandidateUsersByScript(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||||||
|  |         // 获得对应的脚本 | ||||||
|  |         List<BpmTaskAssignScript> scripts = new ArrayList<>(rule.getOptions().size()); | ||||||
|  |         rule.getOptions().forEach(id -> { | ||||||
|  |             BpmTaskAssignScript script = scriptMap.get(id); | ||||||
|  |             if (script == null) { | ||||||
|  |                 throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id); | ||||||
|  |             } | ||||||
|  |             scripts.add(script); | ||||||
|  |         }); | ||||||
|  |         // 逐个计算任务 | ||||||
|  |         Set<Long> userIds = new HashSet<>(); | ||||||
|  |         scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(task))); | ||||||
|  |         return userIds; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @VisibleForTesting | ||||||
|  |     void removeDisableUsers(Set<Long> assigneeUserIds) { | ||||||
|  |         if (CollUtil.isEmpty(assigneeUserIds)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds); | ||||||
|  |         assigneeUserIds.removeIf(id -> { | ||||||
|  |             AdminUserRespDTO user = userMap.get(id); | ||||||
|  |             return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -15,7 +15,6 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; | |||||||
| import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; | import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; | ||||||
| import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper; | import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmActivityMapper; | ||||||
| import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; | import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; | ||||||
| import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum; |  | ||||||
| import cn.iocoder.yudao.module.bpm.domain.enums.task.BpmProcessInstanceResultEnum; | import cn.iocoder.yudao.module.bpm.domain.enums.task.BpmProcessInstanceResultEnum; | ||||||
| import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; | import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; | ||||||
| import cn.iocoder.yudao.module.business.hi.task.inst.service.HiTaskInstService; | import cn.iocoder.yudao.module.business.hi.task.inst.service.HiTaskInstService; | ||||||
| @@ -214,11 +213,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|             taskAssignRuleMapper.selectListByProcessDefinitionId(task.getProcessDefinitionId(), |             taskAssignRuleMapper.selectListByProcessDefinitionId(task.getProcessDefinitionId(), | ||||||
|                 task.getTaskDefinitionKey()); |                 task.getTaskDefinitionKey()); | ||||||
|         if (CollUtil.isNotEmpty(bpmTaskAssignRuleList) && bpmTaskAssignRuleList.size() > 0) { |         if (CollUtil.isNotEmpty(bpmTaskAssignRuleList) && bpmTaskAssignRuleList.size() > 0) { | ||||||
|             if (BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType().equals(bpmTaskAssignRuleList.get(0).getType())) { |             // edit by 芋艿 | ||||||
|                 taskExtMapper.delTaskByProcInstIdAndTaskIdAndTaskDefKey( | //            if (BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType().equals(bpmTaskAssignRuleList.get(0).getType())) { | ||||||
|                     new BpmTaskExtDO().setTaskId(task.getId()).setTaskDefKey(task.getTaskDefinitionKey()) | //                taskExtMapper.delTaskByProcInstIdAndTaskIdAndTaskDefKey( | ||||||
|                         .setProcessInstanceId(task.getProcessInstanceId())); | //                    new BpmTaskExtDO().setTaskId(task.getId()).setTaskDefKey(task.getTaskDefinitionKey()) | ||||||
|             } | //                        .setProcessInstanceId(task.getProcessInstanceId())); | ||||||
|  | //            } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPage | |||||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | ||||||
| import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; | import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; | ||||||
| import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; | import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; | ||||||
| import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum; |  | ||||||
| import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | ||||||
| import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; | import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; | ||||||
| import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; | import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; | ||||||
| @@ -21,14 +20,18 @@ import org.flowable.common.engine.impl.de.odysseus.el.ExpressionFactoryImpl; | |||||||
| import org.flowable.common.engine.impl.de.odysseus.el.util.SimpleContext; | import org.flowable.common.engine.impl.de.odysseus.el.util.SimpleContext; | ||||||
| import org.flowable.common.engine.impl.javax.el.ExpressionFactory; | import org.flowable.common.engine.impl.javax.el.ExpressionFactory; | ||||||
| import org.flowable.common.engine.impl.javax.el.ValueExpression; | import org.flowable.common.engine.impl.javax.el.ValueExpression; | ||||||
| import org.flowable.engine.*; | import org.flowable.engine.HistoryService; | ||||||
|  | import org.flowable.engine.RepositoryService; | ||||||
| import org.flowable.engine.history.HistoricProcessInstance; | import org.flowable.engine.history.HistoricProcessInstance; | ||||||
| import org.flowable.task.api.history.HistoricTaskInstance; | import org.flowable.task.api.history.HistoricTaskInstance; | ||||||
| import org.flowable.variable.api.history.HistoricVariableInstance; | import org.flowable.variable.api.history.HistoricVariableInstance; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
|  |  | ||||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||||
| import java.util.*; | import java.util.HashMap; | ||||||
|  | import java.util.LinkedList; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
| import java.util.function.Function; | import java.util.function.Function; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  |  | ||||||
| @@ -259,10 +262,11 @@ public class HiTaskInstService { | |||||||
|                     DeptDO deptDO = deptMap.get(adminUserDO.getDeptId()); |                     DeptDO deptDO = deptMap.get(adminUserDO.getDeptId()); | ||||||
|                     bpmTaskRespVO.setAssigneeUser(setUser(adminUserDO)); |                     bpmTaskRespVO.setAssigneeUser(setUser(adminUserDO)); | ||||||
|                     bpmTaskRespVO.getAssigneeUser().setDeptName(deptDO.getName()); |                     bpmTaskRespVO.getAssigneeUser().setDeptName(deptDO.getName()); | ||||||
|                     if (!bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType()) |                     // edit by 芋艿 | ||||||
|                         && !bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType())) { | //                    if (!bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_OR_SIGN.getType()) | ||||||
|                         break; | //                        && !bpmTaskAssignRuleDO.getType().equals(BpmTaskAssignRuleTypeEnum.USER_SIGN.getType())) { | ||||||
|                     } | //                        break; | ||||||
|  | //                    } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             getFlow(bpmnModel, nextTaskDefKey, tmpBpmTaskAssignRuleDOList, bpmTaskRespVOList, userDoMap, deptMap, |             getFlow(bpmnModel, nextTaskDefKey, tmpBpmTaskAssignRuleDOList, bpmTaskRespVOList, userDoMap, deptMap, | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ | |||||||
|         SELECT * |         SELECT * | ||||||
|         FROM act_hi_taskinst; |         FROM act_hi_taskinst; | ||||||
|     </select> |     </select> | ||||||
|  |  | ||||||
|     <select id="listAllByProcInstIdAndDelete" |     <select id="listAllByProcInstIdAndDelete" | ||||||
|             resultType="cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO"> |             resultType="cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmActivityDO"> | ||||||
|         SELECT id_                AS `id`, |         SELECT id_                AS `id`, | ||||||
|   | |||||||
| @@ -0,0 +1,96 @@ | |||||||
|  | package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; | ||||||
|  |  | ||||||
|  | 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.flowable.task.service.impl.persistence.entity.TaskEntity; | ||||||
|  | import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; | ||||||
|  | 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 org.junit.jupiter.api.Assertions.assertEquals; | ||||||
|  | import static org.mockito.ArgumentMatchers.eq; | ||||||
|  | import static org.mockito.Mockito.when; | ||||||
|  |  | ||||||
|  | public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { | ||||||
|  |  | ||||||
|  |     @InjectMocks | ||||||
|  |     private BpmTaskAssignLeaderX2Script script; | ||||||
|  |  | ||||||
|  |     @Mock | ||||||
|  |     private AdminUserApi adminUserApi; | ||||||
|  |     @Mock | ||||||
|  |     private DeptApi deptApi; | ||||||
|  |     @Mock | ||||||
|  |     private BpmProcessInstanceService bpmProcessInstanceService; | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_noDept() { | ||||||
|  |         // 准备参数 | ||||||
|  |         TaskEntity task = buildTaskEntity(1L); | ||||||
|  |         // mock 方法(startUser) | ||||||
|  |         AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); | ||||||
|  |         when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> result = script.calculateTaskCandidateUsers(task); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(0, result.size()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_noParentDept() { | ||||||
|  |         // 准备参数 | ||||||
|  |         TaskEntity task = buildTaskEntity(1L); | ||||||
|  |         // mock 方法(startUser) | ||||||
|  |         AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); | ||||||
|  |         when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); | ||||||
|  |         DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) | ||||||
|  |                 .setLeaderUserId(20L)); | ||||||
|  |         when(deptApi.getDept(eq(10L))).thenReturn(startUserDept); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> result = script.calculateTaskCandidateUsers(task); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(20L), result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_existParentDept() { | ||||||
|  |         // 准备参数 | ||||||
|  |         TaskEntity task = buildTaskEntity(1L); | ||||||
|  |         // mock 方法(startUser) | ||||||
|  |         AdminUserRespDTO startUser = randomPojo(AdminUserRespDTO.class, o -> o.setDeptId(10L)); | ||||||
|  |         when(adminUserApi.getUser(eq(1L))).thenReturn(startUser); | ||||||
|  |         DeptRespDTO startUserDept = randomPojo(DeptRespDTO.class, o -> o.setId(10L).setParentId(100L) | ||||||
|  |                 .setLeaderUserId(20L)); | ||||||
|  |         when(deptApi.getDept(eq(10L))).thenReturn(startUserDept); | ||||||
|  |         // mock 方法(父 dept) | ||||||
|  |         DeptRespDTO parentDept = randomPojo(DeptRespDTO.class, o -> o.setId(100L).setParentId(1000L) | ||||||
|  |                 .setLeaderUserId(200L)); | ||||||
|  |         when(deptApi.getDept(eq(100L))).thenReturn(parentDept); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> result = script.calculateTaskCandidateUsers(task); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(200L), result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @SuppressWarnings("SameParameterValue") | ||||||
|  |     private TaskEntity buildTaskEntity(Long startUserId) { | ||||||
|  |         TaskEntityImpl task = new TaskEntityImpl(); | ||||||
|  | //        task.setProcessInstance(new ExecutionEntityImpl()); | ||||||
|  | //        task.getProcessInstance().setStartUserId(String.valueOf(startUserId)); | ||||||
|  |         // TODO | ||||||
|  |         return task; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,217 @@ | |||||||
|  | package cn.iocoder.yudao.module.bpm.service.definition; | ||||||
|  |  | ||||||
|  | import cn.hutool.core.map.MapUtil; | ||||||
|  | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||||
|  | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | ||||||
|  | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | ||||||
|  | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; | ||||||
|  | import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskAssignRuleTypeEnum; | ||||||
|  | import cn.iocoder.yudao.module.bpm.domain.enums.definition.BpmTaskRuleScriptEnum; | ||||||
|  | import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | ||||||
|  | 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.permission.PermissionApi; | ||||||
|  | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||||||
|  | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||||||
|  | import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||||||
|  | import org.junit.jupiter.api.Test; | ||||||
|  | import org.springframework.boot.test.mock.mockito.MockBean; | ||||||
|  | import org.springframework.context.annotation.Import; | ||||||
|  |  | ||||||
|  | import javax.annotation.Resource; | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | 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.Collections.singleton; | ||||||
|  | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||||
|  | import static org.mockito.ArgumentMatchers.eq; | ||||||
|  | import static org.mockito.Mockito.when; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * {@link BpmTaskAssignRuleService} 的单元测试 | ||||||
|  |  * | ||||||
|  |  * @author 芋道源码 | ||||||
|  |  */ | ||||||
|  | @Import(BpmTaskAssignRuleServiceImpl.class) | ||||||
|  | public class BpmTaskAssignRuleServiceImplTest extends BaseDbUnitTest { | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private BpmTaskAssignRuleServiceImpl bpmTaskRuleService; | ||||||
|  |  | ||||||
|  |     @MockBean | ||||||
|  |     private BpmUserGroupService userGroupService; | ||||||
|  |     @MockBean | ||||||
|  |     private DeptApi deptApi; | ||||||
|  |     @MockBean | ||||||
|  |     private AdminUserApi adminUserApi; | ||||||
|  |     @MockBean | ||||||
|  |     private PermissionApi permissionApi; | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_Role() { | ||||||
|  |         // 准备参数 | ||||||
|  |         BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) | ||||||
|  |                 .setType(BpmTaskAssignRuleTypeEnum.ROLE.getType()); | ||||||
|  |         // mock 方法 | ||||||
|  |         when(permissionApi.getUserRoleIdListByRoleIds(eq(rule.getOptions()))) | ||||||
|  |                 .thenReturn(asSet(11L, 22L)); | ||||||
|  |         mockGetUserMap(asSet(11L, 22L)); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(11L, 22L), results); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_DeptMember() { | ||||||
|  |         // 准备参数 | ||||||
|  |         BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) | ||||||
|  |                 .setType(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType()); | ||||||
|  |         // mock 方法 | ||||||
|  |         List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L), | ||||||
|  |                 id -> new AdminUserRespDTO().setId(id)); | ||||||
|  |         when(adminUserApi.getUsersByDeptIds(eq(rule.getOptions()))).thenReturn(users); | ||||||
|  |         mockGetUserMap(asSet(11L, 22L)); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(11L, 22L), results); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_DeptLeader() { | ||||||
|  |         // 准备参数 | ||||||
|  |         BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) | ||||||
|  |                 .setType(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType()); | ||||||
|  |         // mock 方法 | ||||||
|  |         DeptRespDTO dept1 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(11L)); | ||||||
|  |         DeptRespDTO dept2 = randomPojo(DeptRespDTO.class, o -> o.setLeaderUserId(22L)); | ||||||
|  |         when(deptApi.getDepts(eq(rule.getOptions()))).thenReturn(Arrays.asList(dept1, dept2)); | ||||||
|  |         mockGetUserMap(asSet(11L, 22L)); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(11L, 22L), results); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_Post() { | ||||||
|  |         // 准备参数 | ||||||
|  |         BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) | ||||||
|  |                 .setType(BpmTaskAssignRuleTypeEnum.POST.getType()); | ||||||
|  |         // mock 方法 | ||||||
|  |         List<AdminUserRespDTO> users = CollectionUtils.convertList(asSet(11L, 22L), | ||||||
|  |                 id -> new AdminUserRespDTO().setId(id)); | ||||||
|  |         when(adminUserApi.getUsersByPostIds(eq(rule.getOptions()))).thenReturn(users); | ||||||
|  |         mockGetUserMap(asSet(11L, 22L)); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(11L, 22L), results); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_User() { | ||||||
|  |         // 准备参数 | ||||||
|  |         BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) | ||||||
|  |                 .setType(BpmTaskAssignRuleTypeEnum.USER.getType()); | ||||||
|  |         // mock 方法 | ||||||
|  |         mockGetUserMap(asSet(1L, 2L)); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(1L, 2L), results); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_UserGroup() { | ||||||
|  |         // 准备参数 | ||||||
|  |         BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(1L, 2L)) | ||||||
|  |                 .setType(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType()); | ||||||
|  |         // mock 方法 | ||||||
|  |         BpmUserGroupDO userGroup1 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(11L, 12L))); | ||||||
|  |         BpmUserGroupDO userGroup2 = randomPojo(BpmUserGroupDO.class, o -> o.setMemberUserIds(asSet(21L, 22L))); | ||||||
|  |         when(userGroupService.getUserGroupList(eq(rule.getOptions()))).thenReturn(Arrays.asList(userGroup1, userGroup2)); | ||||||
|  |         mockGetUserMap(asSet(11L, 12L, 21L, 22L)); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(11L, 12L, 21L, 22L), results); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testCalculateTaskCandidateUsers_Script() { | ||||||
|  |         // 准备参数 | ||||||
|  |         BpmTaskAssignRuleDO rule = new BpmTaskAssignRuleDO().setOptions(asSet(20L, 21L)) | ||||||
|  |                 .setType(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); | ||||||
|  |         // mock 方法 | ||||||
|  |         BpmTaskAssignScript script1 = new BpmTaskAssignScript() { | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             public Set<Long> calculateTaskCandidateUsers(TaskEntity task) { | ||||||
|  |                 return singleton(11L); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             public BpmTaskRuleScriptEnum getEnum() { | ||||||
|  |                 return BpmTaskRuleScriptEnum.LEADER_X1; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         BpmTaskAssignScript script2 = new BpmTaskAssignScript() { | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             public Set<Long> calculateTaskCandidateUsers(TaskEntity task) { | ||||||
|  |                 return singleton(22L); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             @Override | ||||||
|  |             public BpmTaskRuleScriptEnum getEnum() { | ||||||
|  |                 return BpmTaskRuleScriptEnum.LEADER_X2; | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         bpmTaskRuleService.setScripts(Arrays.asList(script1, script2)); | ||||||
|  |         mockGetUserMap(asSet(11L, 22L)); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         Set<Long> results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(11L, 22L), results); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Test | ||||||
|  |     public void testRemoveDisableUsers() { | ||||||
|  |         // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 | ||||||
|  |         Set<Long> assigneeUserIds = asSet(1L, 2L, 3L); | ||||||
|  |         // mock 方法 | ||||||
|  |         AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) | ||||||
|  |                 .setStatus(CommonStatusEnum.ENABLE.getStatus())); | ||||||
|  |         AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) | ||||||
|  |                 .setStatus(CommonStatusEnum.DISABLE.getStatus())); | ||||||
|  |         Map<Long, AdminUserRespDTO> userMap = MapUtil.builder(user1.getId(), user1) | ||||||
|  |                 .put(user2.getId(), user2).build(); | ||||||
|  |         when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); | ||||||
|  |  | ||||||
|  |         // 调用 | ||||||
|  |         bpmTaskRuleService.removeDisableUsers(assigneeUserIds); | ||||||
|  |         // 断言 | ||||||
|  |         assertEquals(asSet(1L), assigneeUserIds); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void mockGetUserMap(Set<Long> assigneeUserIds) { | ||||||
|  |         Map<Long, AdminUserRespDTO> userMap = CollectionUtils.convertMap(assigneeUserIds, id -> id, | ||||||
|  |                 id -> new AdminUserRespDTO().setId(id).setStatus(CommonStatusEnum.ENABLE.getStatus())); | ||||||
|  |         when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV