Merge branch 'feature/REQ-3290' into 'master'

Feature/req 3290

See merge request universal/infrastructure/backend/workflow-engine!12
This commit is contained in:
王粒 2024-11-27 02:37:15 +00:00
commit 7f42c1c902
9 changed files with 124 additions and 67 deletions

View File

@ -9,6 +9,7 @@ import lombok.NoArgsConstructor;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
import java.util.List;
/**
@ -22,7 +23,9 @@ import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BpmnTaskTransferDTO {
public class BpmnTaskTransferDTO implements Serializable {
private static final long serialVersionUID = 8142105892475867826L;
/**
* 审批任务 ID

View File

@ -40,6 +40,7 @@ public enum BpmnTaskRespCode implements IModuleRespCode {
BACK_TARGET_ACTIVITY_NOT_EXISTS("023", "回退到指定节点【{}】失败!"),
BACK_NODE_CANNOT_REACHABLE("024", "退回节点【{}】不可达,不允许退回"),
REACHED_BACKED_MAXIMUM_NUM("025", "达到回退操作次数上限【{}】次"),
TRANSFER_TO_SELF("026", "任务不能转交给自己"),
;
private final String code;

View File

@ -157,7 +157,7 @@ public class CustomBizSpecifyAssigneeToTaskCmd extends AbstractCommand<Boolean>
taskService.setAssignee(task.getId(), HIDDEN_ASSIGNEE_ID);
((TaskEntity) task).setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), DELETED.getStatus());
CustomTaskHelper.deleteMultiTask(commandContext, (TaskEntity) task);
CustomTaskHelper.deleteMultiTask(commandContext, task);
}
private static void validTask(Task task, String executionId) {

View File

@ -19,9 +19,9 @@ import java.io.Serializable;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
public class CustomCountersignUserTaskAsyncCmd extends AbstractCommand<Void> implements Serializable {
private static final long serialVersionUID = -6072764832727629141L;
private final BpmnTaskCountersignDTO dto;
public CustomCountersignUserTaskAsyncCmd(BpmnTaskCountersignDTO dto) {
@ -46,7 +46,7 @@ public class CustomCountersignUserTaskAsyncCmd extends AbstractCommand<Void> imp
validTask(historicTaskInstance, (TaskEntity) task, dto.getOriginAssigner(), null);
validTaskAssignerDuplicated(commandContext, (TaskEntity) task, dto.getTargetAssignerList());
// validTaskAssignerDuplicated(commandContext, (TaskEntity) task, dto.getTargetAssignerList());
validTaskAssignerCount(processEngineConfiguration.getRuntimeService(), (TaskEntity) task, dto.getTargetAssignerList());

View File

@ -15,14 +15,21 @@ import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.util.CommandContextUtil;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static cn.axzo.workflow.common.constant.BpmnConstants.COUNTERSIGN_ASSIGNER_SHOW_NUMBER;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
@ -30,9 +37,10 @@ import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.COUNTE
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.completeVirtualTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.createVirtualTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.deleteMultiTasks;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.getDuplicatePendingTasks;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerCount;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
/**
* 自定义的加签用户任务命令实现
@ -45,6 +53,7 @@ import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask
@Slf4j
public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implements Serializable {
private static final long serialVersionUID = -2354973133616698898L;
private final BpmnCountersignTypeEnum countersignType;
private final String originTaskId;
private final BpmnTaskDelegateAssigner originTaskAssignee;
@ -81,9 +90,9 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
@Override
public Void execute(CommandContext commandContext) {
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
CommandContextUtil.getProcessEngineConfiguration(commandContext);
HistoricTaskInstanceQuery taskQuery =
processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
HistoricTaskInstance historicTaskInstance = taskQuery.taskId(originTaskId).singleResult();
TaskService taskService = processEngineConfiguration.getTaskService();
@ -93,27 +102,40 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
validTaskAssignerCount(processEngineConfiguration.getRuntimeService(), task, targetTaskAssigneeList);
List<BpmnTaskDelegateAssigner> taskDelegateAssigners =
validTaskAssignerDuplicated(commandContext, task, targetTaskAssigneeList);
resolveOriginTask(commandContext, extAxHiTaskInstService, taskService, task);
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList,
originTaskAssignee);
switch (countersignType) {
case FORWARD_COUNTERSIGN:
// TODO
break;
case BACK_COUNTERSIGN:
// TODO
break;
default:
// share_counterSign
shareCountSign(commandContext, task, taskDelegateAssigners);
break;
//查询重复任务
List<Task> duplicatePendingTasks = getDuplicatePendingTasks(commandContext, task, targetTaskAssigneeList);
List<BpmnTaskDelegateAssigner> valuTargetAssigneeList;
if (CollectionUtils.isEmpty(duplicatePendingTasks)) {
valuTargetAssigneeList = targetTaskAssigneeList;
} else {
valuTargetAssigneeList = new ArrayList<>();
Set<String> duplicateAssigneeSet = duplicatePendingTasks.stream().map(TaskInfo::getAssignee).collect(Collectors.toSet());
for (BpmnTaskDelegateAssigner assigner : targetTaskAssigneeList) {
if (!duplicateAssigneeSet.contains(assigner.buildAssigneeId())) {
valuTargetAssigneeList.add(assigner);
}
}
}
//需要加签的
if (!CollectionUtils.isEmpty(valuTargetAssigneeList)) {
switch (countersignType) {
case FORWARD_COUNTERSIGN:
// TODO
break;
case BACK_COUNTERSIGN:
// TODO
break;
default:
// share_counterSign
shareCountSign(commandContext, task, valuTargetAssigneeList);
break;
}
}
return null;
}
@ -122,23 +144,21 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
*
* @param commandContext
* @param taskEntity
* @param taskDelegateAssigners 当前任务的原审批人列表
*/
private void shareCountSign(CommandContext commandContext, TaskEntity taskEntity,
List<BpmnTaskDelegateAssigner> taskDelegateAssigners) {
private void shareCountSign(CommandContext commandContext, TaskEntity taskEntity, List<BpmnTaskDelegateAssigner> valuTargetAssigneeList) {
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
CommandContextUtil.getProcessEngineConfiguration(commandContext);
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
// 这个节点下所有审批人快照
String activityListSnapshot =
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey();
taskDelegateAssigners.addAll(targetTaskAssigneeList);
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + taskEntity.getTaskDefinitionKey();
List<BpmnTaskDelegateAssigner> taskDelegateAssigners =
processEngineConfiguration.getRuntimeService().getVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, List.class);
taskDelegateAssigners.addAll(valuTargetAssigneeList);
runtimeService.setVariable(taskEntity.getProcessInstanceId(), activityListSnapshot, taskDelegateAssigners);
log.info("正在进行加签任务:{},待加签人合并列表:{}", taskEntity.getId(), JSONUtil.toJsonStr(taskDelegateAssigners));
targetTaskAssigneeList.forEach(assigner -> {
CustomTaskHelper.addMultiTask(commandContext, taskEntity, assigner);
});
valuTargetAssigneeList.forEach(assigner -> CustomTaskHelper.addMultiTask(commandContext, taskEntity, assigner));
}
private void resolveOriginTask(CommandContext commandContext, ExtAxHiTaskInstService extAxHiTaskInstService,
@ -155,7 +175,7 @@ public class CustomCountersignUserTaskCmd extends AbstractCommand<Void> implemen
}
message.append("").append(targetTaskAssigneeList.size()).append("人进行审批");
Task virtualTask = createVirtualTask(commandContext, extAxHiTaskInstService, task.getProcessInstanceId(), task.getName(),
task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus(), new AddComment(message.toString()));
task.getTaskDefinitionKey(), advice, originTaskAssignee, COUNTERSIGN.getStatus(), new AddComment(message.toString()));
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList, originTaskAssignee);
completeVirtualTask(commandContext, virtualTask);
}

View File

@ -1,10 +1,10 @@
package cn.axzo.workflow.core.engine.cmd;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskTransferDTO;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.engine.job.AsyncTransferUserTaskJobHandler;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
@ -17,17 +17,17 @@ import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TRANSFER_TO_SELF;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
/**
* 异步转交任务的命令执行器
*/
public class CustomTransferUserTaskAsyncCmd extends AbstractCommand<Void> implements Serializable {
private static final long serialVersionUID = -1847844435303542933L;
private final BpmnTaskTransferDTO dto;
public CustomTransferUserTaskAsyncCmd(BpmnTaskTransferDTO dto) {
@ -41,13 +41,16 @@ public class CustomTransferUserTaskAsyncCmd extends AbstractCommand<Void> implem
@Override
public Void execute(CommandContext commandContext) {
//不能转交给自己
if (dto.getOriginAssigner().buildAssigneeId().equals(dto.getTargetAssigner().buildAssigneeId())) {
throw new WorkflowEngineException(TRANSFER_TO_SELF);
}
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
HistoricTaskInstanceQuery taskQuery = processEngineConfiguration.getHistoryService().createHistoricTaskInstanceQuery();
HistoricTaskInstance historicTaskInstance = taskQuery.taskId(dto.getTaskId()).singleResult();
TaskService taskService = processEngineConfiguration.getTaskService();
Task task = taskService.createTaskQuery().taskId(dto.getTaskId()).singleResult();
validTask(historicTaskInstance, (TaskEntity) task, dto.getOriginAssigner(), null);
validTaskAssignerDuplicated(commandContext, (TaskEntity) task, Lists.newArrayList(dto.getTargetAssigner()));
startAsync(processEngineConfiguration, task);
return null;
}

View File

@ -16,13 +16,15 @@ import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_ADVICE;
import static cn.axzo.workflow.common.constant.BpmnConstants.COMMENT_TYPE_OPERATION_DESC;
@ -31,13 +33,13 @@ import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_ASSIGNEE_SKIP_
import static cn.axzo.workflow.common.constant.BpmnConstants.TASK_COMPLETE_OPERATION_TYPE;
import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.TRANSFER;
import static cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner.buildDummyAssigner;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.ASSIGNEE_HAS_BEEN_EXISTS;
import static cn.axzo.workflow.core.common.code.BpmnTaskRespCode.TRANSFER_TO_SELF;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addComment;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.addMultiTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.batchAddAttachment;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.deleteMultiTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.deleteMultiTasks;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.getDuplicatePendingTasks;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTask;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.validTaskAssignerDuplicated;
/**
* 转交任务的命令实现
@ -79,6 +81,10 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
@Override
public Void execute(CommandContext commandContext) {
//不能转交给自己
if (targetTaskAssignee.buildAssigneeId().equals(originTaskAssignee.buildAssigneeId())) {
throw new WorkflowEngineException(TRANSFER_TO_SELF);
}
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
HistoricTaskInstanceQuery taskQuery =
@ -90,7 +96,6 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
validTask(historicTaskInstance, task, originTaskAssignee, null);
validTaskAssignerDuplicated(commandContext, task, Lists.newArrayList(targetTaskAssignee));
// 修改节点对应的审批人集合快照信息
processAssignee(processEngineConfiguration, task);
@ -100,11 +105,14 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
batchAddAttachment(commandContext, task.getProcessInstanceId(), task, attachmentList,
originTaskAssignee);
// 生成转交任务
addMultiTask(commandContext, task, targetTaskAssignee);
List<Task> duplicatePendingTasks = getDuplicatePendingTasks(commandContext, task, Lists.newArrayList(targetTaskAssignee));
//转交目标人不存在任务再生成转交任务
if (CollectionUtils.isEmpty(duplicatePendingTasks)) {
addMultiTask(commandContext, task, targetTaskAssignee);
}
task.setTransientVariable(TASK_COMPLETE_OPERATION_TYPE + task.getId(), TRANSFER.getStatus());
// 结束被转交任务
deleteMultiTask(commandContext, task);
deleteMultiTasks(commandContext, Collections.singletonList(task));
return null;
}
@ -126,22 +134,22 @@ public class CustomTransferUserTaskCmd extends AbstractCommand<Void> implements
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
List<BpmnTaskDelegateAssigner> originAssingeeList = runtimeService.getVariable(task.getProcessInstanceId(),
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(), List.class);
Optional<BpmnTaskDelegateAssigner> exists = originAssingeeList.stream()
.filter(i -> Objects.equals(i.buildAssigneeId(), targetTaskAssignee.buildAssigneeId())).findAny();
if (exists.isPresent()) {
throw new WorkflowEngineException(ASSIGNEE_HAS_BEEN_EXISTS);
}
List<BpmnTaskDelegateAssigner> resultList = new ArrayList<>();
boolean containsTargetAssignee = false;
for (BpmnTaskDelegateAssigner assigner : originAssingeeList) {
if (Objects.equals(assigner.buildAssigneeId(), originTaskAssignee.buildAssigneeId())) {
originAssingeeList.remove(assigner);
break;
if (!Objects.equals(assigner.buildAssigneeId(), originTaskAssignee.buildAssigneeId())) {
resultList.add(assigner);
}
if (Objects.equals(assigner.buildAssigneeId(), targetTaskAssignee.buildAssigneeId())) {
containsTargetAssignee = true;
}
}
originAssingeeList.add(targetTaskAssignee);
if (!containsTargetAssignee) {
resultList.add(targetTaskAssignee);
}
runtimeService.setVariable(task.getProcessInstanceId(),
INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT + task.getTaskDefinitionKey(),
originAssingeeList);
resultList);
}
}

View File

@ -17,6 +17,7 @@ import org.flowable.common.engine.impl.cfg.IdGenerator;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.common.engine.impl.interceptor.CommandContext;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
@ -39,6 +40,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@ -93,14 +95,22 @@ public class CustomTaskHelper {
setParentTaskId(originTask, subExecution);
}
public static void deleteMultiTask(CommandContext commandContext, TaskEntity originTask) {
if (Objects.isNull(originTask)) {
public static void deleteMultiTask(CommandContext commandContext, Task originTask) {
if (originTask == null) {
return;
}
ProcessEngineConfigurationImpl processEngineConfiguration =
CommandContextUtil.getProcessEngineConfiguration(commandContext);
deleteMultiTasks(commandContext, Collections.singletonList(originTask));
}
public static void deleteMultiTasks(CommandContext commandContext, List<Task> originTasks) {
if (CollectionUtils.isEmpty(originTasks)) {
return;
}
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
RuntimeService runtimeService = processEngineConfiguration.getRuntimeService();
runtimeService.deleteMultiInstanceExecution(originTask.getExecutionId(), false);
originTasks.stream()
.filter(Objects::nonNull)
.forEach(originTask -> runtimeService.deleteMultiInstanceExecution(originTask.getExecutionId(), false));
}
private static void setParentTaskId(TaskEntity originTask, Execution subExecution) {
@ -161,6 +171,24 @@ public class CustomTaskHelper {
}
}
public static List<Task> getDuplicatePendingTasks(CommandContext commandContext,
TaskEntity taskEntity,
List<BpmnTaskDelegateAssigner> targetAssigneeList) {
if (CollectionUtils.isEmpty(targetAssigneeList)) {
return Collections.emptyList();
}
ProcessEngineConfiguration processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
List<String> assigneeStrList = targetAssigneeList.stream()
.flatMap(ta -> Arrays.stream(new String[]{ta.buildAssigneeId(), ta.buildAssigneeId_1_2_1()}))
.collect(Collectors.toList());
return processEngineConfiguration.getTaskService()
.createTaskQuery()
.processInstanceId(taskEntity.getProcessInstanceId())
.taskAssigneeIds(assigneeStrList)
.list();
}
/**
* 校验被转交/加签的人是否存在重复
*

View File

@ -1,6 +1,5 @@
package cn.axzo.workflow.server.controller.web.bpmn;
import cn.axzo.karma.client.feign.FlowSupportApi;
import cn.axzo.oss.http.api.ServerFileServiceApi;
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
import cn.axzo.oss.http.model.ApiSignUrlDownloadResponse;
@ -32,7 +31,6 @@ import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
import cn.axzo.workflow.server.common.util.RpcExternalUtil;
import cn.axzo.workflow.server.controller.web.BasicPopulateAvatarController;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.v3.oas.annotations.Operation;
@ -56,11 +54,9 @@ import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.azxo.framework.common.model.CommonResponse.success;
@ -78,8 +74,6 @@ public class BpmnProcessInstanceController extends BasicPopulateAvatarController
@Resource
private BpmnProcessInstanceService bpmnProcessInstanceService;
@Resource
private FlowSupportApi flowSupportApi;
@Resource
private ServerFileServiceApi serverFileServiceApi;
/**