Commit 1d463f4f1a359f4a91cc07772c39f68008a69b89

Authored by jason
1 parent 91f356fc

fix: 修复回退报错问题, moveExecutionsToSingleActivityId 替换为 moveActivityIdsToSingleActivityId

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 });
... ...