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 daa4d8616..3d1010462 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 @@ -52,6 +52,8 @@ public interface ErrorCodeConstants { ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); ErrorCode TASK_RETURN_NOT_ASSIGN_TARGET_TASK_ID = new ErrorCode(1_009_005_015, "回退任务未指定目标任务编号"); + ErrorCode TASK_REJECT_HANDLER_TYPE_BY_REJECT_RATIO_ERROR = new ErrorCode(1_009_005_016, "按拒绝人数比例终止流程只能用于会签任务"); + ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); // ========== 动态表单模块 1-009-010-000 ========== diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmApproveMethodEnum.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmApproveMethodEnum.java index 522ff45ea..8d8972bd8 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmApproveMethodEnum.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmApproveMethodEnum.java @@ -16,8 +16,10 @@ public enum BpmApproveMethodEnum { SINGLE_PERSON_APPROVE(1, "单人审批"), ALL_APPROVE(2, "多人会签(需所有审批人同意)"), // 会签 - ANY_OF_APPROVE(3, "多人或签(一名审批人同意即可)"), // 或签 - SEQUENTIAL_APPROVE(4, "依次审批"); // 依次审批 + APPROVE_BY_RATIO(3, "多人会签(按比例投票)"), + ANY_APPROVE_ALL_REJECT(4, "多人会签(通过只需一人,拒绝需要全员)"), // 通过只需一人,拒绝需要全员 + ANY_APPROVE(5, "多人或签(一名审批人通过即可)"), // 或签 + SEQUENTIAL_APPROVE(6, "依次审批"); // 依次审批 /** * 审批方式 diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java index 7a455f382..53bb2abc7 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java @@ -13,8 +13,10 @@ import lombok.Getter; @AllArgsConstructor public enum BpmUserTaskRejectHandlerType { - TERMINATION(1, "终止流程"), - RETURN_PRE_USER_TASK(2, "驳回到指定任务节点"); + FINISH_PROCESS(1, "终止流程"), + RETURN_PRE_USER_TASK(2, "驳回到指定任务节点"), + FINISH_PROCESS_BY_REJECT_RATIO(3, "按拒绝人数比例终止流程"), // 用于会签 + FINISH_TASK(4, "结束任务"); // 待实现,可能会用于意见分支 private final Integer type; private final String name; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java index dcb829c16..7b2f2ef81 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java @@ -474,7 +474,7 @@ public class SimpleModelUtils { if (bpmApproveMethodEnum == BpmApproveMethodEnum.ALL_APPROVE) { multiInstanceCharacteristics.setCompletionCondition(ALL_APPROVE_COMPLETE_EXPRESSION); multiInstanceCharacteristics.setSequential(false); - } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_OF_APPROVE) { + } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE) { multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION); multiInstanceCharacteristics.setSequential(false); userTask.setLoopCharacteristics(multiInstanceCharacteristics); @@ -483,7 +483,12 @@ public class SimpleModelUtils { multiInstanceCharacteristics.setSequential(true); multiInstanceCharacteristics.setLoopCardinality("1"); userTask.setLoopCharacteristics(multiInstanceCharacteristics); + } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT) { + // 这种情况。拒绝任务时候,不会终止或者完成任务 参见 BpmTaskService#rejectTask 方法 + multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION); + multiInstanceCharacteristics.setSequential(false); } + // TODO 会签(按比例投票 ) userTask.setLoopCharacteristics(multiInstanceCharacteristics); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index c57232939..7047261d9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -34,6 +34,7 @@ import org.flowable.engine.HistoryService; import org.flowable.engine.ManagementService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; +import org.flowable.engine.runtime.Execution; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.DelegationState; import org.flowable.task.api.Task; @@ -337,7 +338,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); // 3.1 解析用户任务的拒绝处理类型 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); - FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); + UserTask flowElement = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); Integer rejectHandlerType = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_HANDLER_TYPE)); BpmUserTaskRejectHandlerType userTaskRejectHandlerType = BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType); // 3.2 类型为驳回到指定的任务节点 @@ -350,6 +351,30 @@ public class BpmTaskServiceImpl implements BpmTaskService { .setReason(reqVO.getReason()); returnTask(userId, returnReq); return; + } else if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.FINISH_PROCESS_BY_REJECT_RATIO) { + // 3.3 按拒绝人数比例终止流程 + if(!flowElement.hasMultiInstanceLoopCharacteristics()) { + throw exception(TASK_REJECT_HANDLER_TYPE_BY_REJECT_RATIO_ERROR); + } + Execution execution = runtimeService.createExecutionQuery().processInstanceId(task.getProcessInstanceId()) + .executionId(task.getExecutionId()).singleResult(); + // 获取并行任务总数 + Integer nrOfInstances = runtimeService.getVariable(execution.getParentId(), "nrOfInstances", Integer.class); + // 获取未完成任务列表 + List taskList = getAssignedTaskListByConditions(task.getProcessInstanceId(), null, task.getTaskDefinitionKey()); + // 获取已经拒绝的任务数 + int rejectNumber = 0; + for (Task item : taskList) { + if (Objects.equals(BpmTaskStatusEnum.REJECT.getStatus(), FlowableUtils.getTaskStatus(item))) { + rejectNumber ++; + } + } + // 拒绝任务后,任务分配人清空。但不能完成任务 + taskService.setAssignee(task.getId(), ""); + // 不是所有人拒绝返回。 TODO 后续需要做按拒绝人数比例来判断 + if(!Objects.equals(nrOfInstances, rejectNumber)) { + return; + } } // 3.3 其他情况 终止流程。 TODO 后续可能会增加处理类型 processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason()); @@ -431,8 +456,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); - messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); + if (processInstance != null) { + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); + messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); + } } });