diff --git a/pom.xml b/pom.xml index 3a66524bc..1b5fc92c1 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ yudao-module-system yudao-module-infra - + yudao-module-bpm diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java index c434b2577..d236d1817 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.common.util.string; +import cn.hutool.core.text.StrPool; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; @@ -46,6 +47,10 @@ public class StrUtils { return Arrays.stream(longs).boxed().collect(Collectors.toList()); } + public static Set splitToLongSet(String value) { + return splitToLongSet(value, StrPool.COMMA); + } + public static Set splitToLongSet(String value, CharSequence separator) { long[] longs = StrUtil.splitToLong(value, separator); return Arrays.stream(longs).boxed().collect(Collectors.toSet()); diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index 646841b34..bdc3d17ce 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -26,7 +26,7 @@ public interface ErrorCodeConstants { ErrorCode MODEL_NOT_EXISTS = new ErrorCode(1_009_002_001, "流程模型不存在"); ErrorCode MODEL_KEY_VALID = new ErrorCode(1_009_002_002, "流程标识格式不正确,需要以字母或下划线开头,后接任意字母、数字、中划线、下划线、句点!"); ErrorCode MODEL_DEPLOY_FAIL_FORM_NOT_CONFIG = new ErrorCode(1_009_002_003, "部署流程失败,原因:流程表单未配置,请点击【修改流程】按钮进行配置"); - ErrorCode MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," + + ErrorCode MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG = new ErrorCode(1_009_002_004, "部署流程失败," + "原因:用户任务({})未配置审批人,请点击【流程设计】按钮,选择该它的【任务(审批人)】进行配置"); ErrorCode MODEL_DEPLOY_FAIL_TASK_INFO_EQUALS = new ErrorCode(1_009_003_005, "流程定义部署失败,原因:信息未发生变化"); diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java deleted file mode 100644 index d220da746..000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskAssignRuleTypeEnum.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.bpm.enums.definition; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * BPM 任务分配规则的类型枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum BpmTaskAssignRuleTypeEnum { - - ROLE(10, "角色"), - DEPT_MEMBER(20, "部门的成员"), // 包括负责人 - DEPT_LEADER(21, "部门的负责人"), - POST(22, "岗位"), - USER(30, "用户"), - USER_GROUP(40, "用户组"), - @Deprecated - SCRIPT(50, "自定义脚本"), // 例如说,发起人所在部门的领导、发起人所在部门的领导的领导 - EXPRESS(60, "流程表达式"), // 表达式 ExpressionManager - ; - - /** - * 类型 - */ - private final Integer type; - /** - * 描述 - */ - private final String desc; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java deleted file mode 100644 index 7fc0e3b8b..000000000 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTaskRuleScriptEnum.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.bpm.enums.definition; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * BPM 任务规则的脚本枚举 - * 目前暂时通过 TODO 芋艿:硬编码,未来可以考虑 Groovy 动态脚本的方式 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum BpmTaskRuleScriptEnum { - - START_USER(10L, "流程发起人"), - - LEADER_X1(20L, "流程发起人的一级领导"), - LEADER_X2(21L, "流程发起人的二级领导"); - - /** - * 脚本编号 - */ - private final Long id; - /** - * 脚本描述 - */ - private final String desc; - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCandidateProcessorConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCandidateProcessorConfiguration.java deleted file mode 100644 index cff03488b..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/bpm/config/BpmCandidateProcessorConfiguration.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.bpm.config; - -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor.*; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -// TODO @芋艿:Candidate 相关还在完善中,用户可以暂时忽略,仅 yudao 开发的同学需要关注~计划是把 Candidate 和 Assign 融合成一套 -/** - * BPM 通用的 Configuration 配置类,提供给 Activiti 和 Flowable - * @author kyle - */ -@Configuration(proxyBeanMethods = false) -public class BpmCandidateProcessorConfiguration { - @Bean - public BpmCandidateAdminUserApiSourceInfoProcessor bpmCandidateAdminUserApiSourceInfoProcessor() { - return new BpmCandidateAdminUserApiSourceInfoProcessor(); - } - - @Bean - public BpmCandidateDeptApiSourceInfoProcessor bpmCandidateDeptApiSourceInfoProcessor() { - return new BpmCandidateDeptApiSourceInfoProcessor(); - } - - @Bean - public BpmCandidatePostApiSourceInfoProcessor bpmCandidatePostApiSourceInfoProcessor() { - return new BpmCandidatePostApiSourceInfoProcessor(); - } - - @Bean - public BpmCandidateRoleApiSourceInfoProcessor bpmCandidateRoleApiSourceInfoProcessor() { - return new BpmCandidateRoleApiSourceInfoProcessor(); - } - - @Bean - public BpmCandidateUserGroupApiSourceInfoProcessor bpmCandidateUserGroupApiSourceInfoProcessor() { - return new BpmCandidateUserGroupApiSourceInfoProcessor(); - } - - /** - * 可以自己定制脚本,然后通过这里设置到处理器里面去 - * @param scriptsOp 脚本包装对象 - * @return - */ - @Bean - public BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor(ObjectProvider scriptsOp) { - BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor = new BpmCandidateScriptApiSourceInfoProcessor(); - bpmCandidateScriptApiSourceInfoProcessor.setScripts(scriptsOp); - return bpmCandidateScriptApiSourceInfoProcessor; - } -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java index c048d9c73..9248da552 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java @@ -2,7 +2,9 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.config; import cn.hutool.core.collection.ListUtil; import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.spring.SpringProcessEngineConfiguration; import org.flowable.spring.boot.EngineConfigurationConfigurer; @@ -10,6 +12,8 @@ import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.List; + /** * BPM 模块的 Flowable 配置类 * @@ -36,11 +40,20 @@ public class BpmFlowableConfiguration { }; } + // =========== 审批人相关的 Bean ========== + @Bean - public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskAssignRuleService taskRuleService) { + public BpmActivityBehaviorFactory bpmActivityBehaviorFactory(BpmTaskCandidateInvoker bpmTaskCandidateInvoker) { BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); - bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService); + bpmActivityBehaviorFactory.setTaskCandidateInvoker(bpmTaskCandidateInvoker); return bpmActivityBehaviorFactory; } -} + @Bean + @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection") // adminUserApi 可以注入成功 + public BpmTaskCandidateInvoker bpmTaskCandidateInvoker(List strategyList, + AdminUserApi adminUserApi) { + return new BpmTaskCandidateInvoker(strategyList, adminUserApi); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java index dced1c5bd..e9f1f32d7 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; -import lombok.Data; -import lombok.EqualsAndHashCode; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; -import lombok.ToString; import org.flowable.bpmn.model.Activity; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior; @@ -18,25 +15,22 @@ import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFacto * * @author 芋道源码 */ -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) +@Setter public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { - @Setter - private BpmTaskAssignRuleService bpmTaskRuleService; + private BpmTaskCandidateInvoker taskCandidateInvoker; @Override public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { return new BpmUserTaskActivityBehavior(userTask) - .setBpmTaskRuleService(bpmTaskRuleService); + .setTaskCandidateInvoker(taskCandidateInvoker); } @Override public ParallelMultiInstanceBehavior createParallelMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { return new BpmParallelMultiInstanceBehavior(activity, innerActivityBehavior) - .setBpmTaskRuleService(bpmTaskRuleService); + .setTaskCandidateInvoker(taskCandidateInvoker); } // TODO @ke:SequentialMultiInstanceBehavior 这个抽空也可以看看 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java index 0b60faa06..ed51b23fa 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmParallelMultiInstanceBehavior.java @@ -1,7 +1,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.Activity; @@ -23,7 +23,7 @@ import java.util.Set; public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehavior { @Setter - private BpmTaskAssignRuleService bpmTaskRuleService; + private BpmTaskCandidateInvoker taskCandidateInvoker; public BpmParallelMultiInstanceBehavior(Activity activity, AbstractBpmnActivityBehavior innerActivityBehavior) { @@ -50,7 +50,7 @@ public class BpmParallelMultiInstanceBehavior extends ParallelMultiInstanceBehav super.collectionElementVariable = FlowableUtils.formatCollectionElementVariable(execution.getCurrentActivityId()); // 第二步,获取任务的所有处理人 - Set assigneeUserIds = bpmTaskRuleService.calculateTaskCandidateUsers(execution); + Set assigneeUserIds = taskCandidateInvoker.calculateUsers(execution); execution.setVariable(super.collectionVariable, assigneeUserIds); return assigneeUserIds.size(); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java index aeda4d52c..de17502bf 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.RandomUtil; -import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.UserTask; @@ -29,7 +29,7 @@ import java.util.Set; public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { @Setter - private BpmTaskAssignRuleService bpmTaskRuleService; + private BpmTaskCandidateInvoker taskCandidateInvoker; public BpmUserTaskActivityBehavior(UserTask userTask) { super(userTask); @@ -54,7 +54,7 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { // 情况二,如果非多实例的任务,则计算任务处理人 // 第一步,先计算可处理该任务的处理人们 - Set candidateUserIds = bpmTaskRuleService.calculateTaskCandidateUsers(execution); + Set candidateUserIds = taskCandidateInvoker.calculateUsers(execution); // 第二步,后随机选择一个任务的处理人 // 疑问:为什么一定要选择一个任务处理人? // 解答:项目对 bpm 的任务是责任到人,所以每个任务有且仅有一个处理人。 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java deleted file mode 100644 index c39059048..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script; - -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import org.flowable.engine.delegate.DelegateExecution; - -import java.util.Set; - -/** - * Bpm 任务分配的自定义 Script 脚本 - * 使用场景: - * 1. 设置审批人为发起人 - * 2. 设置审批人为发起人的 Leader - * 3. 甚至审批人为发起人的 Leader 的 Leader - * - * @author 芋道源码 - */ -@Deprecated -public interface BpmTaskAssignScript { - - /** - * 基于执行任务,获得任务的候选用户们 - * - * @param execution 执行任务 - * @return 候选人用户的编号数组 - */ - Set calculateTaskCandidateUsers(DelegateExecution execution); - - /** - * 获得枚举值 - * - * @return 枚举值 - */ - BpmTaskRuleScriptEnum getEnum(); - -} - diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java deleted file mode 100644 index 9c31970f7..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; - -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.stereotype.Component; - -import java.util.Set; - -/** - * 分配给发起人的一级 Leader 审批的 Script 实现类 - * - * @author 芋道源码 - */ -@Deprecated -@Component -public class BpmTaskAssignLeaderX1Script extends BpmTaskAssignLeaderAbstractScript { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution execution) { - return calculateTaskCandidateUsers(execution, 1); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X1; - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java deleted file mode 100644 index 935545100..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; - -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.stereotype.Component; - -import java.util.Set; - -/** - * 分配给发起人的二级 Leader 审批的 Script 实现类 - * - * @author 芋道源码 - */ -@Deprecated -@Component -public class BpmTaskAssignLeaderX2Script extends BpmTaskAssignLeaderAbstractScript { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution execution) { - return calculateTaskCandidateUsers(execution, 2); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X2; - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java new file mode 100644 index 000000000..d1ba65df2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; +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; +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 java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER; + +/** + * {@link BpmTaskCandidateStrategy} 的调用者,用于调用对应的策略,实现任务的候选人的计算 + * + * @author 芋道源码 + */ +@Slf4j +public class BpmTaskCandidateInvoker { + + private final Map strategyMap = new HashMap<>(); + + private final AdminUserApi adminUserApi; + + public BpmTaskCandidateInvoker(List strategyList, + AdminUserApi adminUserApi) { + strategyList.forEach(strategy -> { + BpmTaskCandidateStrategy oldStrategy = strategyMap.put(strategy.getStrategy(), strategy); + Assert.isNull(oldStrategy, "策略(%s) 重复", strategy.getStrategy()); + }); + this.adminUserApi = adminUserApi; + } + + /** + * 校验流程模型的任务分配规则全部都配置了 + * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去! + * + * @param bpmnBytes BPMN XML + */ + public void validateBpmnConfig(byte[] bpmnBytes) { + BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); + assert bpmnModel != null; + List userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); + // 遍历所有的 UserTask,校验审批人配置 + userTaskList.forEach(userTask -> { + // 1. 非空校验 + Integer strategy = parseCandidateStrategy(userTask); + String param = parseCandidateParam(userTask); + if (strategy == null || StrUtil.isBlank(param)) { + throw exception(MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG, userTask.getName()); + } + // 2. 具体策略校验 + getCandidateStrategy(strategy).validateParam(param); + }); + } + + /** + * 计算任务的候选人 + * + * @param execution 执行任务 + * @return 用户编号集合 + */ + public Set calculateUsers(DelegateExecution execution) { + // TODO 芋艿:这里需要重构 +// // 1. 先从提前选好的审批人中获取 +// List assignee = processInstanceService.getAssigneeByProcessInstanceIdAndTaskDefinitionKey( +// execution.getProcessInstanceId(), execution.getCurrentActivityId()); +// if (CollUtil.isNotEmpty(assignee)) { +// // TODO @hai:new HashSet 即可 +// return convertSet(assignee, Function.identity()); +// } + Integer strategy = parseCandidateStrategy(execution.getCurrentFlowElement()); + String param = parseCandidateParam(execution.getCurrentFlowElement()); + // 1.1 计算任务的候选人 + Set userIds = getCandidateStrategy(strategy).calculateUsers(execution, param); + // 1.2 移除被禁用的用户 + removeDisableUsers(userIds); + + // 2. 校验是否有候选人 + if (CollUtil.isEmpty(userIds)) { + log.error("[calculateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(), + execution.getProcessDefinitionId(), execution.getCurrentActivityId(), strategy, param); + throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); + } + return userIds; + } + + @VisibleForTesting + void removeDisableUsers(Set assigneeUserIds) { + if (CollUtil.isEmpty(assigneeUserIds)) { + return; + } + Map userMap = adminUserApi.getUserMap(assigneeUserIds); + assigneeUserIds.removeIf(id -> { + AdminUserRespDTO user = userMap.get(id); + return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); + }); + } + + private static Integer parseCandidateStrategy(FlowElement userTask) { + return NumberUtils.parseInt(userTask.getAttributeValue( + BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY)); + } + + private static String parseCandidateParam(FlowElement userTask) { + return userTask.getAttributeValue( + BpmnModelConstants.NAMESPACE, BpmnModelConstants.USER_TASK_CANDIDATE_PARAM); + } + + private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) { + BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy); + Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy); + BpmTaskCandidateStrategy strategyObj = strategyMap.get(strategyEnum); + Assert.notNull(strategyObj, "策略(%s) 不存在", strategy); + return strategyObj; + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java new file mode 100644 index 000000000..a5c5c9b4d --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateStrategy.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate; + +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import org.flowable.engine.delegate.DelegateExecution; + +import java.util.Set; + +/** + * BPM 任务的候选人的策略接口 + * + * 例如说:分配审批人 + * + * @author 芋道源码 + */ +public interface BpmTaskCandidateStrategy { + + /** + * 对应策略 + * + * @return 策略 + */ + BpmTaskCandidateStrategyEnum getStrategy(); + + /** + * 校验参数 + * + * @param param 参数 + */ + void validateParam(String param); + + /** + * 基于执行任务,获得任务的候选用户们 + * + * @param execution 执行任务 + * @return 用户编号集合 + */ + Set calculateUsers(DelegateExecution execution, String param); + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java similarity index 81% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java index 22ef4cde7..cb5306548 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpression.java @@ -1,7 +1,6 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; 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; @@ -9,7 +8,7 @@ import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; -import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; import org.springframework.util.Assert; import jakarta.annotation.Resource; @@ -19,23 +18,23 @@ import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; import static java.util.Collections.emptySet; /** - * 分配给发起人的 Leader 审批的 Script 实现类 - * 目前 Leader 的定义是, + * 分配给发起人的 Leader 审批的 Expression 流程表达式 + * 目前 Leader 的定义是,发起人所在部门的 Leader * * @author 芋道源码 */ -@Deprecated -public abstract class BpmTaskAssignLeaderAbstractScript implements BpmTaskAssignScript { +@Component +public class BpmTaskAssignLeaderExpression { @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; + @Resource - @Lazy // 解决循环依赖 private BpmProcessInstanceService bpmProcessInstanceService; - protected Set calculateTaskCandidateUsers(DelegateExecution execution, int level) { + protected Set calculateUsers(DelegateExecution execution, int level) { Assert.isTrue(level > 0, "level 必须大于 0"); // 获得发起人 ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java similarity index 54% rename from yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java index 0329aec6a..c4d8811b4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignStartUserExpression.java @@ -1,41 +1,30 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +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 jakarta.annotation.Resource; import java.util.Set; /** - * 分配给发起人审批的 Script 实现类 + * 分配给发起人审批的 Expression 流程表达式 * * @author 芋道源码 */ -@Deprecated @Component -public class BpmTaskAssignStartUserScript implements BpmTaskAssignScript { +public class BpmTaskAssignStartUserExpression { @Resource - @Lazy // 解决循环依赖 private BpmProcessInstanceService bpmProcessInstanceService; - @Override - public Set calculateTaskCandidateUsers(DelegateExecution execution) { + public Set calculateUsers(DelegateExecution execution) { ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(execution.getProcessInstanceId()); Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); return SetUtils.asSet(startUserId); } - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.START_USER; - } - } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java new file mode 100644 index 000000000..485552f91 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +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 jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 部门的负责人 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateDeptLeaderStrategy implements BpmTaskCandidateStrategy { + + @Resource + private DeptApi deptApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.DEPT_LEADER; + } + + @Override + public void validateParam(String param) { + Set deptIds = StrUtils.splitToLongSet(param); + deptApi.validateDeptList(deptIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set deptIds = StrUtils.splitToLongSet(param); + List depts = deptApi.getDeptList(deptIds); + return convertSet(depts, DeptRespDTO::getLeaderUserId); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java new file mode 100644 index 000000000..f60b1cc8b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +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 cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 部门的成员 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateDeptMemberStrategy implements BpmTaskCandidateStrategy { + + @Resource + private DeptApi deptApi; + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.DEPT_MEMBER; + } + + @Override + public void validateParam(String param) { + Set deptIds = StrUtils.splitToLongSet(param); + deptApi.validateDeptList(deptIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set deptIds = StrUtils.splitToLongSet(param); + List users = adminUserApi.getUserListByDeptIds(deptIds); + return convertSet(users, AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java new file mode 100644 index 000000000..f8be5fe3e --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategy.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; +import org.dromara.hutool.core.convert.Convert; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 流程表达式 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author 芋道源码 + */ +@Component +public class BpmTaskCandidateExpressionStrategy implements BpmTaskCandidateStrategy { + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.EXPRESSION; + } + + @Override + public void validateParam(String param) { + // do nothing 因为它基本做不了校验 + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Object result = FlowableUtils.getExpressionValue(execution, param); + return Convert.toSet(Long.class, result); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java new file mode 100644 index 000000000..b8fa00f84 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java @@ -0,0 +1,47 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +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 jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap; + +/** + * 用户组 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateGroupStrategy implements BpmTaskCandidateStrategy { + + @Resource + private BpmUserGroupService userGroupService; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.USER_GROUP; + } + + @Override + public void validateParam(String param) { + Set groupIds = StrUtils.splitToLongSet(param); + userGroupService.getUserGroupList(groupIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set groupIds = StrUtils.splitToLongSet(param); + List groups = userGroupService.getUserGroupList(groupIds); + return convertSetByFlatMap(groups, BpmUserGroupDO::getMemberUserIds, Collection::stream); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java new file mode 100644 index 000000000..3f2ae58f1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +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.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.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * 岗位 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidatePostStrategy implements BpmTaskCandidateStrategy { + + @Resource + private PostApi postApi; + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.POST; + } + + @Override + public void validateParam(String param) { + Set postIds = StrUtils.splitToLongSet(param); + postApi.validPostList(postIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set postIds = StrUtils.splitToLongSet(param); + List users = adminUserApi.getUserListByPostIds(postIds); + return convertSet(users, AdminUserRespDTO::getId); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java new file mode 100644 index 000000000..0dd178626 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +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 jakarta.annotation.Resource; +import org.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 角色 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateRoleStrategy implements BpmTaskCandidateStrategy { + + @Resource + private RoleApi roleApi; + @Resource + private PermissionApi permissionApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.ROLE; + } + + @Override + public void validateParam(String param) { + Set roleIds = StrUtils.splitToLongSet(param); + roleApi.validRoleList(roleIds); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + Set roleIds = StrUtils.splitToLongSet(param); + return permissionApi.getUserRoleIdListByRoleIds(roleIds); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java new file mode 100644 index 000000000..390e4903a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +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.flowable.engine.delegate.DelegateExecution; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * 用户 {@link BpmTaskCandidateStrategy} 实现类 + * + * @author kyle + */ +@Component +public class BpmTaskCandidateUserStrategy implements BpmTaskCandidateStrategy { + + @Resource + private AdminUserApi adminUserApi; + + @Override + public BpmTaskCandidateStrategyEnum getStrategy() { + return BpmTaskCandidateStrategyEnum.USER; + } + + @Override + public void validateParam(String param) { + adminUserApi.validateUserList(StrUtils.splitToLongSet(param)); + } + + @Override + public Set calculateUsers(DelegateExecution execution, String param) { + return StrUtils.splitToLongSet(param); + } + +} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java new file mode 100644 index 000000000..0c3199821 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +import cn.hutool.core.util.ArrayUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * BPM 任务的候选人策略枚举 + * + * 例如说:分配给指定人审批 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum BpmTaskCandidateStrategyEnum { + + ROLE(10, "角色"), + DEPT_MEMBER(20, "部门的成员"), // 包括负责人 + DEPT_LEADER(21, "部门的负责人"), + POST(22, "岗位"), + USER(30, "用户"), + USER_GROUP(40, "用户组"), + EXPRESSION(60, "流程表达式"), // 表达式 ExpressionManager + ; + + /** + * 类型 + */ + private final Integer strategy; + /** + * 描述 + */ + private final String description; + + public static BpmTaskCandidateStrategyEnum valueOf(Integer strategy) { + return ArrayUtil.firstMatch(o -> o.getStrategy().equals(strategy), values()); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java new file mode 100644 index 000000000..c8fefd55b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.enums; + +/** + * 流程常量信息 + */ +public interface BpmnModelConstants { + + String BPMN_FILE_SUFFIX = ".bpmn"; + + /** + * BPMN 中的命名空间 + */ + String NAMESPACE = "http://flowable.org/bpmn"; + + /** + * BPMN UserTask 的扩展属性,用于标记候选人策略 + */ + String USER_TASK_CANDIDATE_STRATEGY = "candidateStrategy"; + /** + * BPMN UserTask 的扩展属性,用于标记候选人参数 + */ + String USER_TASK_CANDIDATE_PARAM = "candidateParam"; + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java deleted file mode 100644 index 0c5f099d6..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java +++ /dev/null @@ -1,45 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate; - -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.HashSet; -import java.util.Set; - -/** - * 获取候选人信息 - */ -@AllArgsConstructor -@NoArgsConstructor -@Data -public class BpmCandidateSourceInfo { - @Schema(description = "当前任务ID") - @NotNull - private String taskId; - /** - * 通过这些规则,生成最终需要生成的用户 - */ - @Schema(description = "当前任务预选规则") - @NotEmpty(message = "不允许空规则") - private Set rules; - - @Schema(description = "发起抄送的用户") - private String creator; - - @Schema(description = "抄送原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "请帮忙审查下!") - @NotEmpty(message = "抄送原因不能为空") - private String reason; - - public void addRule(BpmTaskCandidateRuleVO vo) { - assert vo != null; - if (rules == null) { - rules = new HashSet<>(); - } - rules.add(vo); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessor.java deleted file mode 100644 index 0fe741c20..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessor.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import org.flowable.engine.delegate.DelegateExecution; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -public interface BpmCandidateSourceInfoProcessor { - /** - * 获取该处理器支持的类型 - * 来自 {@link BpmTaskAssignRuleTypeEnum} - * - * @return - */ - Set getSupportedTypes(); - - /** - * 对规则和人员做校验 - * - * @param type 规则 - * @param options 人员id - */ - void validRuleOptions(Integer type, Set options); - - /** - * 默认的处理 - * 如果想去操作所有的规则,则可以覆盖此方法 - * - * @param request 原始请求 - * @param delegateExecution 审批过程中的对象 - * @return 必须包含的是用户ID,而不是其他的ID - * @throws Exception - */ - default Set process(BpmCandidateSourceInfo request, DelegateExecution delegateExecution) throws Exception { - Set rules = request.getRules(); - Set results = new HashSet<>(); - for (BpmTaskCandidateRuleVO rule : rules) { - // 每个处理器都有机会处理自己支持的事件 - if (CollUtil.contains(getSupportedTypes(), rule.getType())) { - results.addAll(doProcess(request, rule, delegateExecution)); - } - } - return results; - } - - default Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - return Collections.emptySet(); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChain.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChain.java deleted file mode 100644 index dafc0835a..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChain.java +++ /dev/null @@ -1,107 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import java.util.*; - -@Service -public class BpmCandidateSourceInfoProcessorChain { - - // 保存处理节点 - - private List processorList; - @Resource - private AdminUserApi adminUserApi; - - /** - * 可添加其他处理器 - * - * @param processorOp - * @return - */ - @Resource - // 动态扩展处理节点 - public BpmCandidateSourceInfoProcessorChain addProcessor(ObjectProvider processorOp) { - List processor = ListUtil.toList(processorOp.iterator()); - if (null == processorList) { - processorList = new ArrayList<>(processor.size()); - } - processorList.addAll(processor); - return this; - } - - // 获取处理器处理 - public Set process(BpmCandidateSourceInfo sourceInfo, DelegateExecution execution) throws Exception { - // Verify our parameters - if (sourceInfo == null) { - throw new IllegalArgumentException(); - } - for (BpmCandidateSourceInfoProcessor processor : processorList) { - try { - for (BpmTaskCandidateRuleVO vo : sourceInfo.getRules()) { - if (CollUtil.contains(processor.getSupportedTypes(), vo.getType())) { - processor.validRuleOptions(vo.getType(), vo.getOptions()); - } - } - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - } - Set saveResult = Collections.emptySet(); - Exception saveException = null; - for (BpmCandidateSourceInfoProcessor processor : processorList) { - try { - saveResult = processor.process(sourceInfo, execution); - if (CollUtil.isNotEmpty(saveResult)) { - removeDisableUsers(saveResult); - break; - } - } catch (Exception e) { - saveException = e; - break; - } - } - // Return the exception or result state from the last execute() - if ((saveException != null)) { - throw saveException; - } else { - return (saveResult); - } - } - - public Set calculateTaskCandidateUsers(DelegateExecution execution, BpmCandidateSourceInfo sourceInfo) { - Set results = Collections.emptySet(); - try { - results = process(sourceInfo, execution); - } catch (Exception e) { - e.printStackTrace(); - } - return results; - } - - /** - * 移除禁用用户 - * - * @param assigneeUserIds - */ - public void removeDisableUsers(Set assigneeUserIds) { - if (CollUtil.isEmpty(assigneeUserIds)) { - return; - } - Map userMap = adminUserApi.getUserMap(assigneeUserIds); - assigneeUserIds.removeIf(id -> { - AdminUserRespDTO user = userMap.get(id); - return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); - }); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateAdminUserApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateAdminUserApiSourceInfoProcessor.java deleted file mode 100644 index 536b3eec2..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateAdminUserApiSourceInfoProcessor.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.system.api.user.AdminUserApi; -import org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.Set; - -public class BpmCandidateAdminUserApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private AdminUserApi api; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.USER.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validateUserList(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - return rule.getOptions(); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateDeptApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateDeptApiSourceInfoProcessor.java deleted file mode 100644 index 6fcfa23fd..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateDeptApiSourceInfoProcessor.java +++ /dev/null @@ -1,50 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -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.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - -public class BpmCandidateDeptApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private DeptApi api; - @Resource - private AdminUserApi adminUserApi; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), - BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validateDeptList(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), rule.getType())) { - List users = adminUserApi.getUserListByDeptIds(rule.getOptions()); - return convertSet(users, AdminUserRespDTO::getId); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), rule.getType())) { - List depts = api.getDeptList(rule.getOptions()); - return convertSet(depts, DeptRespDTO::getLeaderUserId); - } - return Collections.emptySet(); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidatePostApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidatePostApiSourceInfoProcessor.java deleted file mode 100644 index f924d87ef..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidatePostApiSourceInfoProcessor.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -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 org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.List; -import java.util.Set; - -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; - -public class BpmCandidatePostApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private PostApi api; - @Resource - private AdminUserApi adminUserApi; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.POST.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validPostList(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - List users = adminUserApi.getUserListByPostIds(rule.getOptions()); - return convertSet(users, AdminUserRespDTO::getId); - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateRoleApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateRoleApiSourceInfoProcessor.java deleted file mode 100644 index f3ba5b92b..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateRoleApiSourceInfoProcessor.java +++ /dev/null @@ -1,37 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; -import cn.iocoder.yudao.module.system.api.permission.RoleApi; -import org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.Set; - -public class BpmCandidateRoleApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private RoleApi api; - - @Resource - private PermissionApi permissionApi; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.ROLE.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validRoleList(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - return permissionApi.getUserRoleIdListByRoleIds(rule.getOptions()); - } - -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateScriptApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateScriptApiSourceInfoProcessor.java deleted file mode 100644 index 4bf25694d..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateScriptApiSourceInfoProcessor.java +++ /dev/null @@ -1,73 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.hutool.core.collection.CollUtil; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.system.api.dict.DictDataApi; -import org.flowable.engine.delegate.DelegateExecution; -import org.springframework.beans.factory.ObjectProvider; - -import jakarta.annotation.Resource; -import java.util.*; -import java.util.stream.Collectors; - -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.module.bpm.enums.ErrorCodeConstants.TASK_ASSIGN_SCRIPT_NOT_EXISTS; - -public class BpmCandidateScriptApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private DictDataApi dictDataApi; - - /** - * 任务分配脚本 - */ - private Map scriptMap = Collections.emptyMap(); - - public void setScripts(ObjectProvider scriptsOp) { - List scripts = scriptsOp.orderedStream().collect(Collectors.toList()); - setScripts(scripts); - } - - public void setScripts(List scripts) { - this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); - } - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT, - CollectionUtils.convertSet(options, String::valueOf)); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - return calculateTaskCandidateUsersByScript(delegateExecution, rule.getOptions()); - } - - private Set calculateTaskCandidateUsersByScript(DelegateExecution execution, Set options) { - // 获得对应的脚本 - List scripts = new ArrayList<>(options.size()); - options.forEach(id -> { - BpmTaskAssignScript script = scriptMap.get(id); - if (script == null) { - throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id); - } - scripts.add(script); - }); - // 逐个计算任务 - Set userIds = new HashSet<>(); - scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(execution))); - return userIds; - } -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateUserGroupApiSourceInfoProcessor.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateUserGroupApiSourceInfoProcessor.java deleted file mode 100644 index b0720b0d5..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/sourceInfoProcessor/BpmCandidateUserGroupApiSourceInfoProcessor.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor; - -import cn.iocoder.yudao.framework.common.util.collection.SetUtils; -import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessor; -import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; -import org.flowable.engine.delegate.DelegateExecution; - -import jakarta.annotation.Resource; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -public class BpmCandidateUserGroupApiSourceInfoProcessor implements BpmCandidateSourceInfoProcessor { - @Resource - private BpmUserGroupService api; - @Resource - private BpmUserGroupService userGroupService; - - @Override - public Set getSupportedTypes() { - return SetUtils.asSet(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType()); - } - - @Override - public void validRuleOptions(Integer type, Set options) { - api.validUserGroups(options); - } - - @Override - public Set doProcess(BpmCandidateSourceInfo request, BpmTaskCandidateRuleVO rule, DelegateExecution delegateExecution) { - List userGroups = userGroupService.getUserGroupList(rule.getOptions()); - Set userIds = new HashSet<>(); - userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); - return userIds; - } - -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java index 00ba49de4..729e176b0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*; import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO; import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO; import jakarta.annotation.Resource; @@ -54,8 +55,9 @@ public class BpmModelServiceImpl implements BpmModelService { private BpmProcessDefinitionService processDefinitionService; @Resource private BpmFormService bpmFormService; + @Resource - private BpmTaskAssignRuleService taskAssignRuleService; + private BpmTaskCandidateInvoker taskCandidateInvoker; @Override public PageResult getModelPage(BpmModelPageReqVO pageVO) { @@ -166,7 +168,7 @@ public class BpmModelServiceImpl implements BpmModelService { // 1.3 校验表单已配 BpmFormDO form = checkFormConfig(model.getMetaInfo()); // 1.4 校验任务分配规则已配置 - taskAssignRuleService.checkTaskAssignRuleAllConfig(bpmnBytes); + taskCandidateInvoker.validateBpmnConfig(bpmnBytes); // 1.5 校验模型是否发生修改。如果未修改,则不允许创建 BpmProcessDefinitionCreateReqDTO definitionCreateReqDTO = BpmModelConvert.INSTANCE.convert2(model, form) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java index dd5f035a9..82f15beec 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java @@ -5,7 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.PageUtils; -import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java deleted file mode 100644 index 012141adf..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleService.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.definition; - -import org.flowable.engine.delegate.DelegateExecution; - -import java.util.Set; - -/** - * BPM 任务分配规则 Service 接口 - * - * @author 芋道源码 - */ -public interface BpmTaskAssignRuleService { - - /** - * 校验流程模型的任务分配规则全部都配置了 - * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去! - * - * @param bpmnBytes BPMN XML - */ - void checkTaskAssignRuleAllConfig(byte[] bpmnBytes); - - /** - * 计算当前执行任务的处理人 - * - * @param execution 执行任务 - * @return 处理人的编号数组 - */ - Set calculateTaskCandidateUsers(DelegateExecution execution); - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java deleted file mode 100644 index a1474afd0..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java +++ /dev/null @@ -1,254 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.definition; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.util.ObjectUtil; -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.number.NumberUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.common.util.string.StrUtils; -import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; -import cn.iocoder.yudao.framework.flowable.core.enums.BpmnModelConstants; -import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils; -import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.enums.DictTypeConstants; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -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.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.permission.PermissionApi; -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.dto.AdminUserRespDTO; -import com.google.common.annotations.VisibleForTesting; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.dromara.hutool.core.convert.Convert; -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.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.*; -import java.util.function.Function; - -import static cn.hutool.core.text.CharSequenceUtil.format; -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.module.bpm.enums.ErrorCodeConstants.*; - -/** - * BPM 任务分配规则 Service 实现类 - */ -@Service -@Validated -@Slf4j -public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService { - - @Resource - private BpmUserGroupService userGroupService; - @Resource - @Lazy // 解决循环依赖 - private BpmProcessInstanceService processInstanceService; - -// @Resource -// private ExpressionManager expressionManager; - - @Resource - private RoleApi roleApi; - @Resource - private DeptApi deptApi; - @Resource - private PostApi postApi; - @Resource - private AdminUserApi adminUserApi; - @Resource - private DictDataApi dictDataApi; - @Resource - private PermissionApi permissionApi; - - /** - * 任务分配脚本 - */ - private Map scriptMap = Collections.emptyMap(); - - @Resource - public void setScripts(List scripts) { - this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); - } - - @Override - public void checkTaskAssignRuleAllConfig(byte[] bpmnBytes) { - BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes); - assert bpmnModel != null; - List userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class); - // 遍历所有的 UserTask,校验审批人配置 - userTaskList.forEach(userTask -> { - // TODO 芋艿:assignType/assignOptions/, 枚举 - Integer type = NumberUtils.parseInt(userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType")); - String options = userTask.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"); - if (type == null || StrUtil.isBlank(options)) { - throw exception(MODEL_DEPLOY_FAIL_TASK_ASSIGN_RULE_NOT_CONFIG, userTask.getName()); - } - // TODO 芋艿:校验 options - if (ObjectUtil.equal(type, BpmTaskAssignRuleTypeEnum.EXPRESS.getType())) { - return; - } - validTaskAssignRuleOptions(type, StrUtils.splitToLong(options, ",")); - }); - } - - private void validTaskAssignRuleOptions(Integer type, Collection options) { - if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.ROLE.getType())) { - roleApi.validRoleList(options); - } else if (ObjectUtils.equalsAny(type, BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), - BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType())) { - deptApi.validateDeptList(options); - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.POST.getType())) { - postApi.validPostList(options); - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER.getType())) { - adminUserApi.validateUserList(options); - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.USER_GROUP.getType())) { - userGroupService.validUserGroups(options); - } else if (Objects.equals(type, BpmTaskAssignRuleTypeEnum.SCRIPT.getType())) { - dictDataApi.validateDictDataList(DictTypeConstants.TASK_ASSIGN_SCRIPT, - CollectionUtils.convertSet(options, String::valueOf)); - } else { - throw new IllegalArgumentException(format("未知的规则类型({})", type)); - } - } - - public Long test(DelegateExecution execution) { - return 1L; - } - - public Long test2(DelegateExecution execution, Long id) { - return id; - } - - @Override - @DataPermission(enable = false) // 忽略数据权限,不然分配会存在问题 - public Set calculateTaskCandidateUsers(DelegateExecution execution) { - // 1. 先从提前选好的审批人中获取 - List assignee = processInstanceService.getAssigneeByProcessInstanceIdAndTaskDefinitionKey( - execution.getProcessInstanceId(), execution.getCurrentActivityId()); - if (CollUtil.isNotEmpty(assignee)) { - // TODO @hai:new HashSet 即可 - return convertSet(assignee, Function.identity()); - } - // 2. 通过分配规则,计算审批人 - return calculateTaskCandidateUsers0(execution); - } - - @VisibleForTesting - Set calculateTaskCandidateUsers0(DelegateExecution execution) { - // 获得审批人配置 - // TODO 芋艿:assignType/assignOptions/, 枚举 - FlowElement flowElement = execution.getCurrentFlowElement(); - Integer type = NumberUtils.parseInt(flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignType")); - String optionStr = flowElement.getAttributeValue(BpmnModelConstants.NAMESPACE, "assignOptions"); - Set options = null; - if (ObjectUtil.notEqual(BpmTaskAssignRuleTypeEnum.EXPRESS.getType(), type)) { - options = StrUtils.splitToLongSet(optionStr, ","); - } - - // 计算审批人 - Set assigneeUserIds = null; - if (Objects.equals(BpmTaskAssignRuleTypeEnum.ROLE.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByRole(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByDeptMember(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.DEPT_LEADER.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByDeptLeader(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.POST.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByPost(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByUser(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByUserGroup(options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), type)) { - assigneeUserIds = calculateTaskCandidateUsersByScript(execution, options); - } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.EXPRESS.getType(), type)) { - Object result = FlowableUtils.getExpressionValue(execution, optionStr); - assigneeUserIds = Convert.toSet(Long.class, result); - } - - // 移除被禁用的用户 - removeDisableUsers(assigneeUserIds); - // 如果候选人为空,抛出异常 - if (CollUtil.isEmpty(assigneeUserIds)) { - log.error("[calculateTaskCandidateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(), - execution.getProcessDefinitionId(), execution.getCurrentActivityId(), type, options); - throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER); - } - return assigneeUserIds; - } - - private Set calculateTaskCandidateUsersByRole(Set roleIds) { - return permissionApi.getUserRoleIdListByRoleIds(roleIds); - } - - private Set calculateTaskCandidateUsersByDeptMember(Set deptIds) { - List users = adminUserApi.getUserListByDeptIds(deptIds); - return convertSet(users, AdminUserRespDTO::getId); - } - - private Set calculateTaskCandidateUsersByDeptLeader(Set deptIds) { - List depts = deptApi.getDeptList(deptIds); - return convertSet(depts, DeptRespDTO::getLeaderUserId); - } - - private Set calculateTaskCandidateUsersByPost(Set postIds) { - List users = adminUserApi.getUserListByPostIds(postIds); - return convertSet(users, AdminUserRespDTO::getId); - } - - private Set calculateTaskCandidateUsersByUser(Set userIds) { - return userIds; - } - - private Set calculateTaskCandidateUsersByUserGroup(Set groupIds) { - List userGroups = userGroupService.getUserGroupList(groupIds); - Set userIds = new HashSet<>(); - userGroups.forEach(group -> userIds.addAll(group.getMemberUserIds())); - return userIds; - } - - private Set calculateTaskCandidateUsersByScript(DelegateExecution execution, Set scriptIds) { - // 获得对应的脚本 - List scripts = new ArrayList<>(scriptIds.size()); - scriptIds.forEach(scriptId -> { - BpmTaskAssignScript script = scriptMap.get(scriptId); - if (script == null) { - throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, scriptId); - } - scripts.add(script); - }); - // 逐个计算任务 - Set userIds = new HashSet<>(); - scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(execution))); - return userIds; - } - - @VisibleForTesting - void removeDisableUsers(Set assigneeUserIds) { - if (CollUtil.isEmpty(assigneeUserIds)) { - return; - } - Map userMap = adminUserApi.getUserMap(assigneeUserIds); - assigneeUserIds.removeIf(id -> { - AdminUserRespDTO user = userMap.get(id); - return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus()); - }); - } - -} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java index 208749a57..4d1db2958 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java @@ -4,7 +4,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; /** * 流程抄送 Service 接口 @@ -13,14 +12,6 @@ import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; */ public interface BpmProcessInstanceCopyService { - // TODO 芋艿:这块要 review 下;思考下~~ - /** - * 抄送 - * @param sourceInfo 抄送源信息,方便抄送处理 - * @return - */ - boolean makeCopy(BpmCandidateSourceInfo sourceInfo); - /** * 流程实例的抄送 * diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java index 50d042cdc..d800d1932 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java @@ -1,35 +1,22 @@ package cn.iocoder.yudao.module.bpm.service.task.cc; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO; import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper; import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo; -import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessorChain; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; -import cn.iocoder.yudao.module.bpm.service.task.cc.dto.BpmDelegateExecutionDTO; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; -import org.flowable.engine.RuntimeService; -import org.flowable.engine.delegate.DelegateExecution; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** @@ -45,12 +32,6 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy @Resource private BpmProcessInstanceCopyMapper processInstanceCopyMapper; - @Resource - private RuntimeService runtimeService; - - @Resource - private BpmCandidateSourceInfoProcessorChain processorChain; - @Resource @Lazy private BpmTaskService bpmTaskService; @@ -58,55 +39,6 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy @Lazy private BpmProcessInstanceService bpmProcessInstanceService; - @Override - public boolean makeCopy(BpmCandidateSourceInfo sourceInfo) { - if (null == sourceInfo) { - return false; - } - - Task task = bpmTaskService.getTask(sourceInfo.getTaskId()); - if (ObjectUtil.isNull(task)) { - return false; - } - String processInstanceId = task.getProcessInstanceId(); - if (StrUtil.isBlank(processInstanceId)) { - return false; - } - DelegateExecution executionEntity = new BpmDelegateExecutionDTO(processInstanceId); - Set ccCandidates = processorChain.calculateTaskCandidateUsers(executionEntity, sourceInfo); - if (CollUtil.isEmpty(ccCandidates)) { - log.warn("相关抄送人不存在 {}", sourceInfo.getTaskId()); - return false; - } else { - BpmProcessInstanceCopyDO copyDO = new BpmProcessInstanceCopyDO(); - // 调用 - // 设置任务id - copyDO.setTaskId(sourceInfo.getTaskId()); - copyDO.setTaskName(task.getName()); - copyDO.setProcessInstanceId(processInstanceId); - ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() - .processInstanceId(processInstanceId) - .singleResult(); - if (null == processInstance) { - log.warn("相关流程实例不存在 {}", sourceInfo.getTaskId()); - return false; - } - copyDO.setStartUserId(Long.parseLong(processInstance.getStartUserId())); - copyDO.setProcessInstanceName(processInstance.getName()); - copyDO.setCategory(processInstance.getProcessDefinitionCategory()); - copyDO.setReason(sourceInfo.getReason()); - copyDO.setCreator(sourceInfo.getCreator()); - copyDO.setCreateTime(LocalDateTime.now()); - List copyList = new ArrayList<>(ccCandidates.size()); - for (Long userId : ccCandidates) { - BpmProcessInstanceCopyDO copy = BeanUtil.copyProperties(copyDO, BpmProcessInstanceCopyDO.class); - copy.setUserId(userId); - copyList.add(copy); - } - return processInstanceCopyMapper.insertBatch(copyList); - } - } - @Override public void createProcessInstanceCopy(Long userId, BpmProcessInstanceCopyCreateReqVO reqVO) { // 1.1 校验任务存在 diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java new file mode 100644 index 000000000..702dce3f1 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvokerTest.java @@ -0,0 +1,93 @@ +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.enums.BpmTaskCandidateStrategyEnum; +import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.delegate.DelegateExecution; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; + +import java.util.Collections; +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 org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * {@link BpmTaskCandidateInvoker} 的单元测试 + * + * @author 芋道源码 + */ +public class BpmTaskCandidateInvokerTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateInvoker taskCandidateInvoker; + + @Mock + private AdminUserApi adminUserApi; + @Spy + private BpmTaskCandidateStrategy strategy = new BpmTaskCandidateUserStrategy(); + @Spy + private List strategyList = Collections.singletonList(strategy); + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + DelegateExecution execution = mock(DelegateExecution.class); + // mock 方法(DelegateExecution) + UserTask userTask = mock(UserTask.class); + when(execution.getCurrentFlowElement()).thenReturn(userTask); + when(userTask.getAttributeValue(eq(BpmnModelConstants.NAMESPACE), eq(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY))) + .thenReturn(BpmTaskCandidateStrategyEnum.USER.getStrategy().toString()); + when(userTask.getAttributeValue(eq(BpmnModelConstants.NAMESPACE), eq(BpmnModelConstants.USER_TASK_CANDIDATE_PARAM))) + .thenReturn(param); + // mock 方法(adminUserApi) + AdminUserRespDTO user1 = randomPojo(AdminUserRespDTO.class, o -> o.setId(1L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + AdminUserRespDTO user2 = randomPojo(AdminUserRespDTO.class, o -> o.setId(2L) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + Map userMap = MapUtil.builder(user1.getId(), user1) + .put(user2.getId(), user2).build(); + when(adminUserApi.getUserMap(eq(asSet(1L, 2L)))).thenReturn(userMap); + + // 调用 + Set results = taskCandidateInvoker.calculateUsers(execution); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + + @Test + public void testRemoveDisableUsers() { + // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 + Set 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 userMap = MapUtil.builder(user1.getId(), user1) + .put(user2.getId(), user2).build(); + when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); + + // 调用 + taskCandidateInvoker.removeDisableUsers(assigneeUserIds); + // 断言 + assertEquals(asSet(1L), assigneeUserIds); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java similarity index 86% rename from yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java rename to yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java index f46278083..b9a77ca79 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2ScriptTest.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/expression/BpmTaskAssignLeaderExpressionTest.java @@ -1,4 +1,4 @@ -package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.expression; import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; @@ -21,10 +21,10 @@ 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 { +public class BpmTaskAssignLeaderExpressionTest extends BaseMockitoUnitTest { @InjectMocks - private BpmTaskAssignLeaderX2Script script; + private BpmTaskAssignLeaderExpression expression; @Mock private AdminUserApi adminUserApi; @@ -34,7 +34,7 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { private BpmProcessInstanceService bpmProcessInstanceService; @Test - public void testCalculateTaskCandidateUsers_noDept() { + public void testCalculateUsers_noDept() { // 准备参数 DelegateExecution execution = mockDelegateExecution(1L); // mock 方法(startUser) @@ -44,13 +44,13 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { when(deptApi.getDept(eq(10L))).thenReturn(null); // 调用 - Set result = script.calculateTaskCandidateUsers(execution); + Set result = expression.calculateUsers(execution, 1); // 断言 assertEquals(0, result.size()); } @Test - public void testCalculateTaskCandidateUsers_noParentDept() { + public void testCalculateUsers_noParentDept() { // 准备参数 DelegateExecution execution = mockDelegateExecution(1L); // mock 方法(startUser) @@ -63,13 +63,13 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { when(deptApi.getDept(eq(100L))).thenReturn(null); // 调用 - Set result = script.calculateTaskCandidateUsers(execution); + Set result = expression.calculateUsers(execution, 2); // 断言 assertEquals(asSet(20L), result); } @Test - public void testCalculateTaskCandidateUsers_existParentDept() { + public void testCalculateUsers_existParentDept() { // 准备参数 DelegateExecution execution = mockDelegateExecution(1L); // mock 方法(startUser) @@ -84,7 +84,7 @@ public class BpmTaskAssignLeaderX2ScriptTest extends BaseMockitoUnitTest { when(deptApi.getDept(eq(100L))).thenReturn(parentDept); // 调用 - Set result = script.calculateTaskCandidateUsers(execution); + Set result = expression.calculateUsers(execution, 2); // 断言 assertEquals(asSet(200L), result); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java new file mode 100644 index 000000000..9b89e2bd3 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +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.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; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateDeptLeaderStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateDeptLeaderStrategy strategy; + + @Mock + private DeptApi deptApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // 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)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java new file mode 100644 index 000000000..4e72c0281 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; +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 org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateDeptMemberStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateDeptMemberStrategy strategy; + + @Mock + private AdminUserApi adminUserApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "11,22"; + // mock 方法 + List users = convertList(asSet(11L, 22L), + id -> new AdminUserRespDTO().setId(id)); + when(adminUserApi.getUserListByDeptIds(eq(asSet(11L, 22L)))).thenReturn(users); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java new file mode 100644 index 000000000..caa668eac --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateExpressionStrategyTest.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import org.flowable.engine.delegate.DelegateExecution; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.MockedStatic; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +public class BpmTaskCandidateExpressionStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateExpressionStrategy strategy; + + @Test + public void testCalculateUsers() { + try (MockedStatic flowableUtilMockedStatic = mockStatic(FlowableUtils.class)) { + // 准备参数 + String param = "1,2"; + DelegateExecution execution = mock(DelegateExecution.class); + // mock 方法 + flowableUtilMockedStatic.when(() -> FlowableUtils.getExpressionValue(same(execution), eq(param))) + .thenReturn(asSet(1L, 2L)); + + // 调用 + Set results = strategy.calculateUsers(execution, param); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java new file mode 100644 index 000000000..07958a51b --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategyTest.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; +import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Arrays; +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 BpmTaskCandidateGroupStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateGroupStrategy strategy; + + @Mock + private BpmUserGroupService userGroupService; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // 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(asSet(1L, 2L)))).thenReturn(Arrays.asList(userGroup1, userGroup2)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 12L, 21L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java new file mode 100644 index 000000000..a30ce28eb --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategyTest.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +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 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 org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidatePostStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidatePostStrategy strategy; + + @Mock + private PostApi postApi; + @Mock + private AdminUserApi adminUserApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + List users = convertList(asSet(11L, 22L), + id -> new AdminUserRespDTO().setId(id)); + when(adminUserApi.getUserListByPostIds(eq(asSet(1L, 2L)))).thenReturn(users); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java new file mode 100644 index 000000000..7c4247bcd --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategyTest.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.system.api.permission.PermissionApi; +import cn.iocoder.yudao.module.system.api.permission.RoleApi; +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 org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class BpmTaskCandidateRoleStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateRoleStrategy strategy; + + @Mock + private RoleApi roleApi; + @Mock + private PermissionApi permissionApi; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + // mock 方法 + when(permissionApi.getUserRoleIdListByRoleIds(eq(asSet(1L, 2L)))) + .thenReturn(asSet(11L, 22L)); + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(11L, 22L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java new file mode 100644 index 000000000..d71ccebfd --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategyTest.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy; + +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; + +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class BpmTaskCandidateUserStrategyTest extends BaseMockitoUnitTest { + + @InjectMocks + private BpmTaskCandidateUserStrategy strategy; + + @Test + public void testCalculateUsers() { + // 准备参数 + String param = "1,2"; + + // 调用 + Set results = strategy.calculateUsers(null, param); + // 断言 + assertEquals(asSet(1L, 2L), results); + } + +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChainTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChainTest.java deleted file mode 100644 index 29caf9ced..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfoProcessorChainTest.java +++ /dev/null @@ -1,244 +0,0 @@ -package cn.iocoder.yudao.module.bpm.service.candidate; - -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.controller.admin.candidate.vo.BpmTaskCandidateRuleVO; -import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignLeaderX1Script; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignLeaderX2Script; -import cn.iocoder.yudao.module.bpm.service.candidate.sourceInfoProcessor.BpmCandidateScriptApiSourceInfoProcessor; -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.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.permission.PermissionApi; -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.dto.AdminUserRespDTO; -import jakarta.annotation.Resource; -import org.flowable.engine.delegate.DelegateExecution; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -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; - -@Disabled // TODO 芋艿:临时禁用,暂时不修复,等重构后解决 -@Import({BpmCandidateSourceInfoProcessorChain.class, - BpmCandidateScriptApiSourceInfoProcessor.class, BpmTaskAssignLeaderX1Script.class, - BpmTaskAssignLeaderX2Script.class}) -public class BpmCandidateSourceInfoProcessorChainTest extends BaseDbUnitTest { - @Resource - private BpmCandidateSourceInfoProcessorChain processorChain; - - @MockBean - private BpmUserGroupService userGroupService; - @MockBean - private DeptApi deptApi; - @MockBean - private AdminUserApi adminUserApi; - @MockBean - private PermissionApi permissionApi; - @MockBean - private RoleApi roleApi; - @MockBean - private PostApi postApi; - @MockBean - private DictDataApi dictDataApi; - @Resource - private BpmCandidateScriptApiSourceInfoProcessor bpmCandidateScriptApiSourceInfoProcessor; - - @Test - public void testCalculateTaskCandidateUsers_Role() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.ROLE.getType()); - // mock 方法 - when(permissionApi.getUserRoleIdListByRoleIds(eq(rule.getOptions()))) - .thenReturn(asSet(11L, 22L)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_DeptMember() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.DEPT_MEMBER.getType()); - // mock 方法 - List users = CollectionUtils.convertList(asSet(11L, 22L), - id -> new AdminUserRespDTO().setId(id)); - when(adminUserApi.getUserListByDeptIds(eq(rule.getOptions()))).thenReturn(users); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_DeptLeader() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().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.getDeptList(eq(rule.getOptions()))).thenReturn(Arrays.asList(dept1, dept2)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_Post() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.POST.getType()); - // mock 方法 - List users = CollectionUtils.convertList(asSet(11L, 22L), - id -> new AdminUserRespDTO().setId(id)); - when(adminUserApi.getUserListByPostIds(eq(rule.getOptions()))).thenReturn(users); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_User() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(1L, 2L)) - .setType(BpmTaskAssignRuleTypeEnum.USER.getType()); - // mock 方法 - mockGetUserMap(asSet(1L, 2L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(1L, 2L), results); - } - - @Test - public void testCalculateTaskCandidateUsers_UserGroup() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().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)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 12L, 21L, 22L), results); - } - - private void mockGetUserMap(Set assigneeUserIds) { - Map userMap = CollectionUtils.convertMap(assigneeUserIds, id -> id, - id -> new AdminUserRespDTO().setId(id).setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); - } - - @Test - public void testCalculateTaskCandidateUsers_Script() { - // 准备参数 - BpmTaskCandidateRuleVO rule = new BpmTaskCandidateRuleVO().setOptions(asSet(20L, 21L)) - .setType(BpmTaskAssignRuleTypeEnum.SCRIPT.getType()); - // mock 方法 - BpmTaskAssignScript script1 = new BpmTaskAssignScript() { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution task) { - return singleton(11L); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X1; - } - }; - BpmTaskAssignScript script2 = new BpmTaskAssignScript() { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution task) { - return singleton(22L); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X2; - } - }; - bpmCandidateScriptApiSourceInfoProcessor.setScripts(Arrays.asList(script1, script2)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo(); - sourceInfo.addRule(rule); - Set results = processorChain.calculateTaskCandidateUsers(null, sourceInfo); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testRemoveDisableUsers() { - // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 - Set 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 userMap = MapUtil.builder(user1.getId(), user1) - .put(user2.getId(), user2).build(); - when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); - - // 调用 - processorChain.removeDisableUsers(assigneeUserIds); - // 断言 - assertEquals(asSet(1L), assigneeUserIds); - } - -} \ No newline at end of file diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java b/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java deleted file mode 100644 index 2ca2ff914..000000000 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImplTest.java +++ /dev/null @@ -1,227 +0,0 @@ -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.enums.definition.BpmTaskAssignRuleTypeEnum; -import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; -import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl.BpmTaskAssignStartUserScript; -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.dto.DeptRespDTO; -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.user.AdminUserApi; -import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; -import org.flowable.engine.delegate.DelegateExecution; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.context.annotation.Import; - -import jakarta.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, BpmTaskAssignStartUserScript.class}) // Import 引入 BpmTaskAssignStartUserScript 目的是保证不报错 -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; - @MockBean - private RoleApi roleApi; - @MockBean - private PostApi postApi; - @MockBean - private DictDataApi dictDataApi; - - @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 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 users = CollectionUtils.convertList(asSet(11L, 22L), - id -> new AdminUserRespDTO().setId(id)); - when(adminUserApi.getUserListByDeptIds(eq(rule.getOptions()))).thenReturn(users); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set 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.getDeptList(eq(rule.getOptions()))).thenReturn(Arrays.asList(dept1, dept2)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set 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 users = CollectionUtils.convertList(asSet(11L, 22L), - id -> new AdminUserRespDTO().setId(id)); - when(adminUserApi.getUserListByPostIds(eq(rule.getOptions()))).thenReturn(users); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set 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 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 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 calculateTaskCandidateUsers(DelegateExecution task) { - return singleton(11L); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X1; - } - }; - BpmTaskAssignScript script2 = new BpmTaskAssignScript() { - - @Override - public Set calculateTaskCandidateUsers(DelegateExecution task) { - return singleton(22L); - } - - @Override - public BpmTaskRuleScriptEnum getEnum() { - return BpmTaskRuleScriptEnum.LEADER_X2; - } - }; - bpmTaskRuleService.setScripts(Arrays.asList(script1, script2)); - mockGetUserMap(asSet(11L, 22L)); - - // 调用 - Set results = bpmTaskRuleService.calculateTaskCandidateUsers(null, rule); - // 断言 - assertEquals(asSet(11L, 22L), results); - } - - @Test - public void testRemoveDisableUsers() { - // 准备参数. 1L 可以找到;2L 是禁用的;3L 找不到 - Set 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 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 assigneeUserIds) { - Map userMap = CollectionUtils.convertMap(assigneeUserIds, id -> id, - id -> new AdminUserRespDTO().setId(id).setStatus(CommonStatusEnum.ENABLE.getStatus())); - when(adminUserApi.getUserMap(eq(assigneeUserIds))).thenReturn(userMap); - } - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java deleted file mode 100644 index f279e95df..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/enums/BpmnModelConstants.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core.enums; - -/** - * 流程常量信息 - */ -public interface BpmnModelConstants { - - String BPMN_FILE_SUFFIX = ".bpmn"; - - /** - * BPMN 中的命名空间 - * - * 这个东西有可能导致无法切换工作流程的实现 - */ - String NAMESPACE = "http://flowable.org/bpmn"; - -} diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java deleted file mode 100644 index de8d6279d..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.framework.flowable.core; diff --git a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java b/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java deleted file mode 100644 index 324d3de0e..000000000 --- a/yudao-module-bpm/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package cn.iocoder.yudao.framework.flowable;