From fab04f8f2e287fd3194c3db7179901f003001109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Fri, 30 Oct 2026 20:45:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20HCS=E5=90=88=E5=90=8C=E6=8E=A8=E9=80=81?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BD=92=E6=A1=A3=E7=8A=B6=E6=80=81fdArchive?= =?UTF-8?q?Status=EF=BC=8C=E5=8F=8C=E7=AB=A0=E5=BD=92=E6=A1=A3=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=B8=8A=E4=BC=A0=E5=90=8E=E5=8D=B3=E6=97=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=90=88=E8=A7=84=E5=BE=85=E5=BD=92=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../constant/HcsContractFieldConstant.java | 11 ++++ .../transport/constant/HcsSyncConstant.java | 6 ++ .../impl/ContractManageServiceImpl.java | 38 ++++++++++++- .../support/hcs/HcsAttachmentSupport.java | 8 ++- .../support/hcs/HcsContractSyncSupport.java | 56 +++++++++++++++++-- .../support/hcs/HcsImmediatePushSupport.java | 22 ++++++++ 6 files changed, 132 insertions(+), 9 deletions(-) diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsContractFieldConstant.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsContractFieldConstant.java index fa3bace4..952d96f9 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsContractFieldConstant.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsContractFieldConstant.java @@ -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 模板字段) */ diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsSyncConstant.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsSyncConstant.java index 272a735b..ce920802 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsSyncConstant.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsSyncConstant.java @@ -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,特批发起后挂起展示,结果回传后恢复) */ diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java index dac0cdca..ea0274ce 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java @@ -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 originalKeys = new HashSet<>(); + for (Object item : parseJsonArray(originalJson)) { + originalKeys.add(attachmentKey(item)); + } + List 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 files = parseJsonArray(contractFileJson); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsAttachmentSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsAttachmentSupport.java index 07bcfeb0..34f944d0 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsAttachmentSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsAttachmentSupport.java @@ -66,6 +66,7 @@ import java.util.Objects; * 任一附件转传失败 → 抛出异常由整单推送失败进补偿重试(失败原因落单据 hcs_sync_msg)。 *

* 合同链路挂载字段 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 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)) { diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSyncSupport.java index b2968ee1..946f1f54 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSyncSupport.java @@ -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 attachmentRefs, boolean risky) { + HcsContractDraftDTO param = buildDraftParam(contractManage, attachmentRefs, risky); + log.info("HCS合同推送开始:{}(C103-11 更新,挂载附件 {} 个,特批流程={})", contractManage.getContractNo(), attachmentRefs == null ? 0 : attachmentRefs.size(), risky); HcsResult 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 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())); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsImmediatePushSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsImmediatePushSupport.java index fc0339ce..eee77238 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsImmediatePushSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsImmediatePushSupport.java @@ -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,仅留痕交扫描/手动重推补偿 */