Commit 1d463f4f1a359f4a91cc07772c39f68008a69b89
1 parent
91f356fc
fix: 修复回退报错问题, moveExecutionsToSingleActivityId 替换为 moveActivityIdsToSingleActivityId
Showing
2 changed files
with
98 additions
and
94 deletions
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
| ... | ... | @@ -66,8 +66,7 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { |
| 66 | 66 | |
| 67 | 67 | @Override |
| 68 | 68 | protected void taskAssigned(FlowableEngineEntityEvent event) { |
| 69 | - Task entity = (Task) event.getEntity(); | |
| 70 | - FlowableUtils.execute(entity.getTenantId(), () -> taskService.processTaskAssigned(entity)); | |
| 69 | + taskService.processTaskAssigned((Task) event.getEntity()); | |
| 71 | 70 | } |
| 72 | 71 | |
| 73 | 72 | @Override | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| ... | ... | @@ -917,7 +917,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 917 | 917 | * @param reqVO 前端参数封装 |
| 918 | 918 | */ |
| 919 | 919 | public void returnTask(Long userId, BpmnModel bpmnModel, Task currentTask, FlowElement targetElement, BpmTaskReturnReqVO reqVO) { |
| 920 | - // 1. 获得所有需要回撤的任务 taskDefinitionKey,用于稍后的 moveActivityIdsToSingleActivityId 回撤 | |
| 920 | + // 1. 获得所有需要回撤的任务 taskDefinitionKey,用于稍后的 moveExecutionsToSingleActivityId 回撤 | |
| 921 | 921 | // 1.1 获取所有正常进行的任务节点 Key |
| 922 | 922 | List<Task> taskList = taskService.createTaskQuery().processInstanceId(currentTask.getProcessInstanceId()).list(); |
| 923 | 923 | List<String> runTaskKeyList = convertList(taskList, Task::getTaskDefinitionKey); |
| ... | ... | @@ -925,14 +925,16 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 925 | 925 | // 为什么不直接使用 runTaskKeyList 呢?因为可能存在多个审批分支,例如说:A -> B -> C 和 D -> F,而只要 C 撤回到 A,需要排除掉 F |
| 926 | 926 | List<UserTask> returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null); |
| 927 | 927 | List<String> returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId); |
| 928 | - | |
| 928 | + List<String> runExecutionIds = new ArrayList<>(); | |
| 929 | 929 | // 2. 给当前要被退回的 task 数组,设置退回意见 |
| 930 | 930 | taskList.forEach(task -> { |
| 931 | 931 | // 需要排除掉,不需要设置退回意见的任务 |
| 932 | 932 | if (!returnTaskKeyList.contains(task.getTaskDefinitionKey())) { |
| 933 | 933 | return; |
| 934 | 934 | } |
| 935 | - | |
| 935 | + if (task.getExecutionId() != null) { | |
| 936 | + runExecutionIds.add(task.getExecutionId()); | |
| 937 | + } | |
| 936 | 938 | // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 |
| 937 | 939 | if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 |
| 938 | 940 | // 2.1.1 添加评论 |
| ... | ... | @@ -953,9 +955,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 953 | 955 | // 相关 issue: https://github.com/flowable/flowable-engine/issues/3944 |
| 954 | 956 | // ② flowable 7.2.0 版本后,继续使用 moveActivityIdsToSingleActivityId 方法。原因:flowable 7.2.0 版本修复了该问题。 |
| 955 | 957 | // 相关 issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/1018 |
| 958 | + // ③ moveActivityIdsToSingleActivityId 使用遇到问题, 相关 issue https://gitee.com/zhijiantianya/yudao-cloud/issues/IJM8MS | |
| 959 | + // 改成 moveExecutionsToSingleActivityId 好像并没有遇到 ② 提到的超时提醒失效的问题。暂时先改回 moveExecutionsToSingleActivityId | |
| 960 | + // 目前还有的相关问题 https://t.zsxq.com/z4d9i。 估计需要升级 flowable 8 版本试试 | |
| 956 | 961 | runtimeService.createChangeActivityStateBuilder() |
| 957 | 962 | .processInstanceId(currentTask.getProcessInstanceId()) |
| 958 | - .moveActivityIdsToSingleActivityId(returnTaskKeyList, reqVO.getTargetTaskDefinitionKey()) | |
| 963 | + .moveExecutionsToSingleActivityId(runExecutionIds, reqVO.getTargetTaskDefinitionKey()) | |
| 959 | 964 | // 设置需要预测的任务 ids 的流程变量,用于辅助预测 |
| 960 | 965 | .processVariable(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_NEED_SIMULATE_TASK_IDS, needSimulateTaskDefinitionKeys) |
| 961 | 966 | // 设置流程变量节点退回标记, 用于退回到节点,不执行 BpmUserTaskAssignStartUserHandlerTypeEnum 策略,导致自动通过 |
| ... | ... | @@ -1465,107 +1470,107 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 1465 | 1470 | log.error("[processTaskAssigned][taskId({}) 没有找到流程实例]", task.getId()); |
| 1466 | 1471 | return; |
| 1467 | 1472 | } |
| 1468 | - | |
| 1469 | - // 自动去重,通过自动审批的方式 | |
| 1470 | - BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService.getProcessDefinitionInfo(task.getProcessDefinitionId()); | |
| 1471 | - if (processDefinitionInfo == null) { | |
| 1472 | - log.error("[processTaskAssigned][taskId({}) 没有找到流程定义({})]", task.getId(), task.getProcessDefinitionId()); | |
| 1473 | - return; | |
| 1474 | - } | |
| 1475 | - if (processDefinitionInfo.getAutoApprovalType() != null) { | |
| 1476 | - HistoricTaskInstanceQuery sameAssigneeQuery = historyService.createHistoricTaskInstanceQuery() | |
| 1477 | - .processInstanceId(task.getProcessInstanceId()) | |
| 1478 | - .taskVariableValueEquals(BpmnVariableConstants.TASK_VARIABLE_STATUS, BpmTaskStatusEnum.APPROVE.getStatus()) | |
| 1479 | - .finished(); | |
| 1480 | - if (BpmAutoApproveTypeEnum.APPROVE_ALL.getType().equals(processDefinitionInfo.getAutoApprovalType()) | |
| 1481 | - && sameAssigneeQuery.taskAssignee(task.getAssignee()).count() > 0) { | |
| 1482 | - getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) | |
| 1483 | - .setReason(BpmAutoApproveTypeEnum.APPROVE_ALL.getName())); | |
| 1473 | + // 需要基于 instance 设置租户编号,避免 Flowable 内部异步执行时【例如:超时自动通过】 丢失租户编号 | |
| 1474 | + FlowableUtils.execute(processInstance.getTenantId(), () -> { | |
| 1475 | + // 自动去重,通过自动审批的方式 | |
| 1476 | + BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService.getProcessDefinitionInfo(task.getProcessDefinitionId()); | |
| 1477 | + if (processDefinitionInfo == null) { | |
| 1478 | + log.error("[processTaskAssigned][taskId({}) 没有找到流程定义({})]", task.getId(), task.getProcessDefinitionId()); | |
| 1484 | 1479 | return; |
| 1485 | 1480 | } |
| 1486 | - // 连续审批的节点自动通过 | |
| 1487 | - if (BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getType().equals(processDefinitionInfo.getAutoApprovalType())) { | |
| 1488 | - BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId()); | |
| 1489 | - if (bpmnModel == null) { | |
| 1490 | - log.error("[processTaskAssigned][taskId({}) 没有找到流程模型({})]", task.getId(), task.getProcessDefinitionId()); | |
| 1491 | - return; | |
| 1492 | - } | |
| 1493 | - List<String> sourceTaskIds = convertList(BpmnModelUtils.getElementIncomingUserTaskFlows( // 获取所有的上一个 UserTask 节点连线 | |
| 1494 | - BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey())), | |
| 1495 | - SequenceFlow::getSourceRef); | |
| 1496 | - // 设置 taskIds, 并按创建时间倒序排序 | |
| 1497 | - sameAssigneeQuery.taskDefinitionKeys(sourceTaskIds) | |
| 1498 | - .orderByTaskCreateTime() | |
| 1499 | - .desc(); | |
| 1500 | - HistoricTaskInstance firstHisTask = CollUtil.getFirst(sameAssigneeQuery.list()); | |
| 1501 | - if (firstHisTask != null && StrUtil.equals(firstHisTask.getAssignee(), task.getAssignee())) { | |
| 1481 | + if (processDefinitionInfo.getAutoApprovalType() != null) { | |
| 1482 | + HistoricTaskInstanceQuery sameAssigneeQuery = historyService.createHistoricTaskInstanceQuery() | |
| 1483 | + .processInstanceId(task.getProcessInstanceId()) | |
| 1484 | + .taskVariableValueEquals(BpmnVariableConstants.TASK_VARIABLE_STATUS, BpmTaskStatusEnum.APPROVE.getStatus()) | |
| 1485 | + .finished(); | |
| 1486 | + if (BpmAutoApproveTypeEnum.APPROVE_ALL.getType().equals(processDefinitionInfo.getAutoApprovalType()) | |
| 1487 | + && sameAssigneeQuery.taskAssignee(task.getAssignee()).count() > 0) { | |
| 1502 | 1488 | getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) |
| 1503 | - .setReason(BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getName())); | |
| 1489 | + .setReason(BpmAutoApproveTypeEnum.APPROVE_ALL.getName())); | |
| 1504 | 1490 | return; |
| 1505 | 1491 | } |
| 1492 | + // 连续审批的节点自动通过 | |
| 1493 | + if (BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getType().equals(processDefinitionInfo.getAutoApprovalType())) { | |
| 1494 | + BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId()); | |
| 1495 | + if (bpmnModel == null) { | |
| 1496 | + log.error("[processTaskAssigned][taskId({}) 没有找到流程模型({})]", task.getId(), task.getProcessDefinitionId()); | |
| 1497 | + return; | |
| 1498 | + } | |
| 1499 | + List<String> sourceTaskIds = convertList(BpmnModelUtils.getElementIncomingUserTaskFlows( // 获取所有的上一个 UserTask 节点连线 | |
| 1500 | + BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey())), | |
| 1501 | + SequenceFlow::getSourceRef); | |
| 1502 | + // 设置 taskIds, 并按创建时间倒序排序 | |
| 1503 | + sameAssigneeQuery.taskDefinitionKeys(sourceTaskIds) | |
| 1504 | + .orderByTaskCreateTime() | |
| 1505 | + .desc(); | |
| 1506 | + HistoricTaskInstance firstHisTask = CollUtil.getFirst(sameAssigneeQuery.list()); | |
| 1507 | + if (firstHisTask != null && StrUtil.equals(firstHisTask.getAssignee(), task.getAssignee())) { | |
| 1508 | + getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) | |
| 1509 | + .setReason(BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getName())); | |
| 1510 | + return; | |
| 1511 | + } | |
| 1512 | + } | |
| 1506 | 1513 | } |
| 1507 | - } | |
| 1508 | 1514 | |
| 1509 | - // 获取发起人节点 | |
| 1510 | - BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId()); | |
| 1511 | - if (bpmnModel == null) { | |
| 1512 | - log.error("[processTaskAssigned][taskId({}) 没有找到流程模型]", task.getId()); | |
| 1513 | - return; | |
| 1514 | - } | |
| 1515 | - FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); | |
| 1516 | - // 判断是否为退回或者驳回:如果是退回或者驳回不走这个策略 | |
| 1517 | - Boolean returnTaskFlag = runtimeService.getVariable(processInstance.getProcessInstanceId(), | |
| 1518 | - String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey()), Boolean.class); | |
| 1519 | - Boolean skipStartUserNodeFlag = Convert.toBool(runtimeService.getVariable(processInstance.getProcessInstanceId(), | |
| 1520 | - BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class)); | |
| 1521 | - if (userTaskElement.getId().equals(START_USER_NODE_ID) | |
| 1522 | - && (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核 | |
| 1523 | - || BooleanUtil.isTrue(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核 | |
| 1524 | - && ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { | |
| 1525 | - getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) | |
| 1526 | - .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason())); | |
| 1527 | - return; | |
| 1528 | - } | |
| 1529 | - // 当不为发起人节点时,审批人与提交人为同一人时,根据 BpmUserTaskAssignStartUserHandlerTypeEnum 策略进行处理 | |
| 1530 | - if (ObjectUtil.notEqual(userTaskElement.getId(), START_USER_NODE_ID) | |
| 1531 | - && StrUtil.equals(task.getAssignee(), processInstance.getStartUserId())) { | |
| 1532 | - if (ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { | |
| 1533 | - Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(userTaskElement); | |
| 1534 | - | |
| 1535 | - // 情况一:自动跳过 | |
| 1536 | - if (ObjectUtils.equalsAny(assignStartUserHandlerType, | |
| 1537 | - BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP.getType())) { | |
| 1538 | - getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) | |
| 1539 | - .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP.getReason())); | |
| 1540 | - return; | |
| 1541 | - } | |
| 1542 | - // 情况二:转交给部门负责人审批 | |
| 1543 | - if (ObjectUtils.equalsAny(assignStartUserHandlerType, | |
| 1544 | - BpmUserTaskAssignStartUserHandlerTypeEnum.TRANSFER_DEPT_LEADER.getType())) { | |
| 1545 | - AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); | |
| 1546 | - Assert.notNull(startUser, "提交人({})信息为空", processInstance.getStartUserId()); | |
| 1547 | - DeptRespDTO dept = startUser.getDeptId() != null ? deptApi.getDept(startUser.getDeptId()) : null; | |
| 1548 | - Assert.notNull(dept, "提交人({})部门({})信息为空", processInstance.getStartUserId(), startUser.getDeptId()); | |
| 1549 | - // 找不到部门负责人的情况下,自动审批通过 | |
| 1550 | - // noinspection DataFlowIssue | |
| 1551 | - if (dept.getLeaderUserId() == null) { | |
| 1515 | + // 获取发起人节点 | |
| 1516 | + BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId()); | |
| 1517 | + if (bpmnModel == null) { | |
| 1518 | + log.error("[processTaskAssigned][taskId({}) 没有找到流程模型]", task.getId()); | |
| 1519 | + return; | |
| 1520 | + } | |
| 1521 | + FlowElement userTaskElement = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); | |
| 1522 | + // 判断是否为退回或者驳回:如果是退回或者驳回不走这个策略 | |
| 1523 | + Boolean returnTaskFlag = runtimeService.getVariable(processInstance.getProcessInstanceId(), | |
| 1524 | + String.format(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG, task.getTaskDefinitionKey()), Boolean.class); | |
| 1525 | + Boolean skipStartUserNodeFlag = Convert.toBool(runtimeService.getVariable(processInstance.getProcessInstanceId(), | |
| 1526 | + BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE, String.class)); | |
| 1527 | + if (userTaskElement.getId().equals(START_USER_NODE_ID) | |
| 1528 | + && (skipStartUserNodeFlag == null // 目的:一般是“主流程”,发起人节点,自动通过审核 | |
| 1529 | + || BooleanUtil.isTrue(skipStartUserNodeFlag)) // 目的:一般是“子流程”,发起人节点,按配置自动通过审核 | |
| 1530 | + && ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { | |
| 1531 | + getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) | |
| 1532 | + .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP_START_USER_NODE.getReason())); | |
| 1533 | + return; | |
| 1534 | + } | |
| 1535 | + // 当不为发起人节点时,审批人与提交人为同一人时,根据 BpmUserTaskAssignStartUserHandlerTypeEnum 策略进行处理 | |
| 1536 | + if (ObjectUtil.notEqual(userTaskElement.getId(), START_USER_NODE_ID) | |
| 1537 | + && StrUtil.equals(task.getAssignee(), processInstance.getStartUserId())) { | |
| 1538 | + if (ObjUtil.notEqual(returnTaskFlag, Boolean.TRUE)) { | |
| 1539 | + Integer assignStartUserHandlerType = BpmnModelUtils.parseAssignStartUserHandlerType(userTaskElement); | |
| 1540 | + | |
| 1541 | + // 情况一:自动跳过 | |
| 1542 | + if (ObjectUtils.equalsAny(assignStartUserHandlerType, | |
| 1543 | + BpmUserTaskAssignStartUserHandlerTypeEnum.SKIP.getType())) { | |
| 1552 | 1544 | getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) |
| 1553 | - .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND.getReason())); | |
| 1545 | + .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_SKIP.getReason())); | |
| 1554 | 1546 | return; |
| 1555 | 1547 | } |
| 1556 | - // 找得到部门负责人的情况下,修改负责人 | |
| 1557 | - if (ObjectUtil.notEqual(dept.getLeaderUserId(), startUser.getId())) { | |
| 1558 | - getSelf().transferTask(Long.valueOf(task.getAssignee()), new BpmTaskTransferReqVO() | |
| 1559 | - .setId(task.getId()).setAssigneeUserId(dept.getLeaderUserId()) | |
| 1560 | - .setReason(BpmReasonEnum.ASSIGN_START_USER_TRANSFER_DEPT_LEADER.getReason())); | |
| 1561 | - return; | |
| 1548 | + // 情况二:转交给部门负责人审批 | |
| 1549 | + if (ObjectUtils.equalsAny(assignStartUserHandlerType, | |
| 1550 | + BpmUserTaskAssignStartUserHandlerTypeEnum.TRANSFER_DEPT_LEADER.getType())) { | |
| 1551 | + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); | |
| 1552 | + Assert.notNull(startUser, "提交人({})信息为空", processInstance.getStartUserId()); | |
| 1553 | + DeptRespDTO dept = startUser.getDeptId() != null ? deptApi.getDept(startUser.getDeptId()) : null; | |
| 1554 | + Assert.notNull(dept, "提交人({})部门({})信息为空", processInstance.getStartUserId(), startUser.getDeptId()); | |
| 1555 | + // 找不到部门负责人的情况下,自动审批通过 | |
| 1556 | + // noinspection DataFlowIssue | |
| 1557 | + if (dept.getLeaderUserId() == null) { | |
| 1558 | + getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) | |
| 1559 | + .setReason(BpmReasonEnum.ASSIGN_START_USER_APPROVE_WHEN_DEPT_LEADER_NOT_FOUND.getReason())); | |
| 1560 | + return; | |
| 1561 | + } | |
| 1562 | + // 找得到部门负责人的情况下,修改负责人 | |
| 1563 | + if (ObjectUtil.notEqual(dept.getLeaderUserId(), startUser.getId())) { | |
| 1564 | + getSelf().transferTask(Long.valueOf(task.getAssignee()), new BpmTaskTransferReqVO() | |
| 1565 | + .setId(task.getId()).setAssigneeUserId(dept.getLeaderUserId()) | |
| 1566 | + .setReason(BpmReasonEnum.ASSIGN_START_USER_TRANSFER_DEPT_LEADER.getReason())); | |
| 1567 | + return; | |
| 1568 | + } | |
| 1569 | + // 如果部门负责人是自己,还是自己审批吧~ | |
| 1562 | 1570 | } |
| 1563 | - // 如果部门负责人是自己,还是自己审批吧~ | |
| 1564 | 1571 | } |
| 1565 | 1572 | } |
| 1566 | - } | |
| 1567 | - // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号 | |
| 1568 | - FlowableUtils.execute(processInstance.getTenantId(), () -> { | |
| 1573 | + | |
| 1569 | 1574 | AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); |
| 1570 | 1575 | messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); |
| 1571 | 1576 | }); | ... | ... |