13、撤回(撤销)、驳回(退回)、作废(终止)、挂起(中止)

流程撤回-撤销

1、流程定义

<process id="test2" isClosed="false" isExecutable="true" processType="None">
    <startEvent id="_2" name="StartEvent"/>
    <userTask activiti:assignee="sp1" activiti:exclusive="true" id="_3" name="审批1"/>
    <userTask activiti:assignee="sp2" activiti:exclusive="true" id="_4" name="审批2"/>
    <endEvent id="_5" name="EndEvent"/>
    <sequenceFlow id="_6" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_7" sourceRef="_3" targetRef="_4"/>
    <sequenceFlow id="_8" sourceRef="_4" targetRef="_5"/>
  </process>

在这里插入图片描述

2、部署流程,开启流程,完成第一个节点"审批1"审批

/**
     * 部署流程,开启流程,完成第一个节点“审批1”审核
     */
    @Test
    public void shenpi1(){
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("bpmn/test2.bpmn").deploy();
        log.info("流程部署成功:{}",deploy.getId());

        //设置开启人
        Authentication.setAuthenticatedUserId("sp1");
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("test2");
        log.info("流程已开启:id:{},key:{},startUser:{}",instance.getId(),instance.getBusinessKey(),instance.getStartUserId());
        String instanceId=instance.getId();

//        String instanceId="2ac7e417-e2f5-11eb-9ffb-34f39ab07ea4";
        //完成第一个节点审批
        Task task = taskService.createTaskQuery()
                .processInstanceId(instanceId)
                .taskAssignee("sp1")
                .singleResult();
        taskService.complete(task.getId());
        log.info("任务已完成:id:{}",task.getId());

    }

    /**
     * 获取流程审批历史记录
     */
    @Test
    public void history(){
        String instanceId="2ac7e417-e2f5-11eb-9ffb-34f39ab07ea4";
        HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        String startUserId = instance.getStartUserId();
        Date startTime = instance.getStartTime();
        String startActivityId = instance.getStartActivityId();
        Task startTask = taskService.createTaskQuery().taskId(startActivityId).singleResult();

        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(instanceId)
                .orderByHistoricTaskInstanceStartTime()
                .asc()
                .list();
        for(HistoricTaskInstance task:list){
            List<Comment> comments = taskService.getTaskComments(task.getId());
            for(Comment c:comments){
                log.info("任务备注:id:{},userid:{},message:{}",c.getTaskId(),c.getUserId(),c.getFullMessage());
            }
            List<Attachment> attachments = taskService.getTaskAttachments(task.getId());
            log.info("任务id:{},name:{},assignee:{}",task.getId(),task.getName(),task.getAssignee());
        }
    }

3、撤回案例

撤回实现逻辑:

  1. 根据业务逻辑判断,当前任务是否可以撤回;这里只是简单判断,当前任务是当前用户审批的,并且流程下一个节点任务人还未处理任务时,此时任务是可以撤回的。比如流程开启人sp1,开启任务后,提交审批“审批1”,流程走到“审批2”节点。审核人sp1 还未审批任务,此时sp1想撤回刚才的提交,此时是可以的。如果“审批2”处理了审核,此时流程走过当前“审批2”节点了(对于这个流程案例是流程结束),sp1就不能撤回之前的提交了。
  2. 如何实现撤回功能?当前流程审核节点在“审批2”节点,可以手动修改“审批2”节点的输出流,既把“审批2”-“EndEvent”输出流删除,添加1条新输出流 “审批2”-“审批1”,这样“审批2”节点任务complete 流程自动就走到“审批1”了;
  3. “审批2”提交任务后,由于是撤回操作,流程到达“审批1”,历史任务记录中存在“审批2”提交到“审批1”历史记录。但对于业务上来说,可能这个历史记录不是必须要存在的(审批备注里面已经添加“撤回”备注信息),此时就可以把这个历史任务记录删除;当然如果需求要求也可以不删除。
  4. “审批2”提交任务后,流程走到“审批1”节点后,此时需要恢复原来的流程走向“审批2”-“EndEvent”输出流;
  5. 对于流程实现撤回功能,实现方式有很多种,比如也可以修改历史记录信息,同时在历史任务表添加新的任务记录等操作都是可以实现撤回功能。这里只是以修改输出流的方式作为说明,也是工作中用的比较多的一种实现方式。
/**
     * 流程撤回:
     * 当前用户审批通过后(流程到下一节点后),又想撤回时。撤回到上一节点;
     */
    @Test
    public void proBack(){
        //1、判断是否可撤回? 上一个节点是当前用户审核的,并且下一节点审批人还未处理时,可撤回到上一节点;
        //2、如何撤回?动态修改BpmnModel当前流程节点输出流。
        //把当前流程节点输出流方向改成上一个节点,原有输出流删除;
        //审批通过后,再次恢复当前节点的原有输出流;
        //根据业务需求,判断是否删除上次审批的历史记录,不需删除时,不用处理;要求删除时,需删除撤回前的历史记录;
        String instanceId="2ac7e417-e2f5-11eb-9ffb-34f39ab07ea4";
        String canBackTaskId="2acc29dc-e2f5-11eb-9ffb-34f39ab07ea4";
        String userId="sp1";

        Tuple result = canBack(instanceId, canBackTaskId, userId);
        boolean canBack=result.get(0);
        HistoricTaskInstance currentTask=result.get(1);
        if(!canBack){
            log.debug("流程:{}-任务:{},已经处理,不可撤回",instanceId,canBackTaskId);
            return;
        }


        //流程撤回
        HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(instance.getProcessDefinitionId());
        HistoricTaskInstance canBackTask = historyService.createHistoricTaskInstanceQuery().taskId(canBackTaskId).taskAssignee(userId).singleResult();
        if(ObjectUtil.isEmpty(canBack)){
            log.debug("未找到要回退的任务");
            return;
        }

        FlowNode canBackNode = (FlowNode)bpmnModel.getFlowElement(canBackTask.getTaskDefinitionKey());
        FlowNode currentNode=(FlowNode)bpmnModel.getFlowElement(currentTask.getTaskDefinitionKey());

        //记录原始输出流程
        List<SequenceFlow> sourceOuts =new ArrayList<>();
        sourceOuts.addAll(currentNode.getOutgoingFlows());

        //清理活动方向
        currentNode.getOutgoingFlows().clear();

        //创建新流
        List<SequenceFlow> newFlows=new ArrayList<>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(currentNode);
        newSequenceFlow.setTargetFlowElement(canBackNode);
        newFlows.add(newSequenceFlow);
        currentNode.setOutgoingFlows(newFlows);

        //记录备注信息
        Authentication.setAuthenticatedUserId(userId);
        taskService.addComment(currentTask.getId(), currentTask.getProcessInstanceId(), "撤回");

        //完成任务
        taskService.complete(currentTask.getId());
        //恢复原方向
        currentNode.setOutgoingFlows(sourceOuts);

        //删除当前任务历史记录
        historyService.deleteHistoricTaskInstance(currentTask.getId());
    }

    /**
     * 判断流程是否能够撤回
     * 上一个节点是当前用户审核的,并且下一节点审批人还未处理时,可撤回到上一节点;
     * @return
     */
//    @Test
    public Tuple canBack(String instanceId,String canBackTaskId,String userId){
//        String instanceId="2ac7e417-e2f5-11eb-9ffb-34f39ab07ea4";
//        String canBackTaskId="2acc29dc-e2f5-11eb-9ffb-34f39ab07ea4";
//        String userId="sp1";

        boolean canBack=false;


        //查看流程历史节点
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(instanceId)
                .orderByHistoricTaskInstanceStartTime()
                .asc()
                .list();
        boolean hasUserTask=false;
        HistoricTaskInstance currentTask=null;
        for(HistoricTaskInstance task:list) {
            if(task.getId().equalsIgnoreCase(canBackTaskId)
                    &&task.getAssignee().equalsIgnoreCase(userId)){
                //找到了处理人处理的任务,查看下一个任务是否已经处理
                hasUserTask=true;
                continue;
            }

            if(hasUserTask){
                //上一个任务是当前人处理的,查看当前任务是否已经被处理
                hasUserTask=false;
                if(ObjectUtil.isEmpty(task.getEndTime())){
                    canBack=true;
                    currentTask=task;
                    break;
                }
            }
        }

        if(canBack){
            log.debug("未处理的流程可撤回,任务ID:{},任务接收人:{}",currentTask.getId(),currentTask.getAssignee());
        }

        //方法返回多个值,是否可回退,当前任务
        return new Tuple(canBack,currentTask);
    }

流程驳回-退回-退回到历史节点的任何节点

流程驳回,和流程撤回功能实现逻辑基本相同。
撤回功能是上一个节点审批人发起撤回;而驳回功能是当前审批节点人审核处理的,都可以通过修改当前审批节点的输出流进行处理,一般驳回功能需要记录历史记录,不会删除当前任务的历史记录。
具体驳回实现代码,这里不再记录,可借助撤回功能完成。

通过修改节点输出流向的操作,会发现,其实退回可以指定到任何节点上。
比如审批页面列出所有审核历史节点,可以选择历史任务节点,退回到选择的历史节点重新审批操作等功能。

流程挂起、作废

/**
     * 流程-作废(终止)、挂起(中止)
     */
    @Test
    public void deleteProcess(){
        String instanceId="2ac7e417-e2f5-11eb-9ffb-34f39ab07ea4";
        //流程挂起、激活
        runtimeService.suspendProcessInstanceById(instanceId);
        runtimeService.activateProcessInstanceById(instanceId);

        //作废-删除流程,删除流程历史记录
        runtimeService.deleteProcessInstance(instanceId,"删除流程实例");
        historyService.deleteHistoricProcessInstance(instanceId);
    }
  • 10
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值