From ed8fc5f674544d3af63c6f68093ffc038385c493 Mon Sep 17 00:00:00 2001
From: dongyukun <1208714201@qq.com>
Date: 星期一, 16 十二月 2024 09:30:04 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java |  107 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 93 insertions(+), 14 deletions(-)

diff --git a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java
index d70f332..b1a364f 100644
--- a/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java
+++ b/iailab-module-bpm/iailab-module-bpm-biz/src/main/java/com/iailab/module/bpm/framework/flowable/core/candidate/BpmTaskCandidateInvoker.java
@@ -2,23 +2,28 @@
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.lang.Assert;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
 import com.iailab.framework.common.enums.CommonStatusEnum;
+import com.iailab.framework.common.util.object.ObjectUtils;
 import com.iailab.framework.datapermission.core.annotation.DataPermission;
+import com.iailab.module.bpm.enums.definition.BpmUserTaskApproveTypeEnum;
+import com.iailab.module.bpm.enums.definition.BpmUserTaskAssignStartUserHandlerTypeEnum;
 import com.iailab.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
 import com.iailab.module.bpm.framework.flowable.core.util.BpmnModelUtils;
+import com.iailab.module.bpm.service.task.BpmProcessInstanceService;
 import com.iailab.module.system.api.user.AdminUserApi;
 import com.iailab.module.system.api.user.dto.AdminUserRespDTO;
 import com.google.common.annotations.VisibleForTesting;
 import lombok.extern.slf4j.Slf4j;
 import org.flowable.bpmn.model.BpmnModel;
+import org.flowable.bpmn.model.FlowElement;
 import org.flowable.bpmn.model.UserTask;
 import org.flowable.engine.delegate.DelegateExecution;
+import org.flowable.engine.runtime.ProcessInstance;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static com.iailab.module.bpm.enums.ErrorCodeConstants.MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG;
@@ -57,7 +62,14 @@
         List<UserTask> userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class);
         // 遍历所有的 UserTask,校验审批人配置
         userTaskList.forEach(userTask -> {
-            // 1. 非空校验
+            // 1.1 非人工审批,无需校验审批人配置
+            Integer approveType = BpmnModelUtils.parseApproveType(userTask);
+            if (ObjectUtils.equalsAny(approveType,
+                    BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType(),
+                    BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
+                return;
+            }
+            // 1.2 非空校验
             Integer strategy = BpmnModelUtils.parseCandidateStrategy(userTask);
             String param = BpmnModelUtils.parseCandidateParam(userTask);
             if (strategy == null) {
@@ -79,20 +91,66 @@
      * @return 用户编号集合
      */
     @DataPermission(enable = false) // 忽略数据权限,避免因为过滤,导致找不到候选人
-    public Set<Long> calculateUsers(DelegateExecution execution) {
-        Integer strategy = BpmnModelUtils.parseCandidateStrategy(execution.getCurrentFlowElement());
-        String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
+    public Set<Long> calculateUsersByTask(DelegateExecution execution) {
+        // 审批类型非人工审核时,不进行计算候选人。原因是:后续会自动通过、不通过
+        FlowElement flowElement = execution.getCurrentFlowElement();
+        Integer approveType = BpmnModelUtils.parseApproveType(flowElement);
+        if (ObjectUtils.equalsAny(approveType,
+                BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType(),
+                BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
+            return new HashSet<>();
+        }
+
         // 1.1 计算任务的候选人
-        Set<Long> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
+        Integer strategy = BpmnModelUtils.parseCandidateStrategy(flowElement);
+        String param = BpmnModelUtils.parseCandidateParam(flowElement);
+        Set<Long> userIds = getCandidateStrategy(strategy).calculateUsersByTask(execution, param);
         // 1.2 移除被禁用的用户
         removeDisableUsers(userIds);
 
-        // 2. 校验是否有候选人
+        // 2. 候选人为空时,根据“审批人为空”的配置补充
         if (CollUtil.isEmpty(userIds)) {
-            log.error("[calculateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(),
-                    execution.getProcessDefinitionId(), execution.getCurrentActivityId(), strategy, param);
-            throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
+            userIds = getCandidateStrategy(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY.getStrategy())
+                    .calculateUsersByTask(execution, param);
+            // ASSIGN_EMPTY 策略,不需要移除被禁用的用户。原因是,再移除,可能会出现更没审批人了!!!
         }
+
+        // 3. 移除发起人的用户
+        ProcessInstance processInstance = SpringUtil.getBean(BpmProcessInstanceService.class)
+                .getProcessInstance(execution.getProcessInstanceId());
+        Assert.notNull(processInstance, "流程实例({}) 不存在", execution.getProcessInstanceId());
+        removeStartUserIfSkip(userIds, flowElement, Long.valueOf(processInstance.getStartUserId()));
+        return userIds;
+    }
+
+    public Set<Long> calculateUsersByActivity(BpmnModel bpmnModel, String activityId,
+                                              Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
+        // 审批类型非人工审核时,不进行计算候选人。原因是:后续会自动通过、不通过
+        FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
+        Integer approveType = BpmnModelUtils.parseApproveType(flowElement);
+        if (ObjectUtils.equalsAny(approveType,
+                BpmUserTaskApproveTypeEnum.AUTO_APPROVE.getType(),
+                BpmUserTaskApproveTypeEnum.AUTO_REJECT.getType())) {
+            return new HashSet<>();
+        }
+
+        // 1.1 计算任务的候选人
+        Integer strategy = BpmnModelUtils.parseCandidateStrategy(flowElement);
+        String param = BpmnModelUtils.parseCandidateParam(flowElement);
+        Set<Long> userIds = getCandidateStrategy(strategy).calculateUsersByActivity(bpmnModel, activityId, param,
+                startUserId, processDefinitionId, processVariables);
+        // 1.2 移除被禁用的用户
+        removeDisableUsers(userIds);
+
+        // 2. 候选人为空时,根据“审批人为空”的配置补充
+        if (CollUtil.isEmpty(userIds)) {
+            userIds = getCandidateStrategy(BpmTaskCandidateStrategyEnum.ASSIGN_EMPTY.getStrategy())
+                    .calculateUsersByActivity(bpmnModel, activityId, param, startUserId, processDefinitionId, processVariables);
+            // ASSIGN_EMPTY 策略,不需要移除被禁用的用户。原因是,再移除,可能会出现更没审批人了!!!
+        }
+
+        // 3. 移除发起人的用户
+        removeStartUserIfSkip(userIds, flowElement, startUserId);
         return userIds;
     }
 
@@ -104,10 +162,31 @@
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds);
         assigneeUserIds.removeIf(id -> {
             AdminUserRespDTO user = userMap.get(id);
-            return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
+            return user == null || CommonStatusEnum.isDisable(user.getStatus());
         });
     }
 
+    /**
+     * 如果“审批人与发起人相同时”,配置了 SKIP 跳过,则移除发起人
+     *
+     * 注意:如果只有一个候选人,则不处理,避免无法审批
+     *
+     * @param assigneeUserIds 当前分配的候选人
+     * @param flowElement 当前节点
+     * @param startUserId 发起人
+     */
+    @VisibleForTesting
+    void removeStartUserIfSkip(Set<Long> assigneeUserIds, FlowElement flowElement, Long startUserId) {
+        if (CollUtil.size(assigneeUserIds) <= 1) {
+            return;
+        }
+        Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(flowElement);
+        if (ObjectUtil.notEqual(assignStartUserHandlerType, BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP.getType())) {
+            return;
+        }
+        assigneeUserIds.remove(startUserId);
+    }
+
     private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
         BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy);
         Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy);

--
Gitblit v1.9.3