springboot + flowable工作流
背景:项目涉及到审批,用工作流会合适一点。由于之前未接触过,因此选用在activiti基础上开发的flowable进行
需求:在springboot中引入flowable并封装操作(初次使用,仅供参考)
方法:
一、引入依赖
<dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>6.4.2</version> </dependency>
二、封装操作工具(FlowableUtil)
1 import com.hztech.framework.util.SpringBeanUtil; 2 import com.ruoyi.common.exception.CustomException; 3 import org.flowable.engine.ProcessEngine; 4 import org.flowable.engine.RuntimeService; 5 import org.flowable.engine.TaskService; 6 import org.flowable.engine.runtime.ProcessInstance; 7 import org.flowable.task.api.Task; 8 import org.jetbrains.annotations.NotNull; 9 10 import java.util.ArrayList; 11 import java.util.HashMap; 12 import java.util.List; 13 14 /** 15 * @ClassName FlowableUtil 16 * @Description 工作流工具 17 * @Author 包海鹏 18 * @Date 2020/4/27 14:45 19 * @Version 1.0 20 **/ 21 public class FlowableUtil { 22 23 /** 24 * 流程运行控制服务 25 */ 26 private RuntimeService runtimeService; 27 28 /** 29 * 任务管理服务 30 */ 31 private TaskService taskService; 32 33 /** 34 * 流程引擎 35 */ 36 private ProcessEngine processEngine; 37 38 /** 39 * 初始化获取实例 40 */ 41 public FlowableUtil() { 42 runtimeService = SpringBeanUtil.getBean(RuntimeService.class); 43 taskService = SpringBeanUtil.getBean(TaskService.class); 44 processEngine = SpringBeanUtil.getBean(ProcessEngine.class); 45 } 46 47 48 /** 49 * 启动流程 50 * 51 * @param processKey 流程定义key(流程图ID) 52 * @param businessKey 业务key 53 * @param map 参数键值对 54 * @return 流程实例ID 55 * @Author 包海鹏 56 */ 57 public String start(String processKey, String businessKey, HashMap<String, Object> map) { 58 59 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, businessKey, map); 60 return processInstance.getId(); 61 } 62 63 /** 64 * 终止流程 65 * 66 * @param processInstanceId 流程实例ID 67 * @param reason 终止理由 68 * @Author 包海鹏 69 */ 70 public void stop(String processInstanceId, String reason) { 71 72 runtimeService.deleteProcessInstance(processInstanceId, reason); 73 } 74 75 76 /** 77 * 获取指定用户的任务列表(创建时间倒序) 78 * 79 * @param userId 用户ID 80 * @return 任务列表 81 * @Author 包海鹏 82 */ 83 public List<Task> getListByUserId(String userId) { 84 85 List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list(); 86 for (Task task : tasks) { 87 System.out.println(task.toString()); 88 } 89 return tasks; 90 } 91 92 /** 93 * 获取指定用户组的任务列表 94 * 95 * @param group 用户组 96 * @return 任务列表 97 * @Author 包海鹏 98 */ 99 public List<Task> getListByGroup(String group) { 100 101 List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup(group).orderByTaskCreateTime().desc().list(); 102 for (Task task : tasks) { 103 System.out.println(task.toString()); 104 } 105 return tasks; 106 } 107 108 109 /** 110 * 完成指定任务 111 * 112 * @param taskId 任务ID 113 * @param map 变量键值对 114 * @Author 包海鹏 115 */ 116 public void complete(String taskId, HashMap<String, Object> map) { 117 118 Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); 119 if (task == null) { 120 throw new CustomException("流程不存在"); 121 } 122 taskService.complete(taskId, map); 123 } 124 125 /** 126 * 获取指定任务列表中的特定任务 127 * 128 * @param list 任务列表 129 * @param businessKey 业务key 130 * @return 任务 131 * @Author 包海鹏 132 */ 133 public Task getOneByBusinessKey(@NotNull List<Task> list, String businessKey) { 134 135 Task task = null; 136 for (Task t : list) { 137 // 通过任务对象获取流程实例 138 ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult(); 139 if (businessKey.equals(pi.getBusinessKey())) { 140 task = t; 141 } 142 } 143 return task; 144 } 145 146 /** 147 * 创建流程并完成第一个任务 148 * 149 * @param processKey 流程定义key(流程图ID) 150 * @param businessKey 业务key 151 * @param map 变量键值对 152 * @Author 包海鹏 153 */ 154 public void startAndComplete(String processKey, String businessKey, HashMap<String, Object> map) { 155 156 String processInstanceId = start(processKey, businessKey, map); 157 Task task = processEngine.getTaskService().createTaskQuery().processInstanceId(processInstanceId).singleResult(); 158 taskService.complete(task.getId(), map); 159 160 } 161 162 /** 163 * 退回到指定任务节点 164 * 165 * @param currentTaskId 当前任务ID 166 * @param targetTaskKey 目标任务节点key 167 * @Author 包海鹏 168 */ 169 public void backToStep(String currentTaskId, String targetTaskKey) { 170 171 Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult(); 172 if (currentTask == null) { 173 throw new CustomException("当前任务节点不存在"); 174 } 175 List<String> currentTaskKeys = new ArrayList<>(); 176 currentTaskKeys.add(currentTask.getTaskDefinitionKey()); 177 runtimeService.createChangeActivityStateBuilder().processInstanceId(currentTask.getProcessInstanceId()).moveActivityIdsToSingleActivityId(currentTaskKeys, targetTaskKey); 178 } 179 }
二、封装业务工具(ExitUtil、PlanUtil)
1 import com.hztech.mscm.util.FlowableUtil; 2 import org.flowable.task.api.Task; 3 4 import java.util.HashMap; 5 import java.util.List; 6 7 /** 8 * @ClassName PlanUtil 9 * @Description 出库模块工作流工具 10 * @Author 包海鹏 11 * @Date 2020/3/11 15:37 12 * @Version 1.0 13 **/ 14 public class ExitUtil { 15 16 private static final String EXIT_PROCESS_KEY = "exit"; 17 18 19 /** 20 * 提交 21 * 22 * @param inputUserId 申请人ID 23 * @param audiUserId 审核人ID 24 * @param exitId 出库单ID 25 */ 26 public static void submit(String inputUserId, String audiUserId, String exitId) { 27 28 if (inputUserId.isEmpty() || audiUserId.isEmpty() || exitId.isEmpty()) { 29 throw new RuntimeException("【saveAndSubmit】参数缺失!"); 30 } 31 32 HashMap<String, Object> map = new HashMap<>(); 33 map.put("inputUserId", inputUserId); 34 map.put("audiUserId", audiUserId); 35 FlowableUtil util = new FlowableUtil(); 36 util.startAndComplete(EXIT_PROCESS_KEY, exitId, map); 37 } 38 39 /** 40 * 通过-审核 41 * 42 * @param userId 审核操作人ID 43 * @param exitId 出库单ID 44 */ 45 public static void successApplyDepartment(String userId, String exitId) { 46 47 HashMap<String, Object> map = new HashMap<>(); 48 map.put("outcome", "YES"); 49 apply(userId, exitId, map); 50 } 51 52 /** 53 * 拒绝-审核 54 * 55 * @param userId 审核操作人ID 56 * @param exitId 采购计划ID 57 */ 58 public static void failApplyDepartment(String userId, String exitId) { 59 60 HashMap<String, Object> map = new HashMap<>(); 61 map.put("outcome", "NO"); 62 apply(userId, exitId, map); 63 } 64 65 66 /** 67 * 申请处理方法 68 * 69 * @param userId 申请操作人ID 70 * @param exitId 出库单ID 71 * @param map 变量组 72 */ 73 private static void apply(String userId, String exitId, HashMap<String, Object> map) { 74 75 FlowableUtil util = new FlowableUtil(); 76 List<Task> list = util.getTaskList(userId); 77 Task task = util.getOneTask(list, exitId); 78 if (null != task) { 79 util.complete(task.getId(), map); 80 } 81 82 } 83 }
1 import com.hztech.mscm.util.FlowableUtil; 2 import org.flowable.task.api.Task; 3 4 import java.util.HashMap; 5 import java.util.List; 6 7 /** 8 * @ClassName PlanUtil 9 * @Description 采购模块工作流工具 10 * @Author 包海鹏 11 * @Date 2020/3/11 15:37 12 * @Version 1.0 13 **/ 14 public class PlanUtil { 15 16 private static final String PLAN_PROCESS_KEY = "plan"; 17 18 19 /** 20 * 提交 21 * 22 * @param inputUserId 采购申请人ID 23 * @param departmentUserId 部门审核人ID 24 * @param planId 采购计划ID 25 */ 26 public static void submit(String inputUserId, String departmentUserId, String planId) { 27 28 if (inputUserId.isEmpty() || departmentUserId.isEmpty() || planId.isEmpty()) { 29 throw new RuntimeException("【saveAndSubmit】参数缺失!"); 30 } 31 32 HashMap<String, Object> map = new HashMap<>(); 33 map.put("inputUserId", inputUserId); 34 map.put("departmentUserId", departmentUserId); 35 FlowableUtil util = new FlowableUtil(); 36 util.startAndComplete(PLAN_PROCESS_KEY, planId, map); 37 } 38 39 /** 40 * 通过-部门审核 41 * 42 * @param userId 审核操作人ID 43 * @param companyUserId 公司审批人ID 44 * @param planId 采购计划ID 45 */ 46 public static void successApplyDepartment(String userId, String companyUserId, String planId) { 47 48 HashMap<String, Object> map = new HashMap<>(); 49 map.put("companyUserId", companyUserId); 50 map.put("outcome", "YES"); 51 apply(userId, planId, map); 52 } 53 54 /** 55 * 拒绝-部门审核 56 * 57 * @param userId 审核操作人ID 58 * @param planId 采购计划ID 59 */ 60 public static void failApplyDepartment(String userId, String planId) { 61 62 HashMap<String, Object> map = new HashMap<>(); 63 map.put("outcome", "NO"); 64 apply(userId, planId, map); 65 } 66 67 /** 68 * 通过-公司审批 69 * 70 * @param userId 审批操作人ID 71 * @param planId 采购计划ID 72 */ 73 public static void successApplyCompany(String userId, String planId) { 74 75 HashMap<String, Object> map = new HashMap<>(); 76 map.put("outcome", "YES"); 77 apply(userId, planId, map); 78 } 79 80 /** 81 * 拒绝-公司审批 82 * 83 * @param userId 审批操作人ID 84 * @param planId 采购计划ID 85 */ 86 public static void failApplyCompany(String userId, String planId) { 87 88 HashMap<String, Object> map = new HashMap<>(); 89 map.put("outcome", "NO"); 90 apply(userId, planId, map); 91 } 92 93 /** 94 * 申请处理方法 95 * 96 * @param userId 申请操作人ID 97 * @param planId 采购计划ID 98 * @param map 变量组 99 */ 100 private static void apply(String userId, String planId, HashMap<String, Object> map) { 101 102 FlowableUtil util = new FlowableUtil(); 103 List<Task> list = util.getTaskList(userId); 104 Task task = util.getOneTask(list, planId); 105 if (null != task) { 106 util.complete(task.getId(), map); 107 } 108 109 } 110 }
三、放置流程图
1 <?xml version="1.0" encoding="UTF-8"?> 2 <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef"> 3 <process id="exit" name="出库" isExecutable="true"> 4 <startEvent id="startEvent1"></startEvent> 5 <userTask id="sid-84B1745B-2537-454B-BA36-2C857AAA1970" name="创建出库单" flowable:assignee="${inputUserId}"> 6 <extensionElements> 7 <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete> 8 </extensionElements> 9 </userTask> 10 <sequenceFlow id="sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C" sourceRef="startEvent1" targetRef="sid-84B1745B-2537-454B-BA36-2C857AAA1970"></sequenceFlow> 11 <userTask id="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" name="审核" flowable:assignee="${audiUserId}"> 12 <extensionElements> 13 <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete> 14 </extensionElements> 15 </userTask> 16 <sequenceFlow id="sid-51E82709-526B-49A3-95D1-483934328025" sourceRef="sid-84B1745B-2537-454B-BA36-2C857AAA1970" targetRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E"></sequenceFlow> 17 <endEvent id="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44"></endEvent> 18 <sequenceFlow id="sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7" sourceRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" targetRef="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44"> 19 <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome="NO"}]]></conditionExpression> 20 </sequenceFlow> 21 <sequenceFlow id="sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2" sourceRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" targetRef="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44"> 22 <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome="YES"}]]></conditionExpression> 23 </sequenceFlow> 24 </process> 25 <bpmndi:BPMNDiagram id="BPMNDiagram_exit"> 26 <bpmndi:BPMNPlane bpmnElement="exit" id="BPMNPlane_exit"> 27 <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1"> 28 <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds> 29 </bpmndi:BPMNShape> 30 <bpmndi:BPMNShape bpmnElement="sid-84B1745B-2537-454B-BA36-2C857AAA1970" id="BPMNShape_sid-84B1745B-2537-454B-BA36-2C857AAA1970"> 31 <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds> 32 </bpmndi:BPMNShape> 33 <bpmndi:BPMNShape bpmnElement="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" id="BPMNShape_sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E"> 34 <omgdc:Bounds height="80.0" width="100.0" x="320.0" y="138.0"></omgdc:Bounds> 35 </bpmndi:BPMNShape> 36 <bpmndi:BPMNShape bpmnElement="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44" id="BPMNShape_sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44"> 37 <omgdc:Bounds height="28.0" width="28.0" x="540.0" y="164.0"></omgdc:Bounds> 38 </bpmndi:BPMNShape> 39 <bpmndi:BPMNEdge bpmnElement="sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7" id="BPMNEdge_sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7"> 40 <omgdi:waypoint x="370.0" y="217.95000000000002"></omgdi:waypoint> 41 <omgdi:waypoint x="370.0" y="273.0"></omgdi:waypoint> 42 <omgdi:waypoint x="554.0" y="273.0"></omgdi:waypoint> 43 <omgdi:waypoint x="554.0" y="191.94993609491092"></omgdi:waypoint> 44 </bpmndi:BPMNEdge> 45 <bpmndi:BPMNEdge bpmnElement="sid-51E82709-526B-49A3-95D1-483934328025" id="BPMNEdge_sid-51E82709-526B-49A3-95D1-483934328025"> 46 <omgdi:waypoint x="274.9499999999907" y="178.0"></omgdi:waypoint> 47 <omgdi:waypoint x="319.9999999999807" y="178.0"></omgdi:waypoint> 48 </bpmndi:BPMNEdge> 49 <bpmndi:BPMNEdge bpmnElement="sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C" id="BPMNEdge_sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C"> 50 <omgdi:waypoint x="129.9499984899576" y="178.0"></omgdi:waypoint> 51 <omgdi:waypoint x="174.9999999999917" y="178.0"></omgdi:waypoint> 52 </bpmndi:BPMNEdge> 53 <bpmndi:BPMNEdge bpmnElement="sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2" id="BPMNEdge_sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2"> 54 <omgdi:waypoint x="419.9499999999156" y="178.0"></omgdi:waypoint> 55 <omgdi:waypoint x="540.0" y="178.0"></omgdi:waypoint> 56 </bpmndi:BPMNEdge> 57 </bpmndi:BPMNPlane> 58 </bpmndi:BPMNDiagram> 59 </definitions>
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.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" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef"> <process id="plan" name="采购" isExecutable="true"> <documentation>采购流程</documentation> <startEvent id="startEvent1"></startEvent> <userTask id="makePlan" name="编写采购单" flowable:assignee="${inputUserId}"> <extensionElements> <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete> </extensionElements> </userTask> <sequenceFlow id="sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB" sourceRef="startEvent1" targetRef="makePlan"></sequenceFlow> <userTask id="department" name="部门审核" flowable:assignee="${departmentUserId}"> <extensionElements> <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete> </extensionElements> </userTask> <userTask id="company" name="公司审批" flowable:assignee="${companyUserId}"> <extensionElements> <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete> </extensionElements> </userTask> <endEvent id="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5" name="结束"></endEvent> <sequenceFlow id="f1" sourceRef="makePlan" targetRef="department"></sequenceFlow> <sequenceFlow id="departmentYes" name="通过" sourceRef="department" targetRef="company"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="YES"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="companyYes" name="通过" sourceRef="company" targetRef="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="YES"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="departmentNo" name="拒绝" sourceRef="department" targetRef="makePlan"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="NO"}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="companyNo" name="拒绝" sourceRef="company" targetRef="makePlan"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="NO"}]]></conditionExpression> </sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_plan"> <bpmndi:BPMNPlane bpmnElement="plan" id="BPMNPlane_plan"> <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1"> <omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="makePlan" id="BPMNShape_makePlan"> <omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="department" id="BPMNShape_department"> <omgdc:Bounds height="80.0" width="100.0" x="320.0" y="138.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="company" id="BPMNShape_company"> <omgdc:Bounds height="80.0" width="100.0" x="465.0" y="138.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5" id="BPMNShape_sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5"> <omgdc:Bounds height="28.0" width="28.0" x="610.0" y="164.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="companyYes" id="BPMNEdge_companyYes"> <omgdi:waypoint x="564.95" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="610.0" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="companyNo" id="BPMNEdge_companyNo"> <omgdi:waypoint x="515.0" y="138.0"></omgdi:waypoint> <omgdi:waypoint x="515.0" y="56.0"></omgdi:waypoint> <omgdi:waypoint x="225.0" y="56.0"></omgdi:waypoint> <omgdi:waypoint x="225.0" y="138.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB" id="BPMNEdge_sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB"> <omgdi:waypoint x="129.9499984899576" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="174.9999999999917" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="departmentYes" id="BPMNEdge_departmentYes"> <omgdi:waypoint x="419.94999999999067" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="464.9999999999807" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="departmentNo" id="BPMNEdge_departmentNo"> <omgdi:waypoint x="370.0" y="217.95000000000002"></omgdi:waypoint> <omgdi:waypoint x="370.0" y="296.0"></omgdi:waypoint> <omgdi:waypoint x="225.0" y="296.0"></omgdi:waypoint> <omgdi:waypoint x="225.0" y="217.95000000000002"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="f1" id="BPMNEdge_f1"> <omgdi:waypoint x="274.9499999999907" y="178.0"></omgdi:waypoint> <omgdi:waypoint x="319.9999999999807" y="178.0"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>