review:【bpm 工作流】撤回逻辑(没问题)

This commit is contained in:
YunaiV
2025-08-02 15:44:19 +08:00
parent 937fd73160
commit 51e5294a3e
4 changed files with 36 additions and 42 deletions

View File

@ -72,6 +72,9 @@ public class BpmModelMetaInfoVO {
@Schema(description = "允许撤销审批中的申请", example = "true") @Schema(description = "允许撤销审批中的申请", example = "true")
private Boolean allowCancelRunningProcess; private Boolean allowCancelRunningProcess;
@Schema(description = "允许允许审批人撤回任务", example = "false")
private Boolean allowWithdrawTask;
@Schema(description = "流程 ID 规则", example = "{}") @Schema(description = "流程 ID 规则", example = "{}")
private ProcessIdRule processIdRule; private ProcessIdRule processIdRule;
@ -97,9 +100,6 @@ public class BpmModelMetaInfoVO {
@Schema(description = "任务后置通知设置", example = "{}") @Schema(description = "任务后置通知设置", example = "{}")
private HttpRequestSetting taskAfterTriggerSetting; private HttpRequestSetting taskAfterTriggerSetting;
@Schema(description = "允许允许审批人撤回任务", example = "false")
private Boolean allowWithdrawTask;
@Schema(description = "流程 ID 规则") @Schema(description = "流程 ID 规则")
@Data @Data
@Valid @Valid

View File

@ -172,6 +172,11 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
*/ */
private Boolean allowCancelRunningProcess; private Boolean allowCancelRunningProcess;
/**
* 是否允许审批人撤回任务
*/
private Boolean allowWithdrawTask;
/** /**
* 流程 ID 规则 * 流程 ID 规则
*/ */
@ -219,9 +224,4 @@ public class BpmProcessDefinitionInfoDO extends BaseDO {
@TableField(typeHandler = JacksonTypeHandler.class) @TableField(typeHandler = JacksonTypeHandler.class)
private BpmModelMetaInfoVO.HttpRequestSetting taskAfterTriggerSetting; private BpmModelMetaInfoVO.HttpRequestSetting taskAfterTriggerSetting;
/**
* 是否允许审批人撤回任务
*/
private Boolean allowWithdrawTask;
} }

View File

@ -852,7 +852,7 @@ public class BpmnModelUtils {
} else if (flowNode instanceof ScriptTask) { } else if (flowNode instanceof ScriptTask) {
skipExpression = ((ScriptTask) flowNode).getSkipExpression(); skipExpression = ((ScriptTask) flowNode).getSkipExpression();
} }
if (StrUtil.isEmpty(skipExpression)) { if (StrUtil.isEmpty(skipExpression)) {
return false; return false;
} }
@ -910,6 +910,7 @@ public class BpmnModelUtils {
/** /**
* 查找起始节点下一个用户任务列表列表 * 查找起始节点下一个用户任务列表列表
*
* @param source 起始节点 * @param source 起始节点
* @return 结果 * @return 结果
*/ */

View File

@ -40,9 +40,10 @@ import jakarta.annotation.Resource;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.*;
import org.flowable.common.engine.api.FlowableException; import org.flowable.engine.HistoryService;
import org.flowable.common.engine.api.FlowableObjectNotFoundException; import org.flowable.engine.ManagementService;
import org.flowable.engine.*; import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance; import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.runtime.ActivityInstance; import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.Execution; import org.flowable.engine.runtime.Execution;
@ -61,7 +62,6 @@ import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -1180,61 +1180,54 @@ public class BpmTaskServiceImpl implements BpmTaskService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void withdrawTask(Long userId, String taskId) { public void withdrawTask(Long userId, String taskId) {
// 1.查询本人已办任务 // 1.1 查询本人已办任务
HistoricTaskInstance taskInstance = historyService.createHistoricTaskInstanceQuery() HistoricTaskInstance taskInstance = historyService.createHistoricTaskInstanceQuery()
.taskId(taskId).taskAssignee(userId.toString()).finished().singleResult(); .taskId(taskId).taskAssignee(userId.toString()).finished().singleResult();
if (ObjectUtil.isNull(taskInstance)) { if (ObjUtil.isNull(taskInstance)) {
throw exception(TASK_WITHDRAW_FAIL_TASK_NOT_EXISTS); throw exception(TASK_WITHDRAW_FAIL_TASK_NOT_EXISTS);
} }
// 2.校验流程是否结束 // 1.2 校验流程是否结束
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() ProcessInstance processInstance = processInstanceService.getProcessInstance(taskInstance.getProcessInstanceId());
.processInstanceId(taskInstance.getProcessInstanceId()) if (ObjUtil.isNull(processInstance)) {
.active()
.singleResult();
if (ObjectUtil.isNull(processInstance)) {
throw exception(TASK_WITHDRAW_FAIL_PROCESS_NOT_RUNNING); throw exception(TASK_WITHDRAW_FAIL_PROCESS_NOT_RUNNING);
} }
// 3.判断此流程是否允许撤回 // 1.3 判断此流程是否允许撤回
BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService BpmProcessDefinitionInfoDO processDefinitionInfo = bpmProcessDefinitionService.getProcessDefinitionInfo(
.getProcessDefinitionInfo(processInstance.getProcessDefinitionId()); processInstance.getProcessDefinitionId());
if (ObjectUtil.isNull(processDefinitionInfo) || !Boolean.TRUE.equals(processDefinitionInfo.getAllowWithdrawTask())) { if (ObjUtil.isNull(processDefinitionInfo) || !Boolean.TRUE.equals(processDefinitionInfo.getAllowWithdrawTask())) {
throw exception(TASK_WITHDRAW_FAIL_NOT_ALLOW); throw exception(TASK_WITHDRAW_FAIL_NOT_ALLOW);
} }
// 4.判断此任务下一节点是否满足撤回 // 1.4 判断下一节点是否被审批过,如果是则无法撤回
BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(taskInstance.getProcessDefinitionId()); BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(taskInstance.getProcessDefinitionId());
UserTask userTask = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, taskInstance.getTaskDefinitionKey()); UserTask userTask = (UserTask) BpmnModelUtils.getFlowElementById(bpmnModel, taskInstance.getTaskDefinitionKey());
List<UserTask> nextUserTaskList = BpmnModelUtils.getNextUserTasks(userTask); List<String> nextUserTaskKeys = convertList(BpmnModelUtils.getNextUserTasks(userTask), UserTask::getId);
List<String> nextUserTaskKeys = nextUserTaskList.stream().map(UserTask::getId).toList();
if (CollUtil.isEmpty(nextUserTaskKeys)) { if (CollUtil.isEmpty(nextUserTaskKeys)) {
throw exception(TASK_WITHDRAW_FAIL_NEXT_TASK_NOT_ALLOW); throw exception(TASK_WITHDRAW_FAIL_NEXT_TASK_NOT_ALLOW);
} }
// TODO @芋艿是否选择升级flowable版本解决taskCreatedAfter、taskCreatedBefore问题升级7.1.0可以;包括 todo 和 done 那边的查询哇???
long nextUserTaskFinishedCount = historyService.createHistoricTaskInstanceQuery() long nextUserTaskFinishedCount = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstance.getProcessInstanceId()) .processInstanceId(processInstance.getProcessInstanceId()).taskDefinitionKeys(nextUserTaskKeys)
.taskDefinitionKeys(nextUserTaskKeys) .taskCreatedAfter(taskInstance.getEndTime()).finished().count();
.taskCreatedAfter(taskInstance.getEndTime()) // TODO @芋艿是否选择升级flowable版本解决taskCreatedAfter、taskCreatedBefore问题升级7.1.0可以
.finished()
.count();
if (nextUserTaskFinishedCount > 0) { if (nextUserTaskFinishedCount > 0) {
throw exception(TASK_WITHDRAW_FAIL_NEXT_TASK_NOT_ALLOW); throw exception(TASK_WITHDRAW_FAIL_NEXT_TASK_NOT_ALLOW);
} }
// 5.获取需要撤回的运行任务 // 1.5 获取需要撤回的运行任务
List<Task> runningTaskList = taskService.createTaskQuery() List<Task> runningTasks = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId())
.processInstanceId(processInstance.getProcessInstanceId()) .taskDefinitionKeys(nextUserTaskKeys).active().list();
.taskDefinitionKeys(nextUserTaskKeys) if (CollUtil.isEmpty(runningTasks)) {
.active().list();
if (CollUtil.isEmpty(runningTaskList)) {
throw exception(TASK_WITHDRAW_FAIL_NEXT_TASK_NOT_ALLOW); throw exception(TASK_WITHDRAW_FAIL_NEXT_TASK_NOT_ALLOW);
} }
// 2.1 取消当前任务
List<String> withdrawExecutionIds = new ArrayList<>(); List<String> withdrawExecutionIds = new ArrayList<>();
for (Task task : runningTaskList) { for (Task task : runningTasks) {
// 标记撤回任务为取消 // 标记撤回任务为取消
// TODO @芋艿:是否需要添加被撤回状态?
taskService.addComment(task.getId(), taskInstance.getProcessInstanceId(), BpmCommentTypeEnum.CANCEL.getType(), taskService.addComment(task.getId(), taskInstance.getProcessInstanceId(), BpmCommentTypeEnum.CANCEL.getType(),
BpmCommentTypeEnum.CANCEL.formatComment("前一节点撤回")); BpmCommentTypeEnum.CANCEL.formatComment("前一节点撤回"));
updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.CANCEL.getStatus(), BpmReasonEnum.CANCEL_BY_WITHDRAW.getReason()); updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.CANCEL.getStatus(), BpmReasonEnum.CANCEL_BY_WITHDRAW.getReason());
withdrawExecutionIds.add(task.getExecutionId()); withdrawExecutionIds.add(task.getExecutionId());
} }
// 6.执行撤回操作 // 2.2 执行撤回操作
runtimeService.createChangeActivityStateBuilder() runtimeService.createChangeActivityStateBuilder()
.processInstanceId(processInstance.getProcessInstanceId()) .processInstanceId(processInstance.getProcessInstanceId())
.moveExecutionsToSingleActivityId(withdrawExecutionIds, taskInstance.getTaskDefinitionKey()) .moveExecutionsToSingleActivityId(withdrawExecutionIds, taskInstance.getTaskDefinitionKey())