🐛 修复审核通过后再提交未新建MK流程实例的问题

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-29 02:44:48 +08:00
parent fc1e9a95de
commit 32cff235e0
9 changed files with 108 additions and 13 deletions
@@ -42,6 +42,7 @@ public interface IBusinessProcessClient {
String GET_CURRENT_NODES = API_PREFIX + "/getCurrentNodes";
String GET_PROCESS_INFO = API_PREFIX + "/getProcessInfo";
String RESOLVE_BY_FORM_INSTANCE_ID = API_PREFIX + "/resolveByFormInstanceId";
String MARK_PROCESS_FINISHED = API_PREFIX + "/markProcessFinished";
/**
* 提交业务流程
@@ -137,4 +138,15 @@ public interface IBusinessProcessClient {
*/
@GetMapping(RESOLVE_BY_FORM_INSTANCE_ID)
FR<MkFormBindVO> resolveByFormInstanceId(@RequestParam("formInstanceId") Long formInstanceId);
/**
* 公开页流程结束时标记业务流程通过/驳回并完结
*
* @param processInstanceId 流程实例id
* @param approved true=通过 false=驳回
* @return 是否更新成功
*/
@PostMapping(MARK_PROCESS_FINISHED)
FR<Boolean> markProcessFinished(@RequestParam("processInstanceId") String processInstanceId,
@RequestParam("approved") boolean approved);
}
@@ -102,4 +102,12 @@ public class BusinessProcessClient implements IBusinessProcessClient {
public FR<MkFormBindVO> resolveByFormInstanceId(@RequestParam("formInstanceId") Long formInstanceId) {
return FR.data(businessProcessService.resolveByFormInstanceId(formInstanceId));
}
@PreAuth(AuthConstant.PERMIT_ALL)
@PostMapping(MARK_PROCESS_FINISHED)
@Override
public FR<Boolean> markProcessFinished(@RequestParam("processInstanceId") String processInstanceId,
@RequestParam("approved") boolean approved) {
return FR.data(businessProcessService.markProcessFinished(processInstanceId, approved));
}
}
@@ -58,6 +58,15 @@ public interface IBusinessProcessService extends IService<BusinessProcess> {
*/
MkFormBindVO resolveByFormInstanceId(Long formInstanceId);
/**
* 公开页流程结束时标记业务流程通过/驳回并完结
*
* @param processInstanceId 流程实例id
* @param approved true=通过 false=驳回
* @return 是否更新成功
*/
boolean markProcessFinished(String processInstanceId, boolean approved);
/**
* 获取流程当前节点详情
*
@@ -62,13 +62,14 @@ public interface IMkFormBindService extends IService<MkFormBind> {
MkFormBindVO resolveByFormInstanceId(Long formInstanceId);
/**
* 解析或生成表单实例id:无当前绑定则新建;当前流程已审批通过则新建;否则复用
* 解析或生成表单实例id:无当前绑定则新建;强制新建/当前流程已通过或已完结则新建;否则复用
*
* @param bizType 业务类型
* @param bizId 业务主键
* @param bizType 业务类型
* @param bizId 业务主键
* @param forceNew 是否强制生成新表单实例(审核通过后再次提交)
* @return 本次应使用的表单实例id
*/
Long resolveOrCreateFormInstanceId(String bizType, Long bizId);
Long resolveOrCreateFormInstanceId(String bizType, Long bizId, boolean forceNew);
/**
* 回写流程实例id到当前绑定
@@ -140,7 +140,8 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
String bizType = param.getBizType();
Long bizId = resolveBizIdFromSubmitParam(param);
Long formInstanceId = mkFormBindService.resolveOrCreateFormInstanceId(bizType, bizId);
boolean forceNew = Boolean.TRUE.equals(param.getForceNewFormInstance());
Long formInstanceId = mkFormBindService.resolveOrCreateFormInstanceId(bizType, bizId, forceNew);
String formInstanceIdText = String.valueOf(formInstanceId);
param.setFormInstanceId(formInstanceIdText);
@@ -149,8 +150,8 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
.orderByDesc(BusinessProcess::getUpdateTime)
.last("limit 1")
);
// 已有流程实例且 MK 仍能查到详情时,不再删除、不再重新创建提交
if (businessProcess != null && StringUtil.isNotBlank(businessProcess.getProcessInstanceId())
// 已有流程实例且 MK 仍能查到详情时,不再删除、不再重新创建提交(强制新建时跳过短路)
if (!forceNew && businessProcess != null && StringUtil.isNotBlank(businessProcess.getProcessInstanceId())
&& Objects.equals(formInstanceId, businessProcess.getFormInstanceId())) {
String existingProcessInstanceId = businessProcess.getProcessInstanceId();
Object existingProcessInfo = this.getProcessInfo(existingProcessInstanceId, loginName);
@@ -247,8 +248,9 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
if (businessProcess == null || StringUtil.isBlank(businessProcess.getProcessInstanceId())) {
return false;
}
// 审批通过后允许再次提交新表单实例,视为当前无有效待办流程
if (Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus())) {
// 审批通过 / 已完结:允许再次提交新表单实例
if (Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus())
|| (businessProcess.getIsCompleted() != null && businessProcess.getIsCompleted() == 1)) {
return false;
}
String loginName = businessProcess.getPromoterLoginName();
@@ -261,9 +263,24 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
return false;
}
Object processInfo = this.getProcessInfo(businessProcess.getProcessInstanceId(), loginName);
// MK 流程已结束(fdProcessStatus=30)时视为无有效待办,需重新提交新实例
if (isMkProcessFinished(processInfo)) {
return false;
}
return hasProcessInfoData(processInfo);
}
/**
* MK getProcessInfo 是否为已结束流程
*/
private boolean isMkProcessFinished(Object processInfo) {
if (!(processInfo instanceof Map<?, ?> map)) {
return false;
}
Object status = map.get("fdProcessStatus");
return status != null && "30".equals(String.valueOf(status));
}
/**
* MK getProcessInfo 是否返回有效数据
*/
@@ -345,6 +362,30 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
return fallback;
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean markProcessFinished(String processInstanceId, boolean approved) {
AssertUtils.notBlank(processInstanceId, "流程实例id不能为空");
BusinessProcess businessProcess = this.getBusinessProcessByProcessInstanceId(processInstanceId);
if (businessProcess == null) {
log.warn("标记流程完结跳过,未找到业务流程 processInstanceId={}", processInstanceId);
return false;
}
String approveStatus = approved
? ApproveStatusEnum.APPROVED.getValue()
: ApproveStatusEnum.REJECTED.getValue();
businessProcess.setApproveStatus(approveStatus);
businessProcess.setIsCompleted(1);
businessProcess.setCompleteTime(new Date());
businessProcess.setCurrentNodeIds(null);
businessProcess.setCurrentNodeNames(null);
businessProcess.setCurrentHandlers(null);
boolean updated = this.updateById(businessProcess);
log.info("标记流程完结 processInstanceId={} approved={} approveStatus={} result={}",
processInstanceId, approved, approveStatus, updated);
return updated;
}
@Override
public List<?> getCurrentNodes(String processInstanceId, String loginName) {
if (StringUtils.isBlank(processInstanceId)) {
@@ -619,6 +660,7 @@ public class BusinessProcessServiceImpl extends ServiceImpl<BusinessProcessMappe
if (processInstanceIdBlank) {
BusinessProcess businessProcess = this.getOne(Wrappers.<BusinessProcess>lambdaQuery()
.eq(BusinessProcess::getBizId, bizId)
.orderByDesc(BusinessProcess::getUpdateTime)
.last("limit 1")
);
AssertUtils.notNull(businessProcess, "业务流程不存在");
@@ -109,7 +109,7 @@ public class MkFormBindServiceImpl extends ServiceImpl<MkFormBindMapper, MkFormB
@Transactional(rollbackFor = Exception.class)
@Override
public Long resolveOrCreateFormInstanceId(String bizType, Long bizId) {
public Long resolveOrCreateFormInstanceId(String bizType, Long bizId, boolean forceNew) {
AssertUtils.notNull(bizId, "业务id不能为空");
MkFormBind current = this.getCurrentBind(bizType, bizId);
if (current == null) {
@@ -122,9 +122,12 @@ public class MkFormBindServiceImpl extends ServiceImpl<MkFormBindMapper, MkFormB
);
boolean approvedPass = businessProcess != null
&& Objects.equals(ApproveStatusEnum.APPROVED.getValue(), businessProcess.getApproveStatus());
if (approvedPass) {
log.info("审核通过后再次提交,生成新表单实例 bizType={} bizId={} oldFormInstanceId={}",
bizType, bizId, current.getFormInstanceId());
boolean completed = businessProcess != null
&& businessProcess.getIsCompleted() != null
&& businessProcess.getIsCompleted() == 1;
if (forceNew || approvedPass || completed) {
log.info("生成新表单实例 forceNew={} approvedPass={} completed={} bizType={} bizId={} oldFormInstanceId={}",
forceNew, approvedPass, completed, bizType, bizId, current.getFormInstanceId());
this.lambdaUpdate()
.eq(MkFormBind::getBizId, bizId)
.eq(MkFormBind::getIsCurrent, 1)
@@ -151,6 +151,14 @@ public class MkProcessMessageService {
} else {
handler.rejectFromProcess(bizId, processorName);
}
try {
FR<Boolean> markResult = businessProcessClient.markProcessFinished(processId, approved);
log.info("公开页标记业务流程完结 bizType={} processId={} approved={} result={}",
bizType, processId, approved, JSON.toJSONString(markResult));
} catch (Exception markException) {
log.error("公开页标记业务流程完结失败 bizType={} processId={} approved={}",
bizType, processId, approved, markException);
}
} catch (NumberFormatException e) {
log.warn("流程{}但业务id格式不正确 bizType={} id={}", action, bizType, bizIdText);
} catch (Exception e) {
@@ -143,6 +143,13 @@ public class CustomerArchivePublicProcessService {
} else {
customerArchiveService.rejectFromProcess(customerId, processorName);
}
try {
FR<Boolean> markResult = businessProcessClient.markProcessFinished(processId, approved);
log.info("客商公开页标记业务流程完结 processId={} approved={} result={}",
processId, approved, JSON.toJSONString(markResult));
} catch (Exception markException) {
log.error("客商公开页标记业务流程完结失败 processId={} approved={}", processId, approved, markException);
}
} catch (NumberFormatException e) {
log.warn("流程{}但客商id格式不正确:{}", action, customerIdText);
} catch (Exception e) {
@@ -55,4 +55,9 @@ public class MKProcessCreateDTO implements Serializable {
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String bizType;
/**
* 强制生成新表单实例(审核通过后再次提交),仅 ERP 内部使用,不传给 MK
*/
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Boolean forceNewFormInstance;
}