feat: HCS合同推送新增归档状态fdArchiveStatus,双章归档文件上传后即时更新合规待归档
This commit is contained in:
+11
@@ -57,6 +57,17 @@ public final class HcsContractFieldConstant {
|
||||
*/
|
||||
public static final String FIELD_FD_BUS_CONTRACT_NUMBER = "fdBusContractNumber";
|
||||
|
||||
/**
|
||||
* 归档状态(fd 模板字段):toarchive=待归档; archiving=归档中; archived=已归档; archiveerror=归档异常;
|
||||
* TMS 侧仅在双章归档文件上传(归档状态=已归档)后传 toarchive,其余状态由合规侧自行流转,未归档不传
|
||||
*/
|
||||
public static final String FIELD_FD_ARCHIVE_STATUS = "fdArchiveStatus";
|
||||
|
||||
/**
|
||||
* 归档状态取值:待归档(fdArchiveStatus,双章归档文件上传后 TMS 固定传此值)
|
||||
*/
|
||||
public static final String ARCHIVE_STATUS_TO_ARCHIVE = "toarchive";
|
||||
|
||||
/**
|
||||
* 合同标题(fd 模板字段)
|
||||
*/
|
||||
|
||||
+6
@@ -254,6 +254,12 @@ public final class HcsSyncConstant {
|
||||
*/
|
||||
public static final String CONTRACT_ATTACH_KEY_OTHER = "eopCdraftOther";
|
||||
|
||||
/**
|
||||
* TMS 合同归档状态取值:已归档(ContractManage#archiveStatus,双章归档文件上传后由审核通过逻辑维护;
|
||||
* 与合规 fdArchiveStatus 的 archived 不是同一含义,TMS 已归档对应合规 toarchive 待归档)
|
||||
*/
|
||||
public static final String TMS_ARCHIVE_STATUS_ARCHIVED = "已归档";
|
||||
|
||||
/**
|
||||
* 特批审核挂起节点展示名(currentNode,特批发起后挂起展示,结果回传后恢复)
|
||||
*/
|
||||
|
||||
+36
-2
@@ -50,6 +50,7 @@ import org.springblade.transport.service.IContractExeStageService;
|
||||
import org.springblade.transport.service.IContractManageService;
|
||||
import org.springblade.transport.support.TransportBusinessSupport;
|
||||
import org.springblade.transport.support.hcs.HcsCreditCheckSupport;
|
||||
import org.springblade.transport.support.hcs.HcsImmediatePushSupport;
|
||||
import org.springblade.transport.wrapper.ContractManageWrapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -82,6 +83,7 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
|
||||
private final HcsContractExeStageMapper hcsContractExeStageMapper;
|
||||
private final HcsCreditCheckSupport hcsCreditCheckSupport;
|
||||
private final HcsImmediatePushSupport hcsImmediatePushSupport;
|
||||
private final IContractExeStageService contractExeStageService;
|
||||
|
||||
private static final String STAGE_DRAFT = "draft";
|
||||
@@ -544,11 +546,20 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
|| !List.of(STATUS_APPROVED, STATUS_CHANGE_APPROVED).contains(source.getApprovalStatus())) {
|
||||
throw new ServiceException("仅审批通过的正式合同允许上传附件");
|
||||
}
|
||||
String nextContractFileJson = mergeApprovedContractFiles(source.getContractFileJson(), contractManage.getContractFileJson());
|
||||
String originalContractFileJson = source.getContractFileJson();
|
||||
String nextContractFileJson = mergeApprovedContractFiles(originalContractFileJson, contractManage.getContractFileJson());
|
||||
source.setContractFileJson(nextContractFileJson);
|
||||
source.setAttachmentsJson(TransportBusinessSupport.trimToNull(contractManage.getAttachmentsJson()));
|
||||
refreshArchiveStatusOnApprove(source);
|
||||
return updateById(source);
|
||||
boolean saved = updateById(source);
|
||||
// 本次新增双章归档文件:事务提交后即时推送合规归档状态(C103-11 带 fdArchiveStatus=toarchive + 归档附件挂其他附件面板);
|
||||
// 合同尚未发起合规(无 hcs_fd_id)时首次推送报文自带归档状态,无需单独推送
|
||||
String newSealFilesJson = extractNewSealFilesJson(originalContractFileJson, contractManage.getContractFileJson());
|
||||
if (saved && newSealFilesJson != null && Func.isNotEmpty(source.getHcsFdId())) {
|
||||
log.info("合同上传双章归档文件触发合规归档推送:contractNo={},hcsFdId={}", source.getContractNo(), source.getHcsFdId());
|
||||
hcsImmediatePushSupport.pushContractArchiveAfterCommit(source.getId(), newSealFilesJson);
|
||||
}
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -907,6 +918,29 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取本次新增的双章归档文件 JSON(按附件键排除原有行),供合规归档推送挂载其他附件面板;无新增返回 null
|
||||
*/
|
||||
private String extractNewSealFilesJson(String originalJson, String requestJson) {
|
||||
Set<String> originalKeys = new HashSet<>();
|
||||
for (Object item : parseJsonArray(originalJson)) {
|
||||
originalKeys.add(attachmentKey(item));
|
||||
}
|
||||
List<Object> newSealFiles = new ArrayList<>();
|
||||
for (Object item : parseJsonArray(requestJson)) {
|
||||
if (originalKeys.contains(attachmentKey(item))) {
|
||||
continue;
|
||||
}
|
||||
if (item instanceof Map<?, ?> map) {
|
||||
Object fileType = map.get("fileType");
|
||||
if (fileType != null && FILE_TYPE_SEAL_ARCHIVE.equals(String.valueOf(fileType).trim())) {
|
||||
newSealFiles.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newSealFiles.isEmpty() ? null : JsonUtil.toJson(newSealFiles);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private String markContractFilesApproved(String contractFileJson) {
|
||||
List<Object> files = parseJsonArray(contractFileJson);
|
||||
|
||||
+6
-2
@@ -66,6 +66,7 @@ import java.util.Objects;
|
||||
* 任一附件转传失败 → 抛出异常由整单推送失败进补偿重试(失败原因落单据 hcs_sync_msg)。
|
||||
* <p>
|
||||
* 合同链路挂载字段 fdEntityKey(v4 枚举):主文件 approved=true → eopCdraftSign(用印)、
|
||||
* 双章归档文件(fileType=双章归档文件,归档材料非用印正文)→ eopCdraftOther(其他附件,2026-10-30)、
|
||||
* 特批附件(fileType=特批附件)→ eopCdraftSpecial(随 C103-1 fdSepcailContract=true 特批流程)、其它附件 → eopCdraftOther。
|
||||
*
|
||||
* @author Chill
|
||||
@@ -106,7 +107,7 @@ public class HcsAttachmentSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析合同主文件 JSON(仅 approved=true 的文件,挂用印字段)与其它附件 JSON(挂其他附件字段)并转传
|
||||
* 解析合同主文件 JSON(仅 approved=true 的文件:双章归档文件挂其他附件字段,其余挂用印字段)与其它附件 JSON 并转传
|
||||
*
|
||||
* @param bizType 业务单据类型(HcsSyncConstant.BIZ_TYPE_*)
|
||||
* @param bizId 业务单据id
|
||||
@@ -119,8 +120,11 @@ public class HcsAttachmentSupport {
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = new ArrayList<>();
|
||||
for (Map<?, ?> file : parseJsonArray(contractFileJson)) {
|
||||
if (isApproved(file)) {
|
||||
// 双章归档文件挂其他附件面板(2026-10-30:归档材料非用印正文),其余用印材料挂用印字段
|
||||
Object fileType = file.get(HcsSyncConstant.ATTACHMENT_TYPE_FIELD);
|
||||
boolean sealArchive = fileType != null && HcsSyncConstant.ATTACHMENT_TYPE_SEAL.equals(String.valueOf(fileType).trim());
|
||||
attachmentRefs.add(this.transferOne(bizType, bizId, file, operatorLoginName,
|
||||
HcsSyncConstant.CONTRACT_ATTACH_KEY_SEAL));
|
||||
sealArchive ? HcsSyncConstant.CONTRACT_ATTACH_KEY_OTHER : HcsSyncConstant.CONTRACT_ATTACH_KEY_SEAL));
|
||||
}
|
||||
}
|
||||
for (Map<?, ?> attachment : parseJsonArray(attachmentsJson)) {
|
||||
|
||||
+51
-5
@@ -251,7 +251,7 @@ public class HcsContractSyncSupport {
|
||||
markSynced(contractManage, fdContractId, resultMessage);
|
||||
}
|
||||
} else {
|
||||
updateContract(contractManage, risky);
|
||||
updateContract(contractManage, null, risky);
|
||||
resultMessage = "合同更新成功:" + contractManage.getContractNo();
|
||||
markSynced(contractManage, contractManage.getHcsFdId(), resultMessage);
|
||||
}
|
||||
@@ -402,11 +402,12 @@ public class HcsContractSyncSupport {
|
||||
}
|
||||
|
||||
/**
|
||||
* C103-11 合同更新(入参同发起,v4 新增顶层 fdId 定位已有合同);risky=true 时报文带 fdSepcailContract=true
|
||||
* C103-11 合同更新(入参同发起,v4 新增顶层 fdId 定位已有合同);risky=true 时报文带 fdSepcailContract=true;
|
||||
* attachmentRefs 归档推送传新增双章归档文件引用(挂其他附件面板),常规变更更新传 null 不挂载
|
||||
*/
|
||||
private void updateContract(ContractManage contractManage, boolean risky) {
|
||||
HcsContractDraftDTO param = buildDraftParam(contractManage, null, risky);
|
||||
log.info("HCS合同推送开始:{}(C103-11 更新,附件不重复挂载待联调确认,特批流程={})", contractManage.getContractNo(), risky);
|
||||
private void updateContract(ContractManage contractManage, List<HcsAttachmentRefDTO> attachmentRefs, boolean risky) {
|
||||
HcsContractDraftDTO param = buildDraftParam(contractManage, attachmentRefs, risky);
|
||||
log.info("HCS合同推送开始:{}(C103-11 更新,挂载附件 {} 个,特批流程={})", contractManage.getContractNo(), attachmentRefs == null ? 0 : attachmentRefs.size(), risky);
|
||||
HcsResult<Void> result = hcsClient.contractUpdate(param);
|
||||
if (result == null || !result.isSuccess()) {
|
||||
log.error("HCS合同更新失败响应:{},contractNo={}", result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), contractManage.getContractNo());
|
||||
@@ -414,6 +415,47 @@ public class HcsContractSyncSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 双章归档文件上传后即时归档推送(C103-11 更新):报文随 fdArchiveStatus=toarchive(buildXformFields 按
|
||||
* TMS 归档状态=已归档 传值),并把本次新增的双章归档文件转传挂载其他附件面板(eopCdraftOther,2026-10-30)。
|
||||
* 合同尚未发起合规(无 hcs_fd_id)时跳过——首次推送 C103-1 报文自带归档状态与归档附件;
|
||||
* 特批标志不重触发(risky 固定 false,特批随首次发起一次性完成),特批审核中跳过避免干扰在途流程;
|
||||
* 失败由调用方留痕,可重新上传双章归档文件或变更重推补偿
|
||||
*
|
||||
* @param contractId 合同单ID
|
||||
* @param newSealFilesJson 本次新增的双章归档文件元数据 JSON 数组(updateAttachments 按附件键排除原有行提取)
|
||||
* @return 推送结果描述
|
||||
*/
|
||||
public String pushArchiveUpdate(Long contractId, String newSealFilesJson) {
|
||||
ContractManage contractManage = contractManageMapper.selectById(contractId);
|
||||
if (contractManage == null) {
|
||||
log.warn("HCS合同归档推送跳过(合同不存在):id={}", contractId);
|
||||
return "合同不存在,跳过归档推送";
|
||||
}
|
||||
if (StringUtil.isBlank(contractManage.getHcsFdId())) {
|
||||
log.info("HCS合同归档推送跳过(尚未发起合规,归档状态随首次推送报文携带):contractNo={}", contractManage.getContractNo());
|
||||
return "合同尚未发起合规,归档状态随首次推送携带";
|
||||
}
|
||||
if (!List.of("approved", "change_approved").contains(contractManage.getApprovalStatus())
|
||||
|| HcsSyncConstant.SPEC_STATUS_PROCESSING.equals(contractManage.getHcsSpecStatus())
|
||||
|| !HcsSyncConstant.TMS_ARCHIVE_STATUS_ARCHIVED.equals(contractManage.getArchiveStatus())) {
|
||||
log.info("HCS合同归档推送跳过(状态不满足):contractNo={},approvalStatus={},hcsSpecStatus={},archiveStatus={}",
|
||||
contractManage.getContractNo(), contractManage.getApprovalStatus(), contractManage.getHcsSpecStatus(), contractManage.getArchiveStatus());
|
||||
return "合同状态不满足归档推送条件,跳过";
|
||||
}
|
||||
// 本次新增双章归档文件转传(映射表命中复用合规附件ID防重复上传)并统一挂载其他附件面板
|
||||
List<HcsAttachmentRefDTO> attachmentRefs = hcsProperties.getAttachment().isTransferEnabled()
|
||||
? hcsAttachmentSupport.transferAttachments(HcsSyncConstant.BIZ_TYPE_CONTRACT, contractManage.getId(),
|
||||
newSealFilesJson, hcsProperties.getOperatorLoginName()) : new ArrayList<>();
|
||||
for (HcsAttachmentRefDTO attachmentRef : attachmentRefs) {
|
||||
attachmentRef.setFdEntityKey(HcsSyncConstant.CONTRACT_ATTACH_KEY_OTHER);
|
||||
}
|
||||
updateContract(contractManage, attachmentRefs, false);
|
||||
String resultMessage = "合同归档推送成功(fdArchiveStatus=toarchive,挂载归档附件 " + attachmentRefs.size() + " 个):" + contractManage.getContractNo();
|
||||
markSynced(contractManage, contractManage.getHcsFdId(), resultMessage);
|
||||
return resultMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装 C103-1/C103-11 入参(字段标注照 §3.4 规范,映射表见设计文档 §5.2);
|
||||
* attachmentRefs 新建传合规附件引用列表(顶层 attachment,fdId+fdEntityKey,必填,无附件传空列表),更新传 null 不挂载
|
||||
@@ -459,6 +501,10 @@ public class HcsContractSyncSupport {
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_CONTRACT_NO, "合同编号", contractManage.getContractNo()));
|
||||
// 【必填】业务合同号:合规侧 2026-10-30 新增,值同合同编号 contractNo
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_FD_BUS_CONTRACT_NUMBER, "业务合同号", contractManage.getContractNo()));
|
||||
// 归档状态:TMS 已归档(双章归档文件已上传)→ toarchive 待归档(archiving/archived/archiveerror 由合规侧自行流转,未归档不传)
|
||||
if (HcsSyncConstant.TMS_ARCHIVE_STATUS_ARCHIVED.equals(contractManage.getArchiveStatus())) {
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_FD_ARCHIVE_STATUS, "归档状态", HcsContractFieldConstant.ARCHIVE_STATUS_TO_ARCHIVE));
|
||||
}
|
||||
// 【必填】合同标题:ContractManage.contractName
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_FD_SUBJECT, "合同标题", contractManage.getContractName()));
|
||||
fields.add(field(HcsContractFieldConstant.FIELD_CONTRACT_NAME, "合同名称", contractManage.getContractName()));
|
||||
|
||||
+22
@@ -131,6 +131,17 @@ public class HcsImmediatePushSupport {
|
||||
this.submitAfterCommit(HcsSyncConstant.BIZ_TYPE_CONTRACT, id, () -> this.pushContractNow(id), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同双章归档文件上传后即时归档推送(C103-11 更新带 fdArchiveStatus=toarchive + 归档附件挂其他附件面板):
|
||||
* 须在附件保存事务内调用(afterCommit 触发),失败仅留痕(可重新上传双章归档文件或变更重推补偿)
|
||||
*
|
||||
* @param id 合同单ID
|
||||
* @param newSealFilesJson 本次新增的双章归档文件元数据 JSON 数组
|
||||
*/
|
||||
public void pushContractArchiveAfterCommit(Long id, String newSealFilesJson) {
|
||||
this.submitAfterCommit(HcsSyncConstant.BIZ_TYPE_CONTRACT, id, () -> this.pushContractArchiveNow(id, newSealFilesJson), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 付款申请审批通过后即时发起付款特批(C106-3,无需特批则直接推履约数据):
|
||||
* 须在审批事务内调用(afterCommit 触发);按"审批即发起特批"要求不受 immediate-enabled 开关控制
|
||||
@@ -280,6 +291,17 @@ public class HcsImmediatePushSupport {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同归档推送执行体:合同未发起合规/状态不满足由 Support 内部跳过,失败仅留痕
|
||||
*/
|
||||
private void pushContractArchiveNow(Long id, String newSealFilesJson) {
|
||||
try {
|
||||
hcsContractSyncSupport.pushArchiveUpdate(id, newSealFilesJson);
|
||||
} catch (Exception exception) {
|
||||
log.error("HCS合同归档推送失败(可重新上传双章归档文件或变更重推补偿):id={},{}", id, exception.getMessage(), exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 付款推送执行体:非审批通过/已同步短路跳过;失败已由 Support markFailed,仅留痕交扫描/手动重推补偿
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user