Commit ffc569e6 by 王志超

feat: 行动工单提交变更执行,变更工单自动提交

parent 42a2aa4a
Pipeline #86794 passed with stages
in 1 minute 30 seconds
...@@ -1707,93 +1707,6 @@ public class ChangeFlowBiz { ...@@ -1707,93 +1707,6 @@ public class ChangeFlowBiz {
return nextNodeId; return nextNodeId;
} }
void submitMainFlowAfterAllSubFlowsApproved(Long changeRecordId) {
// 查询主工单
ChangeRecord changeRecord = changeRecordMapper.selectByPrimaryKey(changeRecordId);
if (changeRecord == null) {
log.error("[submitMainFlowAfterAllSubFlowsApproved] 主工单不存在,changeRecordId:{}", changeRecordId);
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "主工单不存在");
}
// 验证主工单当前节点
String currentNode = changeRecord.getFlowNode();
if (!ChangeFlowEnum.NEW_CHANGE_FLOW_CONFIRM_EXEC_PLAN.getNodeId().equals(currentNode)) {
throw ExceptionFactory.createBiz(ResponseCode.NODE_ERROR,
String.format("主工单当前节点不是确认变更方案节点,无法流转。当前节点:%s", currentNode));
}
try {
Long flowId = changeRecord.getFlowId();
String uid = RequestLocalBean.getUid();
// 获取工单详情
FlowDataDTO flowDataDTO = flowService.flowDetail(flowId.toString());
if (flowDataDTO == null) {
throw ExceptionFactory.createBiz(ResponseCode.DETAIL_FLOW_ERROR, "工单查询错误,不存在");
}
// 构建提交内容
Map<String, Object> content = new HashMap<>(CommonConstants.INIT_HASH_MAP_SIZE);
content.put("updateTime", System.currentTimeMillis());
content.put(CommonConstants.FLOW_OPERATION_KEY, FlowOperationTypeEnum.PASS.getValue());
// 使用paramMap控制流转方向(所有子单审批通过)
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("type", FlowTransitionType.TYPE_APPROVED);
// 流转主工单到部门负责人审批节点
String ownerApproveNodeId = flowService.submitFlowWithParamMap(flowId.toString(), flowDataDTO, uid,
ChangeFlowEnum.NEW_CHANGE_FLOW.getTopoId(), JSON.toJSONString(content), paramMap,
FlowxOperationEnum.SUBMIT.getName(), "所有子单审批通过,主工单流转", changeRecord.getCreateTime());
changeRecord.setFlowNode(ownerApproveNodeId);
changeRecord.setState(ChangeStatusEnum.WAIT_DEPT_LEADER_APPROVE.getStatus());
changeRecord.setUpdateTime(DateUtils.getCurrentTime());
// 获取变更负责人的上级领导并设置为审批人
String changeCommander = changeRecord.getChangeCommander();
if (StringUtils.isBlank(changeCommander)) {
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "变更负责人邮箱不能为空");
}
String leaderEmail = departmentLeaderBiz.getDepartmentLeader(changeCommander);
if (StringUtils.isBlank(leaderEmail)) {
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST,
String.format("变更负责人[%s]的部门上级领导不存在", changeCommander));
}
// 设置审批人为上级领导(JSON 数组格式)
changeRecord.setApprover(JSON.toJSONString(Collections.singletonList(leaderEmail)));
changeFlowService.updateRecord(changeRecord);
log.info("[submitMainFlowAfterAllSubFlowsApproved] 主工单流转成功,flowId:{}, nextNodeId:{}, approver:{}",
flowId, ownerApproveNodeId, leaderEmail);
} catch (Exception e) {
log.error("[submitMainFlowAfterAllSubFlowsApproved] 主工单流转失败,changeRecordId:{}", changeRecordId, e);
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST,
String.format("主工单流转失败:%s", e.getMessage()));
}
}
/**
* 检查主工单下所有子单是否都已完成(供主工单流转时调用)
* 条件:status = FINISHED 或 CANCELLED
*
* @param changeRecordId 主工单ID
* @return true 表示所有子单都已完成
*/
public boolean checkAllSubFlowsFinishedForMainFlow(Long changeRecordId) {
// 查询该主工单下所有子单
List<ChangeSubFlowRecord> allSubFlows = changeSubFlowRecordMapper.selectByChangeRecordId(changeRecordId);
if (CollectionUtils.isEmpty(allSubFlows)) {
return false;
}
// 检查是否所有子单都满足条件:状态是 FINISHED 或 CANCELLED
return allSubFlows.stream().allMatch(subFlow ->
ChangeSubFlowStatusEnum.FINISHED.getStatus().equals(subFlow.getStatus())
|| ChangeSubFlowStatusEnum.CANCELLED.getStatus().equals(subFlow.getStatus())
);
}
/** /**
* 验证子单归属于主工单(查询一次,返回所有子单供后续复用) * 验证子单归属于主工单(查询一次,返回所有子单供后续复用)
* *
......
...@@ -19,6 +19,7 @@ import com.netease.mail.yanxuan.change.common.bean.ResponseCode; ...@@ -19,6 +19,7 @@ import com.netease.mail.yanxuan.change.common.bean.ResponseCode;
import com.netease.mail.yanxuan.change.common.constants.FlowTransitionType; import com.netease.mail.yanxuan.change.common.constants.FlowTransitionType;
import com.netease.mail.yanxuan.change.common.enums.ChangeFlowEnum; import com.netease.mail.yanxuan.change.common.enums.ChangeFlowEnum;
import com.netease.mail.yanxuan.change.common.enums.ChangeResultEnum; import com.netease.mail.yanxuan.change.common.enums.ChangeResultEnum;
import com.netease.mail.yanxuan.change.common.enums.ChangeStatusEnum;
import com.netease.mail.yanxuan.change.common.enums.ChangeSubFlowStatusEnum; import com.netease.mail.yanxuan.change.common.enums.ChangeSubFlowStatusEnum;
import com.netease.mail.yanxuan.change.common.enums.ChangeSubjectEnum; import com.netease.mail.yanxuan.change.common.enums.ChangeSubjectEnum;
import com.netease.mail.yanxuan.change.common.enums.CreateSourceEnum; import com.netease.mail.yanxuan.change.common.enums.CreateSourceEnum;
...@@ -175,9 +176,7 @@ public class ChangeSubFlowBiz { ...@@ -175,9 +176,7 @@ public class ChangeSubFlowBiz {
log.debug("[checkUpdateAndSubmit] 提交参数:{}", JSON.toJSONString(changeSubFlowSubmitReq)); log.debug("[checkUpdateAndSubmit] 提交参数:{}", JSON.toJSONString(changeSubFlowSubmitReq));
// 构建工单内容 // 构建工单内容
Map<String, Object> content = new HashMap<>(CommonConstants.INIT_HASH_MAP_SIZE); Map<String, Object> content = buildFlowContent();
content.put("updateTime", System.currentTimeMillis());
content.put(CommonConstants.FLOW_OPERATION_KEY, FlowOperationTypeEnum.PASS.getValue());
switch (node) { switch (node) {
case CHANGE_SUB_FLOW_START: case CHANGE_SUB_FLOW_START:
...@@ -347,7 +346,7 @@ public class ChangeSubFlowBiz { ...@@ -347,7 +346,7 @@ public class ChangeSubFlowBiz {
// 检查所有子单是否都已到达提交执行结果节点,如果是则流转主工单 // 检查所有子单是否都已到达提交执行结果节点,如果是则流转主工单
if (checkAllSubFlowsApproved(subFlowRecord.getChangeRecordId())) { if (checkAllSubFlowsApproved(subFlowRecord.getChangeRecordId())) {
changeFlowBiz.submitMainFlowAfterAllSubFlowsApproved(subFlowRecord.getChangeRecordId()); submitMainFlowAfterAllSubFlowsApproved(subFlowRecord.getChangeRecordId());
log.info("[CHANGE_SUB_FLOW_EXE] 所有子单均已到达提交执行结果节点,主工单已流转"); log.info("[CHANGE_SUB_FLOW_EXE] 所有子单均已到达提交执行结果节点,主工单已流转");
} }
} else { } else {
...@@ -495,7 +494,11 @@ public class ChangeSubFlowBiz { ...@@ -495,7 +494,11 @@ public class ChangeSubFlowBiz {
// 发送邮件 // 发送邮件
sendSubFlowFinishEmail(subFlowRecord); sendSubFlowFinishEmail(subFlowRecord);
// todo: 检查所有子单是否都已完成,如果是则流转主工单 // 检查所有子单是否都已完成,如果是则流转主工单
if (checkAllSubFlowsFinishedForMainFlow(subFlowRecord.getChangeRecordId())) {
submitMainFlowAfterAllSubFlowsFinished(subFlowRecord.getChangeRecordId());
log.info("[handleSubFlowFinish] 所有子单均已完成,主工单已流转");
}
return endNodeId; return endNodeId;
} }
...@@ -532,7 +535,11 @@ public class ChangeSubFlowBiz { ...@@ -532,7 +535,11 @@ public class ChangeSubFlowBiz {
// 发送邮件 // 发送邮件
sendSubFlowFinishEmail(subFlowRecord); sendSubFlowFinishEmail(subFlowRecord);
// todo: 检查所有子单是否都已完成,如果是则流转主工单 // 检查所有子单是否都已完成,如果是则流转主工单
if (checkAllSubFlowsFinishedForMainFlow(subFlowRecord.getChangeRecordId())) {
submitMainFlowAfterAllSubFlowsFinished(subFlowRecord.getChangeRecordId());
log.info("[handleSubFlowCancel] 所有子单均已完成,主工单已流转");
}
return cancelNodeId; return cancelNodeId;
} }
...@@ -607,6 +614,188 @@ public class ChangeSubFlowBiz { ...@@ -607,6 +614,188 @@ public class ChangeSubFlowBiz {
} }
/** /**
* 构建工单提交内容(包含 updateTime 和 FLOW_OPERATION_KEY)
*
* @return 工单提交内容 Map
*/
private Map<String, Object> buildFlowContent() {
Map<String, Object> content = new HashMap<>(CommonConstants.INIT_HASH_MAP_SIZE);
content.put("updateTime", System.currentTimeMillis());
content.put(CommonConstants.FLOW_OPERATION_KEY, FlowOperationTypeEnum.PASS.getValue());
return content;
}
/**
* 所有子单审批变更方案通过后,流转主工单到部门负责人审批节点
*
* @param changeRecordId 主工单ID
*/
private void submitMainFlowAfterAllSubFlowsApproved(Long changeRecordId) {
// 查询主工单
ChangeRecord changeRecord = changeRecordMapper.selectByPrimaryKey(changeRecordId);
if (changeRecord == null) {
log.error("[submitMainFlowAfterAllSubFlowsApproved] 主工单不存在,changeRecordId:{}", changeRecordId);
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "主工单不存在");
}
// 验证主工单当前节点
String currentNode = changeRecord.getFlowNode();
if (!ChangeFlowEnum.NEW_CHANGE_FLOW_CONFIRM_EXEC_PLAN.getNodeId().equals(currentNode)) {
throw ExceptionFactory.createBiz(ResponseCode.NODE_ERROR,
String.format("主工单当前节点不是确认变更方案节点,无法流转。当前节点:%s", currentNode));
}
try {
Long flowId = changeRecord.getFlowId();
String uid = RequestLocalBean.getUid();
if (StringUtils.isBlank(uid)) {
uid = "system";
}
// 获取工单详情
FlowDataDTO flowDataDTO = flowService.flowDetail(flowId.toString());
if (flowDataDTO == null) {
throw ExceptionFactory.createBiz(ResponseCode.DETAIL_FLOW_ERROR, "工单查询错误,不存在");
}
// 构建提交内容
Map<String, Object> content = buildFlowContent();
// 使用paramMap控制流转方向(所有子单审批通过)
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("type", FlowTransitionType.TYPE_APPROVED);
// 流转主工单到部门负责人审批节点
String ownerApproveNodeId = flowService.submitFlowWithParamMap(flowId.toString(), flowDataDTO, uid,
ChangeFlowEnum.NEW_CHANGE_FLOW.getTopoId(), JSON.toJSONString(content), paramMap,
FlowxOperationEnum.SUBMIT.getName(), "所有子单审批通过,主工单流转", changeRecord.getCreateTime());
changeRecord.setFlowNode(ownerApproveNodeId);
changeRecord.setState(ChangeStatusEnum.WAIT_DEPT_LEADER_APPROVE.getStatus());
changeRecord.setUpdateTime(DateUtils.getCurrentTime());
// 获取变更负责人的上级领导并设置为审批人
String changeCommander = changeRecord.getChangeCommander();
if (StringUtils.isBlank(changeCommander)) {
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "变更负责人邮箱不能为空");
}
String leaderEmail = departmentLeaderBiz.getDepartmentLeader(changeCommander);
if (StringUtils.isBlank(leaderEmail)) {
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST,
String.format("变更负责人[%s]的部门上级领导不存在", changeCommander));
}
// 设置审批人为上级领导(JSON 数组格式)
changeRecord.setApprover(JSON.toJSONString(Collections.singletonList(leaderEmail)));
changeFlowService.updateRecord(changeRecord);
log.info("[submitMainFlowAfterAllSubFlowsApproved] 主工单流转成功,flowId:{}, nextNodeId:{}, approver:{}",
flowId, ownerApproveNodeId, leaderEmail);
} catch (Exception e) {
log.error("[submitMainFlowAfterAllSubFlowsApproved] 主工单流转失败,changeRecordId:{}", changeRecordId, e);
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST,
String.format("主工单流转失败:%s", e.getMessage()));
}
}
/**
* 所有子单执行完成后,流转主工单到确认执行结果节点
*
* @param changeRecordId 主工单ID
*/
private void submitMainFlowAfterAllSubFlowsFinished(Long changeRecordId) {
// 查询主工单
ChangeRecord changeRecord = changeRecordMapper.selectByPrimaryKey(changeRecordId);
if (changeRecord == null) {
log.error("[submitMainFlowAfterAllSubFlowsFinished] 主工单不存在,changeRecordId:{}", changeRecordId);
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST, "主工单不存在");
}
// 验证主工单当前节点
String currentNode = changeRecord.getFlowNode();
if (!ChangeFlowEnum.NEW_CHANGE_FLOW_EXE.getNodeId().equals(currentNode)) {
log.warn("[submitMainFlowAfterAllSubFlowsFinished] 主工单当前节点不是执行变更方案节点,无法流转。当前节点:{}", currentNode);
return;
}
try {
Long flowId = changeRecord.getFlowId();
String uid = RequestLocalBean.getUid();
if (StringUtils.isBlank(uid)) {
uid = "system";
}
String name = RequestLocalBean.getName();
if (StringUtils.isBlank(name)) {
name = "系统";
}
// 获取工单详情
FlowDataDTO flowDataDTO = flowService.flowDetail(flowId.toString());
if (flowDataDTO == null) {
throw ExceptionFactory.createBiz(ResponseCode.DETAIL_FLOW_ERROR, "工单查询错误,不存在");
}
// 构建提交内容
Map<String, Object> content = buildFlowContent();
// 使用paramMap控制流转方向(所有子单执行结果完成)
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("type", FlowTransitionType.TYPE_APPROVED);
// 流转主工单到确认变更结果节点
String confirmNodeId = flowService.submitFlowWithParamMap(flowId.toString(), flowDataDTO, uid,
ChangeFlowEnum.NEW_CHANGE_FLOW.getTopoId(), JSON.toJSONString(content), paramMap,
FlowxOperationEnum.SUBMIT.getName(), "所有子单执行结果完成,主工单流转", changeRecord.getCreateTime());
changeRecord.setFlowNode(confirmNodeId);
changeRecord.setState(ChangeStatusEnum.WAIT_CONFIRM_EXEC_RESULT.getStatus());
changeRecord.setUpdateTime(DateUtils.getCurrentTime());
changeFlowService.updateRecord(changeRecord);
log.info("[submitMainFlowAfterAllSubFlowsFinished] 主工单流转成功,flowId:{}, nextNodeId:{}, state:{}",
flowId, confirmNodeId, ChangeStatusEnum.WAIT_CONFIRM_EXEC_RESULT.getStatus());
} catch (Exception e) {
log.error("[submitMainFlowAfterAllSubFlowsFinished] 主工单流转失败,changeRecordId:{}", changeRecordId, e);
throw ExceptionFactory.createBiz(ResponseCode.BAD_REQUEST,
String.format("主工单流转失败:%s", e.getMessage()));
}
}
/**
* 检查主工单下所有子单是否都已完成
* 以节点为准:如果节点是结束节点(9999),则认为已完成,允许主工单流转
*
* @param changeRecordId 主工单ID
* @return true 表示所有子单都已完成
*/
private boolean checkAllSubFlowsFinishedForMainFlow(Long changeRecordId) {
// 查询该主工单下所有子单
List<ChangeSubFlowRecord> allSubFlows = changeSubFlowRecordMapper.selectByChangeRecordId(changeRecordId);
if (CollectionUtils.isEmpty(allSubFlows)) {
return false;
}
// 检查是否所有子单都满足条件:以节点为准,节点是结束节点则认为已完成
return allSubFlows.stream().allMatch(subFlow -> {
// 判断节点是否为结束节点(9999),节点是最准确的
boolean isEndNode = ChangeFlowEnum.SUB_FLOW_END.getNodeId().equals(subFlow.getSubFlowNode());
if (isEndNode) {
// 节点是结束节点,认为已完成,允许流转
// 如果状态不对,打印日志提醒
Integer status = subFlow.getStatus();
if (!ChangeSubFlowStatusEnum.FINISHED.getStatus().equals(status)
&& !ChangeSubFlowStatusEnum.CANCELLED.getStatus().equals(status)) {
log.warn("[checkAllSubFlowsFinishedForMainFlow] 子单节点已是结束节点,但状态不正确,subFlowId:{}, status:{}, 期望状态:{}或{}",
subFlow.getSubFlowId(), status,
ChangeSubFlowStatusEnum.FINISHED.getStatus(),
ChangeSubFlowStatusEnum.CANCELLED.getStatus());
}
return true;
}
return false;
});
}
/**
* 发送子单完成/取消邮件 * 发送子单完成/取消邮件
* *
* @param subFlowRecord 子单记录 * @param subFlowRecord 子单记录
...@@ -701,6 +890,27 @@ public class ChangeSubFlowBiz { ...@@ -701,6 +890,27 @@ public class ChangeSubFlowBiz {
// mainFlowNode:设置主单的节点,用于前端判断是否允许提交执行结果 // mainFlowNode:设置主单的节点,用于前端判断是否允许提交执行结果
changeFlowVO.setMainFlowNode(mainRecord.getFlowNode()); changeFlowVO.setMainFlowNode(mainRecord.getFlowNode());
// 子单特有字段:从子单记录中获取并设置到VO中
changeFlowVO.setChangeResult(subFlowRecord.getChangeResult());
changeFlowVO.setRemark(subFlowRecord.getRemark());
changeFlowVO.setCancelReason(subFlowRecord.getCancelReason());
changeFlowVO.setChangeConfirmResultTime(subFlowRecord.getChangeConfirmResultTime());
// 查询子单的文件(替换主单的文件)
List<ChangeSubFlowFile> subFlowFiles = changeSubFlowFileService.getFileList(subFlowRecordId);
if (CollectionUtils.isNotEmpty(subFlowFiles)) {
List<ChangeFlowFile> fileList = subFlowFiles.stream().map(f -> {
ChangeFlowFile file = new ChangeFlowFile();
file.setFileName(f.getFileName());
file.setFileUrl(f.getFileUrl());
file.setFileType(f.getFileType());
return file;
}).collect(Collectors.toList());
changeFlowVO.setFiles(fileList);
} else {
changeFlowVO.setFiles(new ArrayList<>());
}
// 只保留该变更行动工单下绑定的行动项 // 只保留该变更行动工单下绑定的行动项
List<ChangeExecRecord> execRecords = changeFlowExecService.getBySubFlowRecordId(subFlowRecordId); List<ChangeExecRecord> execRecords = changeFlowExecService.getBySubFlowRecordId(subFlowRecordId);
if (CollectionUtils.isNotEmpty(execRecords)) { if (CollectionUtils.isNotEmpty(execRecords)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment