From 128f61a1edcfbcaeb0249d2628f5ccdb3146a265 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Mon, 25 Aug 2025 21:42:25 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20[BPM=20=E5=B7=A5=E4=BD=9C=E6=B5=81]?= =?UTF-8?q?=20=E6=B5=81=E7=A8=8B=E5=89=8D=E7=BD=AE=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=EF=BC=8C=E9=9C=80=E8=A6=81=E6=94=BE=E5=9C=A8=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E5=90=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/BpmProcessInstanceServiceImpl.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index b4a871e145..af324714db 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -996,17 +996,17 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService if (ObjUtil.notEqual(instance.getName(), name)) { runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), name); } + + // 流程前置通知:需要在流程启动后(事务提交后)。variables 已设置。或者放在 PROCESS_STARTED 事件中处理,先放这里。 + if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) { + return; + } + BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting(); + BpmHttpRequestUtils.executeBpmHttpRequest(instance, + setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); } }); - - // 流程前置通知 - if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) { - return; - } - BpmModelMetaInfoVO.HttpRequestSetting setting = processDefinitionInfo.getProcessBeforeTriggerSetting(); - BpmHttpRequestUtils.executeBpmHttpRequest(instance, - setting.getUrl(), setting.getHeader(), setting.getBody(), true, setting.getResponse()); } } From d6643c9a273f8d697381ad1f2f0c099be71f8121 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Wed, 27 Aug 2025 22:34:41 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20[BPM=20=E5=B7=A5=E4=BD=9C=E6=B5=81]?= =?UTF-8?q?=20=E5=AD=90=E6=B5=81=E7=A8=8B=E5=AE=A1=E6=89=B9=E4=B8=8D?= =?UTF-8?q?=E9=80=9A=E8=BF=87=EF=BC=8C=E7=BB=93=E6=9D=9F=E4=B8=BB=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=AE=A1=E6=89=B9=EF=BC=8C=E5=B9=B6=E6=A0=87=E8=AE=B0?= =?UTF-8?q?=E4=B8=BA=E4=B8=8D=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/enums/task/BpmReasonEnum.java | 1 + .../bpm/service/task/BpmTaskServiceImpl.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java index 6ce6f65b82..162dd63d5a 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java @@ -19,6 +19,7 @@ public enum BpmReasonEnum { CANCEL_PROCESS_INSTANCE_BY_START_USER("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程 CANCEL_PROCESS_INSTANCE_BY_ADMIN("管理员【{}】取消流程,原因:{}"), // 场景:管理员取消流程 CANCEL_CHILD_PROCESS_INSTANCE_BY_MAIN_PROCESS("子流程自动取消,原因:主流程已取消"), + REJECT_CHILD_PROCESS("子流程审批不通过"), // ========== 流程任务的独有原因 ========== diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index f53d86d515..ace48227a2 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -67,6 +67,7 @@ import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum.REJECT_CHILD_PROCESS; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE; @@ -805,8 +806,23 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } // 3.2 情况二:直接结束,审批不通过 + // 3.2.1 如果是子流程,需获取父流程。标记父流程为不通过。 + // 注意需要在子流程结束前标记,因为如果子流程是最后一个节点。在子流程结束后标记, 会报错 + ProcessInstance parentProcessInstance = null; + if (StrUtil.isNotBlank(instance.getSuperExecutionId())) { + Execution execution = runtimeService.createExecutionQuery().executionId(instance.getSuperExecutionId()).singleResult(); + parentProcessInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); + // 标记父流程不通过 + processInstanceService.updateProcessInstanceReject(parentProcessInstance, REJECT_CHILD_PROCESS.getReason()); + } + // 3.2.2 标记流程为不通过并结束流程 processInstanceService.updateProcessInstanceReject(instance, reqVO.getReason()); // 标记不通过 moveTaskToEnd(task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); // 结束流程 + + // 3.2.3 如果是子流程,结束主流程 + if (parentProcessInstance!=null) { + moveTaskToEnd(parentProcessInstance.getId(), BpmCommentTypeEnum.REJECT.formatComment(REJECT_CHILD_PROCESS.getReason())); + } } /** From 7925af994bd99d1933bfda95668faf63e5bd302f Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Fri, 29 Aug 2025 07:44:18 +0800 Subject: [PATCH 3/4] =?UTF-8?q?perf:=20[BPM=20=E5=B7=A5=E4=BD=9C=E6=B5=81]?= =?UTF-8?q?=20=E5=AD=90=E6=B5=81=E7=A8=8B=E5=AE=A1=E6=89=B9=E4=B8=8D?= =?UTF-8?q?=E9=80=9A=E8=BF=87,=E4=B8=BB=E6=B5=81=E7=A8=8B=E5=AE=A1?= =?UTF-8?q?=E6=89=B9=E4=B8=8D=E9=80=9A=E8=BF=87=E6=B5=81=E7=A8=8B=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/BpmProcessInstanceServiceImpl.java | 23 +++++++++++++++++++ .../bpm/service/task/BpmTaskServiceImpl.java | 20 +++------------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index af324714db..9dfb98725c 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -52,6 +52,7 @@ import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.Execution; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstanceBuilder; import org.flowable.task.api.Task; @@ -69,6 +70,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO.ActivityNode; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum.REJECT_CHILD_PROCESS; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils.parseNodeType; import static java.util.Arrays.asList; @@ -949,6 +951,27 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService status); } + // 1.3 如果子流程拒绝, 设置其父流程也为拒绝状态且结束父流程 + if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus()) + && StrUtil.isNotBlank(instance.getSuperExecutionId())) { + // 1.3.1 获取父流程实例 并标记为不通过 + Execution execution = runtimeService.createExecutionQuery().executionId(instance.getSuperExecutionId()).singleResult(); + ProcessInstance parentProcessInstance = getProcessInstance(execution.getProcessInstanceId()); + updateProcessInstanceReject(parentProcessInstance, REJECT_CHILD_PROCESS.getReason()); + + // 1.3.2 结束父流程。需要在子流程结束事务提交后执行 + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCompletion(int transactionStatus) { + // 回滚情况,直接返回 + if (ObjectUtil.equal(transactionStatus, TransactionSynchronization.STATUS_ROLLED_BACK)) { + return; + } + taskService.moveTaskToEnd(parentProcessInstance.getId(),REJECT_CHILD_PROCESS.getReason()); + } + }); + } + // 2. 发送对应的消息通知 if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { messageService.sendMessageWhenProcessInstanceApprove( diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index ace48227a2..60b435c6ce 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -67,7 +67,6 @@ import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; -import static cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum.REJECT_CHILD_PROCESS; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_RETURN_FLAG; import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_SKIP_START_USER_NODE; @@ -805,24 +804,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { .setTargetTaskDefinitionKey(returnTaskId).setReason(reqVO.getReason())); return; } - // 3.2 情况二:直接结束,审批不通过 - // 3.2.1 如果是子流程,需获取父流程。标记父流程为不通过。 - // 注意需要在子流程结束前标记,因为如果子流程是最后一个节点。在子流程结束后标记, 会报错 - ProcessInstance parentProcessInstance = null; - if (StrUtil.isNotBlank(instance.getSuperExecutionId())) { - Execution execution = runtimeService.createExecutionQuery().executionId(instance.getSuperExecutionId()).singleResult(); - parentProcessInstance = processInstanceService.getProcessInstance(execution.getProcessInstanceId()); - // 标记父流程不通过 - processInstanceService.updateProcessInstanceReject(parentProcessInstance, REJECT_CHILD_PROCESS.getReason()); - } - // 3.2.2 标记流程为不通过并结束流程 + + // 3.2 情况二: 标记流程为不通过并结束流程 processInstanceService.updateProcessInstanceReject(instance, reqVO.getReason()); // 标记不通过 moveTaskToEnd(task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); // 结束流程 - - // 3.2.3 如果是子流程,结束主流程 - if (parentProcessInstance!=null) { - moveTaskToEnd(parentProcessInstance.getId(), BpmCommentTypeEnum.REJECT.formatComment(REJECT_CHILD_PROCESS.getReason())); - } } /** @@ -1002,6 +987,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { } @Override + @Transactional(rollbackFor = Exception.class) public void moveTaskToEnd(String processInstanceId, String reason) { List taskList = getRunningTaskListByProcessInstanceId(processInstanceId, null, null); if (CollUtil.isEmpty(taskList)) { From c28ca2d87f4e871d64560a21badb7f3215b00eb0 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 29 Aug 2025 20:40:14 +0800 Subject: [PATCH 4/4] =?UTF-8?q?review=EF=BC=9A=E3=80=90bpm=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E3=80=91=E5=AD=90=E6=B5=81=E7=A8=8B=E4=B8=8D?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E7=9A=84=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 9dfb98725c..d26d406d6d 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -951,7 +951,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService status); } - // 1.3 如果子流程拒绝, 设置其父流程也为拒绝状态且结束父流程 + // 1.3 如果子流程拒绝,设置其父流程也为拒绝状态,且结束父流程 + // 相关问题链接:https://t.zsxq.com/kZhyb if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus()) && StrUtil.isNotBlank(instance.getSuperExecutionId())) { // 1.3.1 获取父流程实例 并标记为不通过 @@ -961,6 +962,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService // 1.3.2 结束父流程。需要在子流程结束事务提交后执行 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override public void afterCompletion(int transactionStatus) { // 回滚情况,直接返回 @@ -1020,7 +1022,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService runtimeService.setProcessInstanceName(instance.getProcessInstanceId(), name); } - // 流程前置通知:需要在流程启动后(事务提交后)。variables 已设置。或者放在 PROCESS_STARTED 事件中处理,先放这里。 + // 流程前置通知:需要在流程启动后(事务提交后),保证 variables 已设置 + // 相关问题链接:https://t.zsxq.com/DF7Kq if (ObjUtil.isNull(processDefinitionInfo.getProcessBeforeTriggerSetting())) { return; }