Commit 1ec94e5bbc1bb343ae9112684c466eb09e0926f5

Authored by jason
1 parent c87bea5a

仿钉钉流程设计- 新增会签时通过只需一人,拒绝需要所有人的处理

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 { @@ -52,6 +52,8 @@ public interface ErrorCodeConstants {
52 ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人"); 52 ErrorCode TASK_TRANSFER_FAIL_USER_REPEAT = new ErrorCode(1_009_005_013, "任务转办失败,转办人和当前审批人为同一人");
53 ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在"); 53 ErrorCode TASK_TRANSFER_FAIL_USER_NOT_EXISTS = new ErrorCode(1_009_005_014, "任务转办失败,转办人不存在");
54 ErrorCode TASK_RETURN_NOT_ASSIGN_TARGET_TASK_ID = new ErrorCode(1_009_005_015, "回退任务未指定目标任务编号"); 54 ErrorCode TASK_RETURN_NOT_ASSIGN_TARGET_TASK_ID = new ErrorCode(1_009_005_015, "回退任务未指定目标任务编号");
  55 + ErrorCode TASK_REJECT_HANDLER_TYPE_BY_REJECT_RATIO_ERROR = new ErrorCode(1_009_005_016, "按拒绝人数比例终止流程只能用于会签任务");
  56 +
55 ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); 57 ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!");
56 58
57 // ========== 动态表单模块 1-009-010-000 ========== 59 // ========== 动态表单模块 1-009-010-000 ==========
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 { @@ -16,8 +16,10 @@ public enum BpmApproveMethodEnum {
16 16
17 SINGLE_PERSON_APPROVE(1, "单人审批"), 17 SINGLE_PERSON_APPROVE(1, "单人审批"),
18 ALL_APPROVE(2, "多人会签(需所有审批人同意)"), // 会签 18 ALL_APPROVE(2, "多人会签(需所有审批人同意)"), // 会签
19 - ANY_OF_APPROVE(3, "多人或签(一名审批人同意即可)"), // 或签  
20 - SEQUENTIAL_APPROVE(4, "依次审批"); // 依次审批 19 + APPROVE_BY_RATIO(3, "多人会签(按比例投票)"),
  20 + ANY_APPROVE_ALL_REJECT(4, "多人会签(通过只需一人,拒绝需要全员)"), // 通过只需一人,拒绝需要全员
  21 + ANY_APPROVE(5, "多人或签(一名审批人通过即可)"), // 或签
  22 + SEQUENTIAL_APPROVE(6, "依次审批"); // 依次审批
21 23
22 /** 24 /**
23 * 审批方式 25 * 审批方式
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; @@ -13,8 +13,10 @@ import lombok.Getter;
13 @AllArgsConstructor 13 @AllArgsConstructor
14 public enum BpmUserTaskRejectHandlerType { 14 public enum BpmUserTaskRejectHandlerType {
15 15
16 - TERMINATION(1, "终止流程"),  
17 - RETURN_PRE_USER_TASK(2, "驳回到指定任务节点"); 16 + FINISH_PROCESS(1, "终止流程"),
  17 + RETURN_PRE_USER_TASK(2, "驳回到指定任务节点"),
  18 + FINISH_PROCESS_BY_REJECT_RATIO(3, "按拒绝人数比例终止流程"), // 用于会签
  19 + FINISH_TASK(4, "结束任务"); // 待实现,可能会用于意见分支
18 20
19 private final Integer type; 21 private final Integer type;
20 private final String name; 22 private final String name;
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 { @@ -474,7 +474,7 @@ public class SimpleModelUtils {
474 if (bpmApproveMethodEnum == BpmApproveMethodEnum.ALL_APPROVE) { 474 if (bpmApproveMethodEnum == BpmApproveMethodEnum.ALL_APPROVE) {
475 multiInstanceCharacteristics.setCompletionCondition(ALL_APPROVE_COMPLETE_EXPRESSION); 475 multiInstanceCharacteristics.setCompletionCondition(ALL_APPROVE_COMPLETE_EXPRESSION);
476 multiInstanceCharacteristics.setSequential(false); 476 multiInstanceCharacteristics.setSequential(false);
477 - } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_OF_APPROVE) { 477 + } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE) {
478 multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION); 478 multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION);
479 multiInstanceCharacteristics.setSequential(false); 479 multiInstanceCharacteristics.setSequential(false);
480 userTask.setLoopCharacteristics(multiInstanceCharacteristics); 480 userTask.setLoopCharacteristics(multiInstanceCharacteristics);
@@ -483,7 +483,12 @@ public class SimpleModelUtils { @@ -483,7 +483,12 @@ public class SimpleModelUtils {
483 multiInstanceCharacteristics.setSequential(true); 483 multiInstanceCharacteristics.setSequential(true);
484 multiInstanceCharacteristics.setLoopCardinality("1"); 484 multiInstanceCharacteristics.setLoopCardinality("1");
485 userTask.setLoopCharacteristics(multiInstanceCharacteristics); 485 userTask.setLoopCharacteristics(multiInstanceCharacteristics);
  486 + } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE_ALL_REJECT) {
  487 + // 这种情况。拒绝任务时候,不会终止或者完成任务 参见 BpmTaskService#rejectTask 方法
  488 + multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION);
  489 + multiInstanceCharacteristics.setSequential(false);
486 } 490 }
  491 + // TODO 会签(按比例投票 )
487 userTask.setLoopCharacteristics(multiInstanceCharacteristics); 492 userTask.setLoopCharacteristics(multiInstanceCharacteristics);
488 } 493 }
489 494
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; @@ -34,6 +34,7 @@ import org.flowable.engine.HistoryService;
34 import org.flowable.engine.ManagementService; 34 import org.flowable.engine.ManagementService;
35 import org.flowable.engine.RuntimeService; 35 import org.flowable.engine.RuntimeService;
36 import org.flowable.engine.TaskService; 36 import org.flowable.engine.TaskService;
  37 +import org.flowable.engine.runtime.Execution;
37 import org.flowable.engine.runtime.ProcessInstance; 38 import org.flowable.engine.runtime.ProcessInstance;
38 import org.flowable.task.api.DelegationState; 39 import org.flowable.task.api.DelegationState;
39 import org.flowable.task.api.Task; 40 import org.flowable.task.api.Task;
@@ -337,7 +338,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -337,7 +338,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
337 BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); 338 BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason()));
338 // 3.1 解析用户任务的拒绝处理类型 339 // 3.1 解析用户任务的拒绝处理类型
339 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); 340 BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
340 - FlowElement flowElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); 341 + UserTask flowElement = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
341 Integer rejectHandlerType = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_HANDLER_TYPE)); 342 Integer rejectHandlerType = NumberUtils.parseInt(BpmnModelUtils.parseExtensionElement(flowElement, USER_TASK_REJECT_HANDLER_TYPE));
342 BpmUserTaskRejectHandlerType userTaskRejectHandlerType = BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType); 343 BpmUserTaskRejectHandlerType userTaskRejectHandlerType = BpmUserTaskRejectHandlerType.typeOf(rejectHandlerType);
343 // 3.2 类型为驳回到指定的任务节点 344 // 3.2 类型为驳回到指定的任务节点
@@ -350,6 +351,30 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -350,6 +351,30 @@ public class BpmTaskServiceImpl implements BpmTaskService {
350 .setReason(reqVO.getReason()); 351 .setReason(reqVO.getReason());
351 returnTask(userId, returnReq); 352 returnTask(userId, returnReq);
352 return; 353 return;
  354 + } else if (userTaskRejectHandlerType == BpmUserTaskRejectHandlerType.FINISH_PROCESS_BY_REJECT_RATIO) {
  355 + // 3.3 按拒绝人数比例终止流程
  356 + if(!flowElement.hasMultiInstanceLoopCharacteristics()) {
  357 + throw exception(TASK_REJECT_HANDLER_TYPE_BY_REJECT_RATIO_ERROR);
  358 + }
  359 + Execution execution = runtimeService.createExecutionQuery().processInstanceId(task.getProcessInstanceId())
  360 + .executionId(task.getExecutionId()).singleResult();
  361 + // 获取并行任务总数
  362 + Integer nrOfInstances = runtimeService.getVariable(execution.getParentId(), "nrOfInstances", Integer.class);
  363 + // 获取未完成任务列表
  364 + List<Task> taskList = getAssignedTaskListByConditions(task.getProcessInstanceId(), null, task.getTaskDefinitionKey());
  365 + // 获取已经拒绝的任务数
  366 + int rejectNumber = 0;
  367 + for (Task item : taskList) {
  368 + if (Objects.equals(BpmTaskStatusEnum.REJECT.getStatus(), FlowableUtils.getTaskStatus(item))) {
  369 + rejectNumber ++;
  370 + }
  371 + }
  372 + // 拒绝任务后,任务分配人清空。但不能完成任务
  373 + taskService.setAssignee(task.getId(), "");
  374 + // 不是所有人拒绝返回。 TODO 后续需要做按拒绝人数比例来判断
  375 + if(!Objects.equals(nrOfInstances, rejectNumber)) {
  376 + return;
  377 + }
353 } 378 }
354 // 3.3 其他情况 终止流程。 TODO 后续可能会增加处理类型 379 // 3.3 其他情况 终止流程。 TODO 后续可能会增加处理类型
355 processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason()); 380 processInstanceService.updateProcessInstanceReject(instance.getProcessInstanceId(), reqVO.getReason());
@@ -431,8 +456,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -431,8 +456,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
431 return; 456 return;
432 } 457 }
433 ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); 458 ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
434 - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));  
435 - messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); 459 + if (processInstance != null) {
  460 + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
  461 + messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
  462 + }
436 } 463 }
437 464
438 }); 465 });