Commit e01acfb18e12915523b293c81e386a1cb87c6242
1 parent
41e4283f
工作流 Flowable 任务自定义 Script 脚本 相关实现
Showing
13 changed files
with
307 additions
and
54 deletions
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java
| 1 | package cn.iocoder.yudao.framework.flowable.core.util; | 1 | package cn.iocoder.yudao.framework.flowable.core.util; |
| 2 | 2 | ||
| 3 | +import org.flowable.bpmn.converter.BpmnXMLConverter; | ||
| 4 | +import org.flowable.bpmn.model.BpmnModel; | ||
| 5 | +import org.flowable.bpmn.model.FlowElement; | ||
| 3 | import org.flowable.common.engine.impl.identity.Authentication; | 6 | import org.flowable.common.engine.impl.identity.Authentication; |
| 4 | 7 | ||
| 8 | +import java.util.ArrayList; | ||
| 9 | +import java.util.Arrays; | ||
| 10 | +import java.util.List; | ||
| 11 | + | ||
| 5 | public class FlowableUtils { | 12 | public class FlowableUtils { |
| 6 | 13 | ||
| 7 | public static void setAuthenticatedUserId(Long userId) { | 14 | public static void setAuthenticatedUserId(Long userId) { |
| @@ -11,4 +18,45 @@ public class FlowableUtils { | @@ -11,4 +18,45 @@ public class FlowableUtils { | ||
| 11 | public static void clearAuthenticatedUserId() { | 18 | public static void clearAuthenticatedUserId() { |
| 12 | Authentication.setAuthenticatedUserId(null); | 19 | Authentication.setAuthenticatedUserId(null); |
| 13 | } | 20 | } |
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 获得 BPMN 流程中,指定的元素们 | ||
| 24 | + * | ||
| 25 | + * @param model | ||
| 26 | + * @param clazz 指定元素。例如说,{@link org.flowable.bpmn.model.UserTask}、{@link org.flowable.bpmn.model.Gateway} 等等 | ||
| 27 | + * @return 元素们 | ||
| 28 | + */ | ||
| 29 | + public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) { | ||
| 30 | + List<T> result = new ArrayList<>(); | ||
| 31 | + model.getProcesses().forEach(process -> { | ||
| 32 | + process.getFlowElements().forEach(flowElement -> { | ||
| 33 | + if (flowElement.getClass().isAssignableFrom(clazz)) { | ||
| 34 | + result.add((T) flowElement); | ||
| 35 | + } | ||
| 36 | + }); | ||
| 37 | + }); | ||
| 38 | + return result; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * 比较 两个bpmnModel 是否相同 | ||
| 43 | + * @param oldModel 老的bpmn model | ||
| 44 | + * @param newModel 新的bpmn model | ||
| 45 | + */ | ||
| 46 | + public static boolean equals(BpmnModel oldModel, BpmnModel newModel) { | ||
| 47 | + // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较 | ||
| 48 | + return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel)); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * 把 bpmnModel 转换成 byte[] | ||
| 53 | + * @param model bpmnModel | ||
| 54 | + */ | ||
| 55 | + public static byte[] getBpmnBytes(BpmnModel model) { | ||
| 56 | + if (model == null) { | ||
| 57 | + return new byte[0]; | ||
| 58 | + } | ||
| 59 | + BpmnXMLConverter converter = new BpmnXMLConverter(); | ||
| 60 | + return converter.convertToXML(model); | ||
| 61 | + } | ||
| 14 | } | 62 | } |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java
| 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.config; | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.config; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; | 3 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; |
| 4 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | ||
| 4 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmProcessInstanceEventListener; | 5 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.listener.BpmProcessInstanceEventListener; |
| 5 | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | 6 | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; |
| 6 | import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; | 7 | import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; |
| @@ -27,8 +28,9 @@ import java.util.List; | @@ -27,8 +28,9 @@ import java.util.List; | ||
| 27 | public class BpmFlowableConfiguration { | 28 | public class BpmFlowableConfiguration { |
| 28 | 29 | ||
| 29 | /** | 30 | /** |
| 30 | - * 将自定义 listener 加入全局listener | 31 | + * Flowable engines 自定义的配置 |
| 31 | * @param listeners 自定义 listener | 32 | * @param listeners 自定义 listener |
| 33 | + * @param bpmActivityBehaviorFactory 自定义的 ActivityBehaviorFactory 实现 | ||
| 32 | */ | 34 | */ |
| 33 | @Bean | 35 | @Bean |
| 34 | public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> addCustomerListenerConfigurer (ObjectProvider<FlowableEventListener> listeners, | 36 | public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> addCustomerListenerConfigurer (ObjectProvider<FlowableEventListener> listeners, |
| @@ -51,14 +53,15 @@ public class BpmFlowableConfiguration { | @@ -51,14 +53,15 @@ public class BpmFlowableConfiguration { | ||
| 51 | BpmUserGroupService userGroupService, | 53 | BpmUserGroupService userGroupService, |
| 52 | PermissionApi permissionApi, | 54 | PermissionApi permissionApi, |
| 53 | DeptApi deptApi, | 55 | DeptApi deptApi, |
| 54 | - AdminUserApi adminUserApi) { | 56 | + AdminUserApi adminUserApi, |
| 57 | + List<BpmTaskAssignScript> scripts) { | ||
| 55 | BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); | 58 | BpmActivityBehaviorFactory bpmActivityBehaviorFactory = new BpmActivityBehaviorFactory(); |
| 56 | bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService); | 59 | bpmActivityBehaviorFactory.setBpmTaskRuleService(taskRuleService); |
| 57 | bpmActivityBehaviorFactory.setUserGroupService(userGroupService); | 60 | bpmActivityBehaviorFactory.setUserGroupService(userGroupService); |
| 58 | bpmActivityBehaviorFactory.setAdminUserApi(adminUserApi); | 61 | bpmActivityBehaviorFactory.setAdminUserApi(adminUserApi); |
| 59 | bpmActivityBehaviorFactory.setPermissionApi(permissionApi); | 62 | bpmActivityBehaviorFactory.setPermissionApi(permissionApi); |
| 60 | bpmActivityBehaviorFactory.setDeptApi(deptApi); | 63 | bpmActivityBehaviorFactory.setDeptApi(deptApi); |
| 61 | -// bpmActivityBehaviorFactory.setScripts(scripts); | 64 | + bpmActivityBehaviorFactory.setScripts(scripts); |
| 62 | return bpmActivityBehaviorFactory; | 65 | return bpmActivityBehaviorFactory; |
| 63 | } | 66 | } |
| 64 | } | 67 | } |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmActivityBehaviorFactory.java
| 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; | 1 | package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | ||
| 3 | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | 4 | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; |
| 4 | import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; | 5 | import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; |
| 5 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; | 6 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| @@ -13,6 +14,8 @@ import org.flowable.bpmn.model.UserTask; | @@ -13,6 +14,8 @@ import org.flowable.bpmn.model.UserTask; | ||
| 13 | import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; | 14 | import org.flowable.engine.impl.bpmn.behavior.UserTaskActivityBehavior; |
| 14 | import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; | 15 | import org.flowable.engine.impl.bpmn.parser.factory.DefaultActivityBehaviorFactory; |
| 15 | 16 | ||
| 17 | +import java.util.List; | ||
| 18 | + | ||
| 16 | /** | 19 | /** |
| 17 | * 自定义的 ActivityBehaviorFactory 实现类,目的如下: | 20 | * 自定义的 ActivityBehaviorFactory 实现类,目的如下: |
| 18 | * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配 | 21 | * 1. 自定义 {@link #createUserTaskActivityBehavior(UserTask)}:实现自定义的流程任务的 assignee 负责人的分配 |
| @@ -35,6 +38,8 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { | @@ -35,6 +38,8 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { | ||
| 35 | private DeptApi deptApi; | 38 | private DeptApi deptApi; |
| 36 | @Setter | 39 | @Setter |
| 37 | private AdminUserApi adminUserApi; | 40 | private AdminUserApi adminUserApi; |
| 41 | + @Setter | ||
| 42 | + private List<BpmTaskAssignScript> scripts; | ||
| 38 | 43 | ||
| 39 | @Override | 44 | @Override |
| 40 | public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { | 45 | public UserTaskActivityBehavior createUserTaskActivityBehavior(UserTask userTask) { |
| @@ -44,8 +49,7 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { | @@ -44,8 +49,7 @@ public class BpmActivityBehaviorFactory extends DefaultActivityBehaviorFactory { | ||
| 44 | userTaskActivityBehavior.setDeptApi(deptApi); | 49 | userTaskActivityBehavior.setDeptApi(deptApi); |
| 45 | userTaskActivityBehavior.setUserGroupService(userGroupService); | 50 | userTaskActivityBehavior.setUserGroupService(userGroupService); |
| 46 | userTaskActivityBehavior.setAdminUserApi(adminUserApi); | 51 | userTaskActivityBehavior.setAdminUserApi(adminUserApi); |
| 47 | - //TODO | ||
| 48 | - //userTaskActivityBehavior.setScripts(scripts); | 52 | + userTaskActivityBehavior.setScripts(scripts); |
| 49 | return userTaskActivityBehavior; | 53 | return userTaskActivityBehavior; |
| 50 | } | 54 | } |
| 51 | } | 55 | } |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmUserTaskActivityBehavior.java
| @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | ||
| 7 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; | 7 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; |
| 8 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; | 8 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; |
| 9 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; | 9 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskAssignRuleTypeEnum; |
| 10 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | ||
| 10 | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; | 11 | import cn.iocoder.yudao.module.bpm.service.definition.BpmTaskAssignRuleService; |
| 11 | import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; | 12 | import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; |
| 12 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; | 13 | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| @@ -30,8 +31,10 @@ import org.flowable.task.service.impl.persistence.entity.TaskEntity; | @@ -30,8 +31,10 @@ import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||
| 30 | import java.util.*; | 31 | import java.util.*; |
| 31 | 32 | ||
| 32 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 33 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 34 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | ||
| 33 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | 35 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 34 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | 36 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 37 | +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_ASSIGN_SCRIPT_NOT_EXISTS; | ||
| 35 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER; | 38 | import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER; |
| 36 | 39 | ||
| 37 | /** | 40 | /** |
| @@ -56,9 +59,17 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { | @@ -56,9 +59,17 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { | ||
| 56 | @Setter | 59 | @Setter |
| 57 | private PermissionApi permissionApi; | 60 | private PermissionApi permissionApi; |
| 58 | 61 | ||
| 62 | + /** | ||
| 63 | + * 任务分配脚本 | ||
| 64 | + */ | ||
| 65 | + private Map<Long, BpmTaskAssignScript> scriptMap = Collections.emptyMap(); | ||
| 66 | + | ||
| 59 | public BpmUserTaskActivityBehavior(UserTask userTask) { | 67 | public BpmUserTaskActivityBehavior(UserTask userTask) { |
| 60 | super(userTask); | 68 | super(userTask); |
| 61 | } | 69 | } |
| 70 | + public void setScripts(List<BpmTaskAssignScript> scripts) { | ||
| 71 | + this.scriptMap = convertMap(scripts, script -> script.getEnum().getId()); | ||
| 72 | + } | ||
| 62 | 73 | ||
| 63 | @Override | 74 | @Override |
| 64 | protected void handleAssignments(TaskService taskService, String assignee, String owner, List<String> candidateUsers, List<String> candidateGroups, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) { | 75 | protected void handleAssignments(TaskService taskService, String assignee, String owner, List<String> candidateUsers, List<String> candidateGroups, TaskEntity task, ExpressionManager expressionManager, DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) { |
| @@ -100,10 +111,9 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { | @@ -100,10 +111,9 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { | ||
| 100 | assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); | 111 | assigneeUserIds = calculateTaskCandidateUsersByUser(task, rule); |
| 101 | } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) { | 112 | } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.USER_GROUP.getType(), rule.getType())) { |
| 102 | assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule); | 113 | assigneeUserIds = calculateTaskCandidateUsersByUserGroup(task, rule); |
| 114 | + } else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) { | ||
| 115 | + assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule); | ||
| 103 | } | 116 | } |
| 104 | -// else if (Objects.equals(BpmTaskAssignRuleTypeEnum.SCRIPT.getType(), rule.getType())) { | ||
| 105 | -// assigneeUserIds = calculateTaskCandidateUsersByScript(task, rule); | ||
| 106 | -// } | ||
| 107 | 117 | ||
| 108 | // 移除被禁用的用户 | 118 | // 移除被禁用的用户 |
| 109 | removeDisableUsers(assigneeUserIds); | 119 | removeDisableUsers(assigneeUserIds); |
| @@ -146,6 +156,22 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { | @@ -146,6 +156,22 @@ public class BpmUserTaskActivityBehavior extends UserTaskActivityBehavior { | ||
| 146 | return userIds; | 156 | return userIds; |
| 147 | } | 157 | } |
| 148 | 158 | ||
| 159 | + private Set<Long> calculateTaskCandidateUsersByScript(TaskEntity task, BpmTaskAssignRuleDO rule) { | ||
| 160 | + // 获得对应的脚本 | ||
| 161 | + List<BpmTaskAssignScript> scripts = new ArrayList<>(rule.getOptions().size()); | ||
| 162 | + rule.getOptions().forEach(id -> { | ||
| 163 | + BpmTaskAssignScript script = scriptMap.get(id); | ||
| 164 | + if (script == null) { | ||
| 165 | + throw exception(TASK_ASSIGN_SCRIPT_NOT_EXISTS, id); | ||
| 166 | + } | ||
| 167 | + scripts.add(script); | ||
| 168 | + }); | ||
| 169 | + // 逐个计算任务 | ||
| 170 | + Set<Long> userIds = new HashSet<>(); | ||
| 171 | + scripts.forEach(script -> CollUtil.addAll(userIds, script.calculateTaskCandidateUsers(task))); | ||
| 172 | + return userIds; | ||
| 173 | + } | ||
| 174 | + | ||
| 149 | private Long chooseTaskAssignee(Set<Long> candidateUserIds) { | 175 | private Long chooseTaskAssignee(Set<Long> candidateUserIds) { |
| 150 | // TODO 芋艿:未来可以优化下,改成轮询的策略 | 176 | // TODO 芋艿:未来可以优化下,改成轮询的策略 |
| 151 | int index = RandomUtil.randomInt(candidateUserIds.size()); | 177 | int index = RandomUtil.randomInt(candidateUserIds.size()); |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/BpmTaskAssignScript.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; | ||
| 4 | +import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||
| 5 | + | ||
| 6 | +import java.util.Set; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * Bpm 任务分配的自定义 Script 脚本 | ||
| 10 | + * 使用场景: | ||
| 11 | + * 1. 设置审批人为发起人 | ||
| 12 | + * 2. 设置审批人为发起人的 Leader | ||
| 13 | + * 3. 甚至审批人为发起人的 Leader 的 Leader | ||
| 14 | + * | ||
| 15 | + * @author 芋道源码 | ||
| 16 | + */ | ||
| 17 | +public interface BpmTaskAssignScript { | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 基于流程任务,获得任务的候选用户们 | ||
| 21 | + * | ||
| 22 | + * @param task 任务 | ||
| 23 | + * @return 候选人用户的编号数组 | ||
| 24 | + */ | ||
| 25 | + Set<Long> calculateTaskCandidateUsers(TaskEntity task); | ||
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 获得枚举值 | ||
| 29 | + * | ||
| 30 | + * @return 枚举值 | ||
| 31 | + */ | ||
| 32 | + BpmTaskRuleScriptEnum getEnum(); | ||
| 33 | +} | ||
| 34 | + |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderAbstractScript.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||
| 4 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | ||
| 5 | +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | ||
| 6 | +import cn.iocoder.yudao.module.system.api.dept.DeptApi; | ||
| 7 | +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; | ||
| 8 | +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; | ||
| 9 | +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; | ||
| 10 | + | ||
| 11 | +import org.flowable.engine.runtime.ProcessInstance; | ||
| 12 | +import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||
| 13 | +import org.springframework.context.annotation.Lazy; | ||
| 14 | +import org.springframework.util.Assert; | ||
| 15 | + | ||
| 16 | +import javax.annotation.Resource; | ||
| 17 | +import java.util.Set; | ||
| 18 | + | ||
| 19 | +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; | ||
| 20 | +import static java.util.Collections.emptySet; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * 分配给发起人的 Leader 审批的 Script 实现类 | ||
| 24 | + * 目前 Leader 的定义是, | ||
| 25 | + * | ||
| 26 | + * @author 芋道源码 | ||
| 27 | + */ | ||
| 28 | +public abstract class BpmTaskAssignLeaderAbstractScript implements BpmTaskAssignScript { | ||
| 29 | + | ||
| 30 | + @Resource | ||
| 31 | + private AdminUserApi adminUserApi; | ||
| 32 | + @Resource | ||
| 33 | + private DeptApi deptApi; | ||
| 34 | + @Resource | ||
| 35 | + @Lazy // 解决循环依赖 | ||
| 36 | + private BpmProcessInstanceService bpmProcessInstanceService; | ||
| 37 | + | ||
| 38 | + protected Set<Long> calculateTaskCandidateUsers(TaskEntity task, int level) { | ||
| 39 | + Assert.isTrue(level > 0, "level 必须大于 0"); | ||
| 40 | + // 获得发起人 | ||
| 41 | + ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(task.getProcessInstanceId()); | ||
| 42 | + Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); | ||
| 43 | + // 获得对应 leve 的部门 | ||
| 44 | + DeptRespDTO dept = null; | ||
| 45 | + for (int i = 0; i < level; i++) { | ||
| 46 | + // 获得 level 对应的部门 | ||
| 47 | + if (dept == null) { | ||
| 48 | + dept = getStartUserDept(startUserId); | ||
| 49 | + if (dept == null) { // 找不到发起人的部门,所以无法使用该规则 | ||
| 50 | + return emptySet(); | ||
| 51 | + } | ||
| 52 | + } else { | ||
| 53 | + DeptRespDTO parentDept = deptApi.getDept(dept.getParentId()); | ||
| 54 | + if (parentDept == null) { // 找不到父级部门,所以只好结束寻找。原因是:例如说,级别比较高的人,所在部门层级比较少 | ||
| 55 | + break; | ||
| 56 | + } | ||
| 57 | + dept = parentDept; | ||
| 58 | + } | ||
| 59 | + } | ||
| 60 | + return dept.getLeaderUserId() != null ? asSet(dept.getLeaderUserId()) : emptySet(); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + private DeptRespDTO getStartUserDept(Long startUserId) { | ||
| 64 | + AdminUserRespDTO startUser = adminUserApi.getUser(startUserId); | ||
| 65 | + if (startUser.getDeptId() == null) { // 找不到部门,所以无法使用该规则 | ||
| 66 | + return null; | ||
| 67 | + } | ||
| 68 | + return deptApi.getDept(startUser.getDeptId()); | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | +} |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX1Script.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; | ||
| 4 | +import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||
| 5 | +import org.springframework.stereotype.Component; | ||
| 6 | + | ||
| 7 | +import java.util.Set; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 分配给发起人的一级 Leader 审批的 Script 实现类 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@Component | ||
| 15 | +public class BpmTaskAssignLeaderX1Script extends BpmTaskAssignLeaderAbstractScript { | ||
| 16 | + | ||
| 17 | + @Override | ||
| 18 | + public Set<Long> calculateTaskCandidateUsers(TaskEntity task) { | ||
| 19 | + return calculateTaskCandidateUsers(task, 1); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + @Override | ||
| 23 | + public BpmTaskRuleScriptEnum getEnum() { | ||
| 24 | + return BpmTaskRuleScriptEnum.LEADER_X1; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | +} |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignLeaderX2Script.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; | ||
| 4 | +import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||
| 5 | +import org.springframework.stereotype.Component; | ||
| 6 | + | ||
| 7 | +import java.util.Set; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 分配给发起人的二级 Leader 审批的 Script 实现类 | ||
| 11 | + * | ||
| 12 | + * @author 芋道源码 | ||
| 13 | + */ | ||
| 14 | +@Component | ||
| 15 | +public class BpmTaskAssignLeaderX2Script extends BpmTaskAssignLeaderAbstractScript { | ||
| 16 | + | ||
| 17 | + @Override | ||
| 18 | + public Set<Long> calculateTaskCandidateUsers(TaskEntity task) { | ||
| 19 | + return calculateTaskCandidateUsers(task, 2); | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + @Override | ||
| 23 | + public BpmTaskRuleScriptEnum getEnum() { | ||
| 24 | + return BpmTaskRuleScriptEnum.LEADER_X2; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | +} |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/script/impl/BpmTaskAssignStartUserScript.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.impl; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.common.util.collection.SetUtils; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||
| 5 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTaskRuleScriptEnum; | ||
| 6 | + | ||
| 7 | +import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.script.BpmTaskAssignScript; | ||
| 8 | +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; | ||
| 9 | +import org.flowable.engine.runtime.ProcessInstance; | ||
| 10 | +import org.flowable.task.service.impl.persistence.entity.TaskEntity; | ||
| 11 | +import org.springframework.context.annotation.Lazy; | ||
| 12 | +import org.springframework.stereotype.Component; | ||
| 13 | + | ||
| 14 | +import javax.annotation.Resource; | ||
| 15 | +import java.util.Set; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * 分配给发起人审批的 Script 实现类 | ||
| 19 | + * | ||
| 20 | + * @author 芋道源码 | ||
| 21 | + */ | ||
| 22 | +@Component | ||
| 23 | +public class BpmTaskAssignStartUserScript implements BpmTaskAssignScript { | ||
| 24 | + | ||
| 25 | + @Resource | ||
| 26 | + @Lazy // 解决循环依赖 | ||
| 27 | + private BpmProcessInstanceService bpmProcessInstanceService; | ||
| 28 | + | ||
| 29 | + @Override | ||
| 30 | + public Set<Long> calculateTaskCandidateUsers(TaskEntity task) { | ||
| 31 | + ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(task.getProcessInstanceId()); | ||
| 32 | + Long startUserId = NumberUtils.parseLong(processInstance.getStartUserId()); | ||
| 33 | + return SetUtils.asSet(startUserId); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @Override | ||
| 37 | + public BpmTaskRuleScriptEnum getEnum() { | ||
| 38 | + return BpmTaskRuleScriptEnum.START_USER; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | +} |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java
| @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; | @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; | ||
| 5 | import cn.hutool.core.util.StrUtil; | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 7 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; |
| 8 | +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; | ||
| 8 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; | 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO; |
| 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; | 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO; |
| 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; | 11 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO; |
| @@ -198,7 +199,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | @@ -198,7 +199,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | ||
| 198 | BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes()); | 199 | BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes()); |
| 199 | BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId()); | 200 | BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId()); |
| 200 | //TODO 貌似 flowable 不修改这个也不同。需要看看。 sourceSystemId 不同 | 201 | //TODO 貌似 flowable 不修改这个也不同。需要看看。 sourceSystemId 不同 |
| 201 | - if (equals(oldModel, newModel)) { | 202 | + if (FlowableUtils.equals(oldModel, newModel)) { |
| 202 | return false; | 203 | return false; |
| 203 | } | 204 | } |
| 204 | // 最终发现都一致,则返回 true | 205 | // 最终发现都一致,则返回 true |
| @@ -216,19 +217,8 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | @@ -216,19 +217,8 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ | ||
| 216 | BpmnXMLConverter converter = new BpmnXMLConverter(); | 217 | BpmnXMLConverter converter = new BpmnXMLConverter(); |
| 217 | return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true); | 218 | return converter.convertToBpmnModel(new BytesStreamSource(bpmnBytes), true, true); |
| 218 | } | 219 | } |
| 219 | - //TODO 移出去 | ||
| 220 | - public boolean equals(BpmnModel oldModel, BpmnModel newModel) { | ||
| 221 | - // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较 | ||
| 222 | - return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel)); | ||
| 223 | - } | ||
| 224 | - //TODO 移出去 | ||
| 225 | - public byte[] getBpmnBytes(BpmnModel model) { | ||
| 226 | - if (model == null) { | ||
| 227 | - return new byte[0]; | ||
| 228 | - } | ||
| 229 | - BpmnXMLConverter converter = new BpmnXMLConverter(); | ||
| 230 | - return converter.convertToXML(model); | ||
| 231 | - } | 220 | + |
| 221 | + | ||
| 232 | 222 | ||
| 233 | @Override | 223 | @Override |
| 234 | public BpmProcessDefinitionExtDO getProcessDefinitionExt(String id) { | 224 | public BpmProcessDefinitionExtDO getProcessDefinitionExt(String id) { |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java
| @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; | @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; | ||
| 5 | import cn.hutool.core.util.StrUtil; | 5 | import cn.hutool.core.util.StrUtil; |
| 6 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 6 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 7 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; | 7 | import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; |
| 8 | +import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; | ||
| 8 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; | 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO; |
| 9 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; | 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO; |
| 10 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; | 11 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO; |
| @@ -87,37 +88,15 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService{ | @@ -87,37 +88,15 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService{ | ||
| 87 | if (model == null) { | 88 | if (model == null) { |
| 88 | return Collections.emptyList(); | 89 | return Collections.emptyList(); |
| 89 | } | 90 | } |
| 90 | - | ||
| 91 | // 获得用户任务,只有用户任务才可以设置分配规则 | 91 | // 获得用户任务,只有用户任务才可以设置分配规则 |
| 92 | - List<UserTask> userTasks = getBpmnModelElements(model, UserTask.class); | 92 | + List<UserTask> userTasks = FlowableUtils.getBpmnModelElements(model, UserTask.class); |
| 93 | if (CollUtil.isEmpty(userTasks)) { | 93 | if (CollUtil.isEmpty(userTasks)) { |
| 94 | return Collections.emptyList(); | 94 | return Collections.emptyList(); |
| 95 | } | 95 | } |
| 96 | - | ||
| 97 | // 转换数据 | 96 | // 转换数据 |
| 98 | return BpmTaskAssignRuleConvert.INSTANCE.convertList(userTasks, rules); | 97 | return BpmTaskAssignRuleConvert.INSTANCE.convertList(userTasks, rules); |
| 99 | } | 98 | } |
| 100 | 99 | ||
| 101 | - /** | ||
| 102 | - * TODO 需要移出去 | ||
| 103 | - * 获得 BPMN 流程中,指定的元素们 | ||
| 104 | - * | ||
| 105 | - * @param model | ||
| 106 | - * @param clazz 指定元素。例如说,{@link org.flowable.bpmn.model.UserTask}、{@link org.flowable.bpmn.model.Gateway} 等等 | ||
| 107 | - * @return 元素们 | ||
| 108 | - */ | ||
| 109 | - public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) { | ||
| 110 | - List<T> result = new ArrayList<>(); | ||
| 111 | - model.getProcesses().forEach(process -> { | ||
| 112 | - process.getFlowElements().forEach(flowElement -> { | ||
| 113 | - if (flowElement.getClass().isAssignableFrom(clazz)) { | ||
| 114 | - result.add((T) flowElement); | ||
| 115 | - } | ||
| 116 | - }); | ||
| 117 | - }); | ||
| 118 | - return result; | ||
| 119 | - } | ||
| 120 | - | ||
| 121 | @Override | 100 | @Override |
| 122 | public Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO) { | 101 | public Long createTaskAssignRule(@Valid BpmTaskAssignRuleCreateReqVO reqVO) { |
| 123 | // 校验参数 | 102 | // 校验参数 |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| @@ -106,6 +106,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | @@ -106,6 +106,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService | ||
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | @Override | 108 | @Override |
| 109 | + @Transactional(rollbackFor = Exception.class) | ||
| 109 | public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { | 110 | public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { |
| 110 | // 获得流程定义 | 111 | // 获得流程定义 |
| 111 | ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); | 112 | ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| @@ -25,6 +25,7 @@ import org.flowable.task.api.TaskQuery; | @@ -25,6 +25,7 @@ import org.flowable.task.api.TaskQuery; | ||
| 25 | import org.flowable.task.api.history.HistoricTaskInstance; | 25 | import org.flowable.task.api.history.HistoricTaskInstance; |
| 26 | import org.flowable.task.api.history.HistoricTaskInstanceQuery; | 26 | import org.flowable.task.api.history.HistoricTaskInstanceQuery; |
| 27 | import org.springframework.stereotype.Service; | 27 | import org.springframework.stereotype.Service; |
| 28 | +import org.springframework.transaction.annotation.Transactional; | ||
| 28 | import org.springframework.transaction.support.TransactionSynchronization; | 29 | import org.springframework.transaction.support.TransactionSynchronization; |
| 29 | import org.springframework.transaction.support.TransactionSynchronizationManager; | 30 | import org.springframework.transaction.support.TransactionSynchronizationManager; |
| 30 | 31 | ||
| @@ -167,6 +168,7 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | @@ -167,6 +168,7 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | ||
| 167 | } | 168 | } |
| 168 | 169 | ||
| 169 | @Override | 170 | @Override |
| 171 | + @Transactional(rollbackFor = Exception.class) | ||
| 170 | public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) { | 172 | public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) { |
| 171 | // 校验任务存在 | 173 | // 校验任务存在 |
| 172 | Task task = checkTask(userId, reqVO.getId()); | 174 | Task task = checkTask(userId, reqVO.getId()); |
| @@ -184,6 +186,7 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | @@ -184,6 +186,7 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | ||
| 184 | } | 186 | } |
| 185 | 187 | ||
| 186 | @Override | 188 | @Override |
| 189 | + @Transactional(rollbackFor = Exception.class) | ||
| 187 | public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) { | 190 | public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) { |
| 188 | Task task = checkTask(userId, reqVO.getId()); | 191 | Task task = checkTask(userId, reqVO.getId()); |
| 189 | // 校验流程实例存在 | 192 | // 校验流程实例存在 |
| @@ -234,16 +237,15 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | @@ -234,16 +237,15 @@ public class BpmTaskServiceImpl implements BpmTaskService{ | ||
| 234 | .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())) | 237 | .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())) |
| 235 | .setTaskId(task.getId()); | 238 | .setTaskId(task.getId()); |
| 236 | taskExtMapper.updateByTaskId(taskExtDO); | 239 | taskExtMapper.updateByTaskId(taskExtDO); |
| 237 | - //TODO 创建任务时候 也会调用 updateTaskExtAssign, processInstance 名称为空 校验不通过 | ||
| 238 | // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 | 240 | // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。 |
| 239 | -// TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | ||
| 240 | -// @Override | ||
| 241 | -// public void afterCommit() { | ||
| 242 | -// ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); | ||
| 243 | -// AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); | ||
| 244 | -// messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); | ||
| 245 | -// } | ||
| 246 | -// }); | 241 | + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { |
| 242 | + @Override | ||
| 243 | + public void afterCommit() { | ||
| 244 | + ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); | ||
| 245 | + AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId())); | ||
| 246 | + messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task)); | ||
| 247 | + } | ||
| 248 | + }); | ||
| 247 | } | 249 | } |
| 248 | 250 | ||
| 249 | /** | 251 | /** |