|
|
@@ -0,0 +1,252 @@ |
|
|
|
package com.ningdatech.pmapi.todocenter; |
|
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
|
|
|
import com.ningdatech.basic.exception.BizException; |
|
|
|
import com.ningdatech.pmapi.AppTests; |
|
|
|
import com.wflow.bean.entity.WflowCcTasks; |
|
|
|
import com.wflow.mapper.WflowCcTasksMapper; |
|
|
|
import com.wflow.utils.CodeUtil; |
|
|
|
import com.wflow.workflow.bean.dto.ReqProcessHandlerDTO; |
|
|
|
import com.wflow.workflow.enums.ProcessHandlerEnum; |
|
|
|
import com.wflow.workflow.mapper.CustomHisActInstMapper; |
|
|
|
import com.wflow.workflow.utils.ProcessTaskUtils; |
|
|
|
import lombok.extern.slf4j.Slf4j; |
|
|
|
import org.assertj.core.util.Lists; |
|
|
|
import org.flowable.bpmn.model.BpmnModel; |
|
|
|
import org.flowable.bpmn.model.FlowElement; |
|
|
|
import org.flowable.common.engine.impl.cmd.CustomSqlExecution; |
|
|
|
import org.flowable.engine.*; |
|
|
|
import org.flowable.engine.history.HistoricActivityInstance; |
|
|
|
import org.flowable.engine.impl.cmd.AbstractCustomSqlExecution; |
|
|
|
import org.flowable.engine.runtime.Execution; |
|
|
|
import org.flowable.task.api.Task; |
|
|
|
import org.flowable.task.api.history.HistoricTaskInstance; |
|
|
|
import org.junit.Test; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
|
|
|
|
import java.util.Date; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Objects; |
|
|
|
import java.util.stream.Collectors; |
|
|
|
|
|
|
|
/** |
|
|
|
* @Classname FlowableTest |
|
|
|
* @Description |
|
|
|
* @Date 2023/5/14 9:12 |
|
|
|
* @Author PoffyZhang |
|
|
|
*/ |
|
|
|
@Slf4j |
|
|
|
public class FlowableTest extends AppTests { |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private RuntimeService runtimeService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private HistoryService historyService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private RepositoryService repositoryService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private TaskService taskService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private ManagementService managementService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private WflowCcTasksMapper ccTasksMapper; |
|
|
|
|
|
|
|
@Test |
|
|
|
public void withdrawTest(){ |
|
|
|
String taskId = "cc3d7536-f1f3-11ed-b9e0-02426daa406d"; |
|
|
|
|
|
|
|
// 不是流程发起人撤回 |
|
|
|
HistoricTaskInstance handledTaskInstance = historyService.createHistoricTaskInstanceQuery() |
|
|
|
.taskId(taskId) |
|
|
|
.singleResult(); |
|
|
|
if (Objects.isNull(handledTaskInstance)){ |
|
|
|
throw new BizException("获取任务实例失败!"); |
|
|
|
} |
|
|
|
|
|
|
|
String processInstanceId = handledTaskInstance.getProcessInstanceId(); |
|
|
|
|
|
|
|
// 获取已处理历史活跃实例节点ID |
|
|
|
String handledNodeId = handledTaskInstance.getTaskDefinitionKey(); |
|
|
|
|
|
|
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(handledTaskInstance.getProcessDefinitionId()); |
|
|
|
|
|
|
|
//先得到 其所在子流程 |
|
|
|
Map<String, String> subNodeMap = ProcessTaskUtils.getSubNodeMap(bpmnModel); |
|
|
|
String subProcessId = subNodeMap.get(handledNodeId); |
|
|
|
//然后得到 子流程下的所有 nodeId |
|
|
|
Map<String, List<String>> allSubNodeMap = ProcessTaskUtils.loadSubNodeMap(bpmnModel); |
|
|
|
List<String> nodeIds = allSubNodeMap.get(subProcessId); |
|
|
|
|
|
|
|
// 获取待处理历史活跃实例节点ID(会签/或签会有多个) |
|
|
|
// 获取当前流程实例待审核任务信息 |
|
|
|
List<Task> taskList = taskService.createTaskQuery() |
|
|
|
.processInstanceId(processInstanceId) |
|
|
|
.taskDefinitionKeys(nodeIds) |
|
|
|
.list(); |
|
|
|
//保证是此子流程下的任务 那第一个就是当前操作节点了 |
|
|
|
Task currentTask = taskList.get(0); |
|
|
|
String currentNodeId = currentTask.getTaskDefinitionKey(); |
|
|
|
|
|
|
|
// 传节点定义key 获取撤回操作人在流程配置中所在的节点 |
|
|
|
FlowElement beforeFlowElement = bpmnModel.getFlowElement(handledNodeId); |
|
|
|
// 获取执行撤回操作的节点所在子流程所有节点ID |
|
|
|
List<String> actIdList = Lists.newArrayList(handledNodeId,currentNodeId); |
|
|
|
|
|
|
|
List<HistoricActivityInstance> historicActivityInstanceList = historyService |
|
|
|
.createHistoricActivityInstanceQuery() |
|
|
|
.processInstanceId(processInstanceId) |
|
|
|
.list(); |
|
|
|
|
|
|
|
// 标记执行撤回操作节点及当前待处理节点(userTask类型)为被撤回(使用DELETE_REASON_标志) |
|
|
|
List<HistoricActivityInstance> activityInstances = historicActivityInstanceList.stream() |
|
|
|
.filter(a -> actIdList.contains(a.getActivityId())) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
// 先查出当前撤回节点所在子流程节点的节点ID |
|
|
|
List<String> subProcessActIds = historicActivityInstanceList.stream() |
|
|
|
.filter(a -> "subProcess".equals(a.getActivityType())) |
|
|
|
.map(HistoricActivityInstance::getActivityId) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
List<Execution> executions = runtimeService.createExecutionQuery() |
|
|
|
.processInstanceId(processInstanceId).onlyChildExecutions().list(); |
|
|
|
List<String> actIds = executions.stream().map(Execution::getActivityId).collect(Collectors.toList()); |
|
|
|
// 去除子流程节点ID |
|
|
|
actIds.removeAll(subProcessActIds); |
|
|
|
// 强制流程指向前一个审核人节点 |
|
|
|
runtimeService.createChangeActivityStateBuilder() |
|
|
|
.processInstanceId(processInstanceId) |
|
|
|
.moveActivityIdsToSingleActivityId(actIds,handledNodeId) |
|
|
|
.changeState(); |
|
|
|
|
|
|
|
// 如果是从会签节点撤回,执行会签节点的节点ID和当前待处理节点ID相同,只需要标记当前会签节点为被撤回 |
|
|
|
if (handledNodeId.equals(currentNodeId)){ |
|
|
|
activityInstances = activityInstances.stream().filter(a -> currentNodeId.equals(a.getActivityId())).collect(Collectors.toList()); |
|
|
|
} |
|
|
|
for (HistoricActivityInstance activityInstance : activityInstances) { |
|
|
|
String executionId = activityInstance.getExecutionId(); |
|
|
|
// 备注子流程已处理节点为被撤回 |
|
|
|
CustomSqlExecution<CustomHisActInstMapper, Integer> customSqlExecution = new AbstractCustomSqlExecution<CustomHisActInstMapper, Integer>(CustomHisActInstMapper.class) { |
|
|
|
@Override |
|
|
|
public Integer execute(CustomHisActInstMapper customHisActInstMapper) { |
|
|
|
// 更新历史活跃实例表中删除原因为被撤回 |
|
|
|
return customHisActInstMapper.deleteHisActInst(processInstanceId, executionId); |
|
|
|
} |
|
|
|
}; |
|
|
|
managementService.executeCustomSql(customSqlExecution); |
|
|
|
taskService.deleteTask(activityInstance.getTaskId()); |
|
|
|
historyService.deleteHistoricTaskInstance(activityInstance.getTaskId()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Test |
|
|
|
public void testWithDraw(){ |
|
|
|
ReqProcessHandlerDTO param = new ReqProcessHandlerDTO(); |
|
|
|
param.setProjectId(633L); |
|
|
|
param.setTaskId("8e3e9329-f544-11ed-91fd-02426daa406d"); |
|
|
|
param.setAction(ProcessHandlerEnum.WITHDRAW); |
|
|
|
param.setInstanceId("93877c57-f542-11ed-91fd-02426daa406d"); |
|
|
|
|
|
|
|
// 不是流程发起人撤回 |
|
|
|
HistoricTaskInstance handledTaskInstance = historyService.createHistoricTaskInstanceQuery() |
|
|
|
.taskId(param.getTaskId()) |
|
|
|
.singleResult(); |
|
|
|
if (Objects.isNull(handledTaskInstance)){ |
|
|
|
throw new BizException("获取任务实例失败!"); |
|
|
|
} |
|
|
|
|
|
|
|
String processInstanceId = handledTaskInstance.getProcessInstanceId(); |
|
|
|
|
|
|
|
// 获取已处理历史活跃实例节点ID |
|
|
|
String handledNodeId = handledTaskInstance.getTaskDefinitionKey(); |
|
|
|
Date handleCreateTime = handledTaskInstance.getCreateTime(); |
|
|
|
|
|
|
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(handledTaskInstance.getProcessDefinitionId()); |
|
|
|
|
|
|
|
//先得到 其所在子流程 |
|
|
|
Map<String, String> subNodeMap = ProcessTaskUtils.getSubNodeMap(bpmnModel); |
|
|
|
String subProcessId = subNodeMap.get(handledNodeId); |
|
|
|
//然后得到 子流程下的所有 nodeId |
|
|
|
Map<String, List<String>> allSubNodeMap = ProcessTaskUtils.loadSubNodeMap(bpmnModel); |
|
|
|
List<String> nodeIds = allSubNodeMap.get(subProcessId); |
|
|
|
|
|
|
|
// 获取待处理历史活跃实例节点ID(会签/或签会有多个) |
|
|
|
// 获取当前流程实例待审核任务信息 |
|
|
|
List<Task> taskList = taskService.createTaskQuery() |
|
|
|
.processInstanceId(processInstanceId) |
|
|
|
.taskDefinitionKeys(nodeIds) |
|
|
|
.list(); |
|
|
|
//保证是此子流程下的任务 那第一个就是当前操作节点了 |
|
|
|
Task currentTask = taskList.get(0); |
|
|
|
Date currentCreateTime = currentTask.getCreateTime(); |
|
|
|
String currentNodeId = currentTask.getTaskDefinitionKey(); |
|
|
|
|
|
|
|
// 传节点定义key 获取撤回操作人在流程配置中所在的节点 |
|
|
|
FlowElement beforeFlowElement = bpmnModel.getFlowElement(handledNodeId); |
|
|
|
// 获取执行撤回操作的节点所在子流程所有节点ID |
|
|
|
List<String> actIdList = Lists.newArrayList(handledNodeId,currentNodeId); |
|
|
|
|
|
|
|
List<HistoricActivityInstance> historicActivityInstanceList = historyService |
|
|
|
.createHistoricActivityInstanceQuery() |
|
|
|
.processInstanceId(processInstanceId) |
|
|
|
.list(); |
|
|
|
|
|
|
|
// 标记执行撤回操作节点及当前待处理节点(userTask类型)为被撤回(使用DELETE_REASON_标志) |
|
|
|
List<HistoricActivityInstance> activityInstances = historicActivityInstanceList.stream() |
|
|
|
.filter(a -> { |
|
|
|
if(actIdList.contains(a.getActivityId())){ |
|
|
|
if(a.getActivityId().equals(handledNodeId)){ |
|
|
|
return (CodeUtil.computationTime(a.getStartTime(),handleCreateTime) == 0L); |
|
|
|
}else if(a.getActivityId().equals(currentNodeId)){ |
|
|
|
return (CodeUtil.computationTime(a.getStartTime(),currentCreateTime) == 0L); |
|
|
|
} |
|
|
|
} |
|
|
|
return Boolean.FALSE; |
|
|
|
}) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
// 先查出当前撤回节点所在子流程节点的节点ID |
|
|
|
List<String> subProcessActIds = historicActivityInstanceList.stream() |
|
|
|
.filter(a -> "subProcess".equals(a.getActivityType())) |
|
|
|
.map(HistoricActivityInstance::getActivityId) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
List<Execution> executions = runtimeService.createExecutionQuery() |
|
|
|
.processInstanceId(processInstanceId).onlyChildExecutions().list(); |
|
|
|
List<String> actIds = executions.stream().map(Execution::getActivityId).collect(Collectors.toList()); |
|
|
|
// 去除子流程节点ID |
|
|
|
actIds.removeAll(subProcessActIds); |
|
|
|
// 强制流程指向前一个审核人节点 |
|
|
|
runtimeService.createChangeActivityStateBuilder() |
|
|
|
.processInstanceId(processInstanceId) |
|
|
|
// .moveActivityIdTo(currentNodeId,handledNodeId) |
|
|
|
.moveActivityIdsToSingleActivityId(actIds,handledNodeId) |
|
|
|
.changeState(); |
|
|
|
|
|
|
|
// 如果是从会签节点撤回,执行会签节点的节点ID和当前待处理节点ID相同,只需要标记当前会签节点为被撤回 |
|
|
|
if (handledNodeId.equals(currentNodeId)){ |
|
|
|
activityInstances = activityInstances.stream().filter(a -> currentNodeId.equals(a.getActivityId())).collect(Collectors.toList()); |
|
|
|
} |
|
|
|
for (HistoricActivityInstance activityInstance : activityInstances) { |
|
|
|
String executionId = activityInstance.getExecutionId(); |
|
|
|
// 备注子流程已处理节点为被撤回 |
|
|
|
CustomSqlExecution<CustomHisActInstMapper, Integer> customSqlExecution = new AbstractCustomSqlExecution<CustomHisActInstMapper, Integer>(CustomHisActInstMapper.class) { |
|
|
|
@Override |
|
|
|
public Integer execute(CustomHisActInstMapper customHisActInstMapper) { |
|
|
|
// 更新历史活跃实例表中删除原因为被撤回 |
|
|
|
return customHisActInstMapper.deleteHisActInst(processInstanceId, executionId); |
|
|
|
} |
|
|
|
}; |
|
|
|
managementService.executeCustomSql(customSqlExecution); |
|
|
|
taskService.deleteTask(activityInstance.getTaskId()); |
|
|
|
historyService.deleteHistoricTaskInstance(activityInstance.getTaskId()); |
|
|
|
} |
|
|
|
// 如果当前执行撤回操作的节点后有抄送节点,撤回后,需将抄送任务节点删除 |
|
|
|
String ccNodeId = param.getCcNodeId(); |
|
|
|
ccTasksMapper.delete(Wrappers.lambdaQuery(WflowCcTasks.class).eq(WflowCcTasks::getNodeId,ccNodeId)); |
|
|
|
} |
|
|
|
} |