当前使用的BPM引擎为Activiti6.0,客户需求是流程发起人能将整个流程撤销,对于某个流程节点,办理人可以撤回已经办理的任务,同时前提是该任务节点的下个节点未被办理。
1、流程撤销
首先说下发起人对整个流程的撤销,直接删除流程,传入流程实例ID,结束一个流程。执行此方法后,流程实例的当前任务act_ru_task会被删除,流程历史act_hi_taskinst不会被删除,并且流程历史的状态置为finished完成。
runtimeService.deleteProcessInstance(instanceId, deleteReason);
2、任务撤回
已执行任务的撤回操作相对来说复杂些,这里先分步骤说下总体思路:
1)选择一条已办理任务,根据该任务查询出任务ID =myTaskId和流程实例ID=processInstanceId;
2)根据processInstanceId判断当前流程是否已结束或已挂起,流程结束或挂起则无法执行撤回操作;
3)根据myTaskId查询选择任务的历史任务实例historicTaskInstance,进而查询出对应历史活动实例historicActivityInstance,最终得到活动标识myActivityId;
4)根据活动标识myActivityId获取该任务对应的FlowNode对象myFlowNode;
5)查询出该任务节点的所有下一任务节点flowElementList,此处是任务节点Task,排查其它类型活动节点;
6)判断flowElementList中是否有代办事项,如果有则可以执行撤回操作,否则表示该任务的所有下一任务都执行完毕,此时不允许再执行撤回操作;
7)对下一节点代办任务,同样查询出对应的FlowNode对象flowNode;
8)借助FlowNode对象myFlowNode和flowNode,反方向执行一次任务,即从代办任务节点反方向流转到当前任务节点,从而完成了任务撤回操作。
完整代码如下:
public Result cancelTask(ActivitiTask doneTask) {
try {
// doneTask为封装的Task对象
String processInstanceId = doneTask.getInstanceId();
String myTaskId = doneTask.getTaskId();
// 校验流程是否结束
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId).active()
.singleResult();
if(processInstance == null) {
return Result.error("流程已结束或已挂起,无法执行撤回操作");
}
// 当前任务
HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(myTaskId)
.processInstanceId(processInstanceId).singleResult();
if(historicTaskInstance==null) {
return Result.error("当前任务不存在,无法撤回");
}
String myActivityId = null;
List<HistoricActivityInstance> actInstList =
historyService.createHistoricActivityInstanceQuery()
.executionId(historicTaskInstance.getExecutionId())
.finished().list();
for(HistoricActivityInstance hai : actInstList) {
if(myTaskId.equals(hai.getTaskId())) {
myActivityId = hai.getActivityId();
break;
}
}
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
// 获取所有下一任务节点的标识ID
Map<String, String> taskKeyMap = Maps.newHashMap();
// 获取所有下一任务节点对应的FlowElement
List<FlowElement> flowElementList = getOutgoingTask(bpmnModel, myActivityId);
for(FlowElement flowElement : flowElementList) {
String eleId = flowElement.getId();
taskKeyMap.put(eleId, eleId);
}
// 获取当前流程代办事项,没有代办事项表明流程结束或已挂起
List<Task> alltaskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
if(alltaskList.size() <= 0) {
return Result.error("流程已结束或已挂起,无法执行撤回操作");
}
// 判断所有下一任务节点中是否有代办任务,没有则表示任务已办理或已撤回,此时无法再执行撤回操作
List<Task> nextTaskList = Lists.newArrayList();
for(Task task : alltaskList) {
if(taskKeyMap.containsKey(task.getTaskDefinitionKey())) {
nextTaskList.add(task);
}
}
if(nextTaskList.size() <= 0) {
return Result.error("任务已办理或已撤回,无法执行撤回操作");
}
// 执行撤回操作
for(Task task : nextTaskList) {
Execution execution = runtimeService.createExecutionQuery()
.executionId(task.getExecutionId()).singleResult();
String activityId = execution.getActivityId();
FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess()
.getFlowElement(activityId);
// 记录原活动方向
List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
oriSequenceFlows.addAll(flowNode.getOutgoingFlows());
flowNode.getOutgoingFlows().clear();
// 建立新方向
List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("sid-"+UUID.randomUUID().toString());
newSequenceFlow.setSourceFlowElement(flowNode);
newSequenceFlow.setTargetFlowElement(myFlowNode);
newSequenceFlowList.add(newSequenceFlow);
flowNode.setOutgoingFlows(newSequenceFlowList);
taskService.addComment(task.getId(), task.getProcessInstanceId(), "主动撤回");
taskService.resolveTask(task.getId());
taskService.claim(task.getId(), doneTask.getTodoUserId());
taskService.complete(task.getId());
flowNode.setOutgoingFlows(oriSequenceFlows);
}
return Result.success();
} catch (Exception e) {
logger.error(e.getMessage(), e);
return Result.error("任务撤回失败500");
}
}