Browse Source

撤回优化

tags/24080901
PoffyZhang 1 year ago
parent
commit
639c8e47f6
2 changed files with 268 additions and 0 deletions
  1. +16
    -0
      pmapi/src/main/java/com/ningdatech/pmapi/todocenter/handle/WithDrawHandle.java
  2. +252
    -0
      pmapi/src/test/java/com/ningdatech/pmapi/todocenter/FlowableTest.java

+ 16
- 0
pmapi/src/main/java/com/ningdatech/pmapi/todocenter/handle/WithDrawHandle.java View File

@@ -111,10 +111,12 @@ public class WithDrawHandle {
return Boolean.FALSE;
}
currentProgressNode = children.get(children.size() - 1);

//把当前和上一个节点和 会签或签的情况 都check出来
beforeProgressNode = checkBeforeNodeAndOr(children,currentProgressNode,thisAndOr,beforeAndOr);
} else {
currentProgressNode = currentProgressInfo.get(currentProgressInfo.size() - 1);

// 把当前和上一个节点和 会签或签的情况 都check出来
beforeProgressNode = checkBeforeNodeAndOr(currentProgressInfo,currentProgressNode,thisAndOr,beforeAndOr);
}
@@ -127,12 +129,16 @@ public class WithDrawHandle {

Boolean isAndOr = Boolean.FALSE;

//判断当前子流程是否结束 如果结束了 必不能撤回
Boolean thisSubNodeOver = Boolean.FALSE;
//当前节点是 会签|或签的情况
if(CollUtil.isNotEmpty(thisAndOr)){
Integer finishNodes = 0;
for(ProgressNode n : thisAndOr){
if(Objects.nonNull(n.getFinishTime())){
//当前会签 有审批过的 那么上个会签|或签 无论如何 就不可能可以撤回了
beforeAndOr = Collections.emptyList();
finishNodes ++;
}
//找到了 当前的操作人 在当前的 会签|或签 中 并且已经审批了
if(n.getUserId().equals(user.getEmployeeCode()) &&
@@ -142,6 +148,16 @@ public class WithDrawHandle {
isAndOr = Boolean.TRUE;
}
}
//如果都审批过了 结束了 那说明此子流程已经结束了 不能再撤回了
if(finishNodes.equals(thisAndOr.size())){
return Boolean.FALSE;
}
}else{
//如果当前不是会签|或签 就判断 当前最后一个节点 结束了没
//如果结束了 也同样 直接不能撤回
if(Objects.nonNull(currentProgressNode.getFinishTime())){
return Boolean.FALSE;
}
}

//如果上个会签没取到 还有种情况是 会签 或签 并且在上个节点


+ 252
- 0
pmapi/src/test/java/com/ningdatech/pmapi/todocenter/FlowableTest.java View File

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

Loading…
Cancel
Save