Activiti6---process endorsement consultation implementation

1. endorsement

An endorsement means that after the current node is approved, an additional approver needs to be added for approval. After the additional approval user is approved, the process flows to the next node. For example, the normal approval process is A->B->C, if B executes the signature action, then the process becomes A->B-->D-->C, and node D is added.

In medicine, there is a panacea called a placebo. It has no drug effect. It may be just a candy, but the patient does not know it, but it plays a role because of the patient’s trust in the doctor, the patient’s self-suggestion, and the expectation of the efficacy of a certain drug. It has an analgesic, anti-dip or relief effect. Why is this mentioned? Because the endorsement plan is a placebo plan. The user perceives the endorsement from the approval history. When doing the endorsement operation, the approval history records the endorsement action, but it is executed in the background The reassign operation reassigns the current process to another person to achieve the effect of signing, so signing is just one line of code:

taskService.setAssignee(task.getTaskId(), user);  

This may have the following problems:

The flow chart cannot reflect the endorsement, because no new nodes are generated

If your system is ready to transform activiti, then the standard activiti flow chart is far from meeting your needs, and you need additional plan to record the approval history to draw the flow chart.

2. Consultation

Consultation means that you are not very clear about the current process. You need to forward the process to another person and need another person to give you guidance. After the other person approves the process, the process will come back to you, and you will approve it based on his approval comments. . Simply put, if the normal approval process is A->B->C, if B performs the inquiry operation, then the process becomes A->B-->D-->B->C. The difference between inquiry and endorsement is that the inquiry will return to the node that initiated the inquiry, and the endorsement will not.

Consultation is two reallocations:

  1. B is reassigned to D
  2. D is reassigned to B

Consultation can be realized by two reassign operations. The problem to be solved is how to coordinate these two reallocations.

  1. When B performs the inquiry operation, the inquiry action is marked by the variable, and the information of the inquiry person B (mainly the account number) is stored in the variable

  2. When D executes the reply operation (after the process becomes the inquiry, the inquired person only has the right to reply), take out the account of B from the variable, and re-assign the process to B

  3. B performs normal approval operations, and the process flows normally.

3. Testing

Design flow chart
Insert picture description here
Bpmn file:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1597390628483" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="consultation" isClosed="false" isExecutable="true" processType="None">
    <startEvent id="_2" name="开始"/>
    <userTask activiti:assignee="A" activiti:exclusive="true" id="_3" name="A"/>
    <userTask activiti:assignee="B" activiti:exclusive="true" id="_4" name="B"/>
    <userTask activiti:assignee="C" activiti:exclusive="true" id="_5" name="C"/>
    <endEvent id="_6" name="结束"/>
    <sequenceFlow id="_7" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_8" sourceRef="_3" targetRef="_4"/>
    <sequenceFlow id="_9" sourceRef="_4" targetRef="_5"/>
    <sequenceFlow id="_10" sourceRef="_5" targetRef="_6"/>

  </process>
  <bpmndi:BPMNDiagram documentation="background=#000000;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="consultation">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <omgdc:Bounds height="32.0" width="32.0" x="20.0" y="315.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <omgdc:Bounds height="55.0" width="85.0" x="140.0" y="305.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
        <omgdc:Bounds height="55.0" width="85.0" x="315.0" y="305.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <omgdc:Bounds height="55.0" width="85.0" x="500.0" y="305.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_6" id="Shape-_6">
        <omgdc:Bounds height="32.0" width="32.0" x="645.0" y="315.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_11" id="Shape-_11">
        <omgdc:Bounds height="55.0" width="85.0" x="315.0" y="140.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_2" targetElement="_3">
        <omgdi:waypoint x="52.0" y="331.0"/>
        <omgdi:waypoint x="140.0" y="332.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_3" targetElement="_4">
        <omgdi:waypoint x="225.0" y="332.5"/>
        <omgdi:waypoint x="315.0" y="332.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9" sourceElement="_4" targetElement="_5">
        <omgdi:waypoint x="400.0" y="332.5"/>
        <omgdi:waypoint x="500.0" y="332.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10" sourceElement="_5" targetElement="_6">
        <omgdi:waypoint x="585.0" y="332.5"/>
        <omgdi:waypoint x="645.0" y="331.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

Test category:

package com.yb;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @author [email protected]
 * @version 1.0
 * @date 2020/8/5
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class ActivitiJpaTest09 {
    
    

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private TaskService taskService;
    @Resource
    private HistoryService historyService;

    @Resource
    private HttpServletRequest request;

    /**
     * 部署流程,测试征询
     */
    @Test
    public void repositoryDeploy(){
    
    
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("processes/activiti_Consultation.bpmn")
                .addClasspathResource("processes/activiti_Consultation.png")
                .name("测试征询-2")
                .deploy();
        System.out.println("部署ID:"+deploy.getId());
        System.out.println("部署名称"+deploy.getName());
    }

    /**
     * 发布流程
     */
    @Test
    public void runtimeRelease(){
    
    

        ProcessInstance pi = runtimeService.startProcessInstanceByKey("consultation");
        System.out.println("流程实例ID:"+pi.getId());
        System.out.println("流程定义ID:"+pi.getProcessDefinitionId());
    }

    /**
     * 查询及完成任务
     */
    @Test
    public void taskQueryComplete(){
    
    
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee("A")
                .list();
        for (Task task : list) {
    
    
            System.out.println("--------------------------------------------");
            System.out.println("任务ID:" + task.getId());
            System.out.println("任务名称:" + task.getName());
            System.out.println("任务创建时间:" + task.getCreateTime());
            System.out.println("任务委派人:" + task.getAssignee());
            System.out.println("流程实例ID:" + task.getProcessInstanceId());
            System.out.println("--------------------------------------------");
            taskService.complete(task.getId());
        }
    }





    /**
     *征询
     */
    @Test
    public void taskQueryComplete2(){
    
    

        Task task = taskService.createTaskQuery()
                .taskAssignee("B")
                .singleResult();
        taskService.setAssignee(task.getId(),"D");

        //对被征询者做出记录
        taskService.setVariableLocal(task.getId(),"status","D");
        //对发出征询者做出记录
        taskService.setVariableLocal(task.getId(),"originUser","B");


    }

    /**
     * D执行回复操作
     */
    @Test
    public void reply(){
    
    

        String originUser = (String)
                taskService.getVariableLocal("5002", "originUser");
        System.out.println(originUser);

        taskService.setAssignee("5002",originUser);
        taskService.removeVariable("5002", "status");
        taskService.removeVariable("5002", "originUser");
    }
}

Database:
Basically the simple process of sending out the inquiry and reply:
Insert picture description here
save the information of the approver who sent out the inquiry and reply in the database:
Insert picture description here
Description:
After the test is completed, in order to add functions in case 4 later , the current approver can consult others when they don't know how to approve, and others will reply, and the current approver will perform the next approval based on the content of the reply. That is to ask for and sign function. Follow-up update case 4.

Guess you like

Origin blog.csdn.net/Lv_vI/article/details/108005678