Commit 1ec94e5bbc1bb343ae9112684c466eb09e0926f5
1 parent
c87bea5a
仿钉钉流程设计- 新增会签时通过只需一人,拒绝需要所有人的处理
Showing
5 changed files
with
46 additions
and
8 deletions
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 | }); |