当前使用的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) { return Result.error("任务撤回失败500"); } }