REQ-3282 修复转交指定人错误问题

This commit is contained in:
yangqicheng 2024-12-26 16:07:51 +08:00
parent 45ef878ec2
commit b32e287fc9
3 changed files with 139 additions and 67 deletions

View File

@ -34,30 +34,12 @@ import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.*;
import static cn.axzo.workflow.common.constant.BpmnConstants.APPROVAL_ASSIGNER_LIMIT_NUMBER;
import static cn.axzo.workflow.common.constant.BpmnConstants.BIZ_ORG_RELATION;
import static cn.axzo.workflow.common.constant.BpmnConstants.BPM_ALLOW_SKIP_USER_TASK;
import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE;
import static cn.axzo.workflow.common.constant.BpmnConstants.DUMMY_ASSIGNEE_TYPE;
import static cn.axzo.workflow.common.constant.BpmnConstants.FLOW_SERVER_VERSION_121;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_ACTIVITY_RELATION_ASSIGNEE_LIST_INFO_SNAPSHOT;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_INITIATOR;
import static cn.axzo.workflow.common.constant.BpmnConstants.INTERNAL_TASK_RELATION_ASSIGNEE_LIST_INFO;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_BUSINESS;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_STARTER;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.NODE_TASK;
import static cn.axzo.workflow.common.constant.BpmnConstants.*;
import static cn.axzo.workflow.common.enums.BpmnFlowNodeType.*;
import static cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner.buildDummyAssigner;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApprovalMethod;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverEmptyHandleType;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getApproverSpecify;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getNodeType;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.getProcessServerVersion;
import static cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper.*;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.getLimitedElementList;
import static cn.axzo.workflow.core.engine.cmd.helper.CustomTaskHelper.removeDuplicateByPersonId;
@ -204,14 +186,16 @@ public class EngineExecutionStartListener implements ExecutionListener {
}
private void finalEmptyAssigneeHandle(List<BpmnTaskDelegateAssigner> assigners, UserTask userTask, DelegateExecution execution, String operationDesc) {
if (CollectionUtils.isEmpty(assigners) && refreshProperties.getSendDingTalk()) {
CooperationOrgDTO orgScopes = execution.getVariable(BIZ_ORG_RELATION, CooperationOrgDTO.class);
DingTalkUtils.sendDingTalkForTransferToAdminError(profile, execution.getProcessInstanceId(), userTask.getId(), orgScopes);
if (CollectionUtils.isEmpty(assigners)) {
//发送钉钉消息
if (Boolean.TRUE.equals(refreshProperties.getSendDingTalk())) {
CooperationOrgDTO orgScopes = execution.getVariable(BIZ_ORG_RELATION, CooperationOrgDTO.class);
DingTalkUtils.sendDingTalkForTransferToAdminError(profile, execution.getProcessInstanceId(), userTask.getId(), orgScopes);
}
BpmnProcessInstanceAbortDTO abortDTO = new BpmnProcessInstanceAbortDTO();
abortDTO.setProcessInstanceId(execution.getProcessInstanceId());
abortDTO.setReason("转交管理员失败,系统中止");
CommandContextUtil.getProcessEngineConfiguration().getCommandExecutor()
.execute(new CustomAbortProcessInstanceAsyncCmd(abortDTO));
abortDTO.setReason(operationDesc);
CommandContextUtil.getProcessEngineConfiguration().getCommandExecutor().execute(new CustomAbortProcessInstanceAsyncCmd(abortDTO));
}
}

View File

@ -69,15 +69,15 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
List<BpmnTaskDelegateAssigner> assigners = new ArrayList<>();
if (flowElement instanceof UserTask) {
assigners.addAll(BpmnMetaParserHelper.getApproverScope((UserTask) flowElement)
.map(approverScopeEnum -> privateSelector(approverScopeEnum, flowElement, execution,
throwException))
.orElseGet(Collections::emptyList));
.map(approverScopeEnum -> privateSelector(approverScopeEnum, flowElement, execution,
throwException))
.orElseGet(Collections::emptyList));
} else if (flowElement instanceof ServiceTask) {
List<CustomProperty> customProperties = ((ServiceTask) flowElement).getCustomProperties();
if (!CollectionUtils.isEmpty(customProperties)) {
String processor = CarbonCopyObjectType.valueOfType(customProperties.get(0).getName()).getProcessor();
assigners.addAll(privateSelector(ApproverScopeEnum.valueOfProcessor(processor), flowElement,
execution, throwException));
execution, throwException));
}
} else if (flowElement instanceof NoticeFlowElement) {
ApproverScopeEnum processor = ((NoticeFlowElement) flowElement).getProcessor();
@ -89,14 +89,11 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
private List<BpmnTaskDelegateAssigner> privateSelector(ApproverScopeEnum processorType, FlowElement flowElement,
DelegateExecution execution, Boolean throwException) {
ApproverScopeProcessor processor = applicationContext.getBean(processorType.getProcessor(),
ApproverScopeProcessor.class);
ApproverScopeProcessor.class);
ApproverScopeDTO scopeDto = processor.build(flowElement, execution);
if (CollectionUtils.isEmpty(scopeDto.getOrgScopes())
&& CollectionUtils.isEmpty(scopeDto.getWorkerTeamScopes())) {
if (Boolean.TRUE.equals(throwException)) {
throw new WorkflowEngineException(ENGINE_USER_TASK_PARAM_ERROR, flowElement.getId(),
processorType.getDesc());
}
&& CollectionUtils.isEmpty(scopeDto.getWorkerTeamScopes()) && Boolean.TRUE.equals(throwException)) {
throw new WorkflowEngineException(ENGINE_USER_TASK_PARAM_ERROR, flowElement.getId(), processorType.getDesc());
}
try {
return populateNameAndAvatar(invokeService(flowElement, execution, scopeDto), flowSupportApi, refreshProperties, applicationContext);
@ -105,7 +102,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
log.warn("执行查询候选审批人时发现异常, 审批节点:{}, 异常信息:{}", flowElement.getId(), t.getMessage());
if (!(t instanceof WorkflowEngineException)) {
throw new WorkflowEngineException(ENGINE_USER_TASK_CALC_ERROR, flowElement.getId(),
this.getType(), t.getMessage());
this.getType(), t.getMessage());
}
throw t;
} else {
@ -120,7 +117,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
}
protected final <T> T parseFoundationApiResult(Supplier<cn.axzo.foundation.result.ApiResult<T>> supplier, String operatorDesc,
String extInfo, Object... param) {
String extInfo, Object... param) {
StopWatch stopWatch = new StopWatch(operatorDesc);
log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param));
stopWatch.start();
@ -151,12 +148,12 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
protected final <T> T parseApiResult(Supplier<ApiResult<T>> supplier, String operatorDesc,
String extInfo, Object... param) {
String extInfo, Object... param) {
return parseApiResult(supplier, operatorDesc, extInfo, refreshProperties, applicationContext, param);
}
public static <T> T parseApiResult(Supplier<ApiResult<T>> supplier, String operatorDesc,
String extInfo, SupportRefreshProperties refreshProperties,
String extInfo, SupportRefreshProperties refreshProperties,
ApplicationContext context, Object... param) {
StopWatch stopWatch = new StopWatch(operatorDesc);
log.info("{}-Param: {}", operatorDesc, JSONUtil.toJsonStr(param));
@ -164,16 +161,16 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
ApiResult<T> result = supplier.get();
stopWatch.stop();
log.info("{}-Cost:{}, Result: {}", operatorDesc,
"API StopWatch '" + stopWatch.getId() + "': running time = " + stopWatch.getTotalTimeSeconds() + " 's",
JSONUtil.toJsonStr(result));
"API StopWatch '" + stopWatch.getId() + "': running time = " + stopWatch.getTotalTimeSeconds() + " 's",
JSONUtil.toJsonStr(result));
try {
if (stopWatch.getTotalTimeSeconds() > refreshProperties.getApiTimeout() && refreshProperties.getSendDingTalk()) {
DingTalkUtils.sendDingTalkForSlowUrl(context.getEnvironment()
.getProperty("spring.profiles.active"),
stopWatch.getTotalTimeSeconds(),
extInfo,
param,
result);
.getProperty("spring.profiles.active"),
stopWatch.getTotalTimeSeconds(),
extInfo,
param,
result);
}
} catch (Exception e) {
// ignore
@ -192,26 +189,26 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
try {
if (flowElement instanceof UserTask) {
return BpmnMetaParserHelper.getApproverSpecifyValue((UserTask) flowElement)
.map(value -> JSON.parseArray(value, String.class).stream().map(JSON::parseObject)
.map(i -> i.getString("value"))
.collect(Collectors.toList()))
.orElse(Collections.emptyList());
.map(value -> JSON.parseArray(value, String.class).stream().map(JSON::parseObject)
.map(i -> i.getString("value"))
.collect(Collectors.toList()))
.orElse(Collections.emptyList());
} else if (flowElement instanceof ServiceTask) {
List<CustomProperty> customProperties = ((ServiceTask) flowElement).getCustomProperties();
if (CollectionUtils.isEmpty(customProperties)) {
return Collections.emptyList();
}
return JSON.parseArray(customProperties.get(0).getSimpleValue(), String.class)
.stream().map(JSON::parseObject)
.map(i -> i.getString("value"))
.collect(Collectors.toList());
.stream().map(JSON::parseObject)
.map(i -> i.getString("value"))
.collect(Collectors.toList());
} else if (flowElement instanceof NoticeFlowElement) {
String customValues = ((NoticeFlowElement) flowElement).getCustomValues();
if (StringUtils.hasText(customValues)) {
return JSON.parseArray(customValues, String.class)
.stream().map(JSON::parseObject)
.map(i -> i.getString("value"))
.collect(Collectors.toList());
.stream().map(JSON::parseObject)
.map(i -> i.getString("value"))
.collect(Collectors.toList());
}
return Collections.emptyList();
} else {
@ -219,7 +216,7 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
}
} catch (Exception e) {
throw new WorkflowEngineException(CONVERTOR_META_DATA_FORMAT_ERROR, "AbstractBpmnTaskAssigneeSelector" +
"#getTypes", e.getMessage());
"#getTypes", e.getMessage());
}
}
@ -231,16 +228,16 @@ public abstract class AbstractBpmnTaskAssigneeSelector implements BpmnTaskAssign
return assigners;
}
List<Long> personIds = assigners.stream()
.map(BpmnTaskDelegateAssigner::getPersonId)
.filter(e-> Objects.nonNull(e) && StringUtils.hasText(e) && !Objects.equals("null", e))
.map(Long::parseLong)
.distinct().collect(Collectors.toList());
if(CollectionUtils.isEmpty(personIds)) {
.map(BpmnTaskDelegateAssigner::getPersonId)
.filter(e -> Objects.nonNull(e) && StringUtils.hasText(e) && !Objects.equals("null", e))
.map(Long::parseLong)
.distinct().collect(Collectors.toList());
if (CollectionUtils.isEmpty(personIds)) {
return assigners;
}
Map<Long, PersonProfileResp> personProfileMap = parseApiResult(() -> flowSupportApi.listPersons(PersonProfileQueryReq.builder().personIds(personIds).build()),
"根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds)
.stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s));
"根据 PersonId 查询自然人档案", "cn.axzo.karma.client.feign.FlowSupportApi.listPersons", refreshProperties, context, personIds)
.stream().collect(Collectors.toMap(PersonProfileResp::getId, Function.identity(), (s, t) -> s));
assigners.forEach(assigner -> {
if (!StringUtils.hasText(assigner.getPersonId()) || Objects.equals("null", assigner.getPersonId())) {
return;

View File

@ -0,0 +1,91 @@
package cn.axzo.workflow.server.controller.delegate;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi;
import cn.axzo.orggateway.api.nodeuser.dto.OrgNodeUserDTO;
import cn.axzo.orggateway.api.nodeuser.req.ListOrgNodeUserReq;
import cn.axzo.workflow.common.enums.ApproverEmptyHandleTypeEnum;
import cn.axzo.workflow.common.model.request.bpmn.task.BpmnTaskDelegateAssigner;
import cn.axzo.workflow.core.common.utils.BpmnMetaParserHelper;
import cn.axzo.workflow.core.deletage.approverscope.ApproverScopeDTO;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* 转交指定人查询人
*/
@Slf4j
@Component
public class SpecifyAssigneeTaskAssigneeSelector extends AbstractBpmnTaskAssigneeSelector {
@Resource
private OrgNodeUserApi orgNodeUserApi;
@Override
public String getType() {
return ApproverEmptyHandleTypeEnum.specifyAssignee.getType();
}
@Override
public boolean support(String param) {
return getType().equals(param);
}
@Override
protected List<BpmnTaskDelegateAssigner> invokeService(FlowElement flowElement, DelegateExecution execution, ApproverScopeDTO scopeDto) {
if (!(flowElement instanceof UserTask)) {
return Collections.emptyList();
}
List<BpmnTaskDelegateAssigner> emptyAssignees =
BpmnMetaParserHelper.getEmptyApproverSpecify((UserTask) flowElement)
.map(listStr -> JSON.parseArray(listStr, BpmnTaskDelegateAssigner.class))
.orElse(Collections.emptyList());
if (CollectionUtils.isEmpty(emptyAssignees)) {
return Collections.emptyList();
}
List<OrgNodeUserDTO> onlineUsers = new ArrayList<>();
Set<Long> workspaceIds = emptyAssignees.stream()
.map(BpmnTaskDelegateAssigner::getTenantId)
.filter(StringUtils::hasText)
.map(Long::parseLong)
.collect(Collectors.toSet());
List<Long> personIds = emptyAssignees.stream()
.map(BpmnTaskDelegateAssigner::getPersonId)
.filter(StringUtils::hasText)
.map(Long::parseLong)
.collect(Collectors.toList());
ListOrgNodeUserReq searchReq = new ListOrgNodeUserReq();
searchReq.setWorkspaceIds(workspaceIds);
searchReq.setPersonIds(personIds);
searchReq.setPage(1);
searchReq.setPageSize(personIds.size());
PageResp<OrgNodeUserDTO> pageResp = parseFoundationApiResult(() -> orgNodeUserApi.list(searchReq), "查询指定人员是否在职",
"cn.axzo.orggateway.api.nodeuser.OrgNodeUserApi.list", searchReq);
if (pageResp != null) {
onlineUsers = pageResp.getData();
}
// 只要有在职的人不会走审批人为空
if (ListUtils.emptyIfNull(onlineUsers).stream()
.filter(i -> Objects.equals(i.getIsDelete(), 0L))
.anyMatch(u -> emptyAssignees.stream()
.anyMatch(i -> Objects.equals(i.getPersonId(), String.valueOf(u.getPersonId()))
&& Objects.equals(i.getOuId(), String.valueOf(u.getOrganizationalUnitId()))))) {
return emptyAssignees;
}
return Collections.emptyList();
}
}