From 68885ab31e587532f5cd51f95fc754bd72123ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Tue, 13 Oct 2026 18:36:24 +0800 Subject: [PATCH] =?UTF-8?q?:refactor:=20=E5=90=88=E5=90=8C=E7=89=B9?= =?UTF-8?q?=E6=89=B9=E6=94=B9=E4=B8=BA=E9=9A=8F=E8=B5=B7=E8=8D=89=E6=8A=A5?= =?UTF-8?q?=E6=96=87=20fdSepcailContract=20=E5=8F=91=E8=B5=B7=EF=BC=8C?= =?UTF-8?q?=E5=88=A0=E9=99=A4=20C103-8=20=E9=93=BE=E8=B7=AF=E5=B9=B6?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=BB=93=E6=9E=9C=E5=9B=9E=E8=B0=83=E6=8A=A5?= =?UTF-8?q?=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C103-8 独立特批发起接口合规未提供(联调 404):删除 IHcsClient#addSpecContract、SPEC_CONTRACT_ADD_URL、HcsSpecContractSaveDTO、applySpec 及辅助方法、人工端点 POST /hcs/contract/spec-apply - 高风险/黑名单客商合同推送时 C103-1/C103-11 报文携带 fdSepcailContract=true,合规侧随起草自动走特批流程;推送门禁与手动重推仅拦截 processing,need 存量卡单重推自愈 - 推送成功后 hangSpecReview 挂起"特批审核"(processing),含 approved/rejected 终态守卫防合规秒批回调竞态覆盖 - 特批附件随 C103-1 附件面板 eopCdraftSpecial 挂载(原全部走 eopCdraftOther) - contractLegal/result 回调报文按合规方最新字段表修正(HcsContractLegalResultDTO:contractCode/success/kingdeeId/sourceSystem=WCCK),按合同编号定位合同,success=true 联动放行、false 联动审批驳回 --- .../transport/constant/HcsSyncConstant.java | 6 +- .../controller/HcsSyncController.java | 34 +-- .../support/hcs/HcsAttachmentSupport.java | 8 +- .../hcs/HcsContractSpecSyncSupport.java | 255 +++++++----------- .../support/hcs/HcsContractSyncSupport.java | 123 +++------ ...TO.java => HcsContractLegalResultDTO.java} | 36 +-- .../org/springblade/hcs/feign/IHcsClient.java | 17 +- 7 files changed, 171 insertions(+), 308 deletions(-) rename blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/{HcsSpecContractSaveDTO.java => HcsContractLegalResultDTO.java} (55%) 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 6e4da84b..a99ec2cd 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 @@ -85,7 +85,7 @@ public final class HcsSyncConstant { public static final String CHECK_TYPE_CREDIT = "credit"; /** - * 校验类型:合同特批(C103-8 发起 / 合规特批结果推送留痕) + * 校验类型:合同特批(合规特批结果推送/查询联动留痕;原 C103-8 发起留痕随接口删除) */ public static final String CHECK_TYPE_SPEC = "spec"; @@ -176,9 +176,9 @@ public final class HcsSyncConstant { public static final String ATTACHMENT_TYPE_FIELD = "fileType"; /** - * 附件类型:特批说明(高风险/黑名单客商合同必须上传;中文匹配沿用 FILE_TYPE_SEAL_ARCHIVE="双章归档文件" 惯例) + * 附件类型:特批附件(高风险/黑名单客商合同必须上传;值取业务字典 contract_attachment_type,中文匹配沿用 FILE_TYPE_SEAL_ARCHIVE="双章归档文件" 惯例) */ - public static final String ATTACHMENT_TYPE_SPEC_EXPLANATION = "特批说明"; + public static final String ATTACHMENT_TYPE_SPEC_EXPLANATION = "特批附件"; /** * 附件类型:用印附件(双章归档文件,取值沿用 ContractManageServiceImpl#FILE_TYPE_SEAL_ARCHIVE) diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/HcsSyncController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/HcsSyncController.java index ec573299..32acee07 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/HcsSyncController.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/HcsSyncController.java @@ -38,6 +38,7 @@ import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.tool.api.R; import org.springblade.core.tool.utils.StringUtil; import org.springblade.hcs.dto.HcsAttachmentRefDTO; +import org.springblade.hcs.dto.HcsContractLegalResultDTO; import org.springblade.hcs.dto.HcsCurrencyVO; import org.springblade.hcs.dto.HcsLegalResultDTO; import org.springblade.hcs.dto.HcsTemplateVO; @@ -216,35 +217,6 @@ public class HcsSyncController { } } - /** - * 合同发起特批(C103-8,前端接入设计 §3.4):body = { contractId, attachments: [{fdId, name}] } - */ - @PostMapping("/contract/spec-apply") - @ApiOperationSupport(order = 13) - @Operation(summary = "合同发起特批", description = "C103-8:高风险客商合同特批发起,attachments 为经 /hcs/attachment/upload 上传的合规附件引用") - @SuppressWarnings("unchecked") - public R applyContractSpec(@RequestBody Map body) { - Object contractIdValue = body == null ? null : body.get("contractId"); - if (contractIdValue == null || StringUtil.isBlank(String.valueOf(contractIdValue))) { - return R.fail("contractId 不能为空"); - } - Long contractId = Long.valueOf(String.valueOf(contractIdValue)); - Object attachmentsValue = body == null ? null : body.get("attachments"); - List attachments = (attachmentsValue instanceof List list ? list : List.of()).stream() - .filter(Map.class::isInstance) - .map(item -> { - Map attachment = (Map) item; - HcsAttachmentRefDTO ref = new HcsAttachmentRefDTO(); - // 附件ID:C103-2 上传返回的合规附件ID - ref.setFdId(String.valueOf(attachment.get("fdId"))); - // 附件名 - ref.setFdFileName(attachment.get("name") == null ? null : String.valueOf(attachment.get("name"))); - return ref; - }) - .toList(); - return R.data(hcsContractSpecSyncSupport.applySpec(contractId, attachments)); - } - /** * 合同特批结果人工确认(§6-U1 过渡方案:与合规推送等效) */ @@ -266,8 +238,8 @@ public class HcsSyncController { */ @PostMapping("/contractLegal/result") @ApiOperationSupport(order = 15) - @Operation(summary = "合同特批结果回传接收", description = "合规系统推送合同特批结果,按合同ID定位并联动特批状态,原文留痕") - public R contractLegalResult(@RequestBody(required = false) HcsLegalResultDTO param) { + @Operation(summary = "合同特批结果回传接收", description = "合规系统推送合同特批(金蝶同步)结果,按合同编号定位并联动特批状态,原文留痕") + public R contractLegalResult(@RequestBody(required = false) HcsContractLegalResultDTO param) { return R.data(hcsContractSpecSyncSupport.handleLegalResult(param)); } 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 8e63c988..07bcfeb0 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,7 +66,7 @@ import java.util.Objects; * 任一附件转传失败 → 抛出异常由整单推送失败进补偿重试(失败原因落单据 hcs_sync_msg)。 *

* 合同链路挂载字段 fdEntityKey(v4 枚举):主文件 approved=true → eopCdraftSign(用印)、 - * 其它附件 → eopCdraftOther、特批说明 → eopCdraftSpecial(C103-8 特批链路)。 + * 特批附件(fileType=特批附件)→ eopCdraftSpecial(随 C103-1 fdSepcailContract=true 特批流程)、其它附件 → eopCdraftOther。 * * @author Chill */ @@ -124,8 +124,10 @@ public class HcsAttachmentSupport { } } for (Map attachment : parseJsonArray(attachmentsJson)) { - attachmentRefs.add(this.transferOne(bizType, bizId, attachment, operatorLoginName, - HcsSyncConstant.CONTRACT_ATTACH_KEY_OTHER)); + // 特批附件(fileType=特批附件)挂特批面板字段,其余挂其他附件字段(2026-10-13:特批改随 C103-1 fdSepcailContract 发起) + String entityKey = HcsSyncConstant.ATTACHMENT_TYPE_SPEC_EXPLANATION.equals(attachment.get(HcsSyncConstant.ATTACHMENT_TYPE_FIELD)) + ? HcsSyncConstant.CONTRACT_ATTACH_KEY_SPECIAL : HcsSyncConstant.CONTRACT_ATTACH_KEY_OTHER; + attachmentRefs.add(this.transferOne(bizType, bizId, attachment, operatorLoginName, entityKey)); } return attachmentRefs; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSpecSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSpecSyncSupport.java index 820df7fb..27eaaad4 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSpecSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsContractSpecSyncSupport.java @@ -25,20 +25,17 @@ */ package org.springblade.transport.support.hcs; -import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springblade.core.log.exception.ServiceException; import org.springblade.core.tool.utils.StringUtil; -import org.springblade.hcs.config.HcsProperties; -import org.springblade.hcs.dto.HcsAttachmentRefDTO; +import org.springblade.hcs.dto.HcsContractDetailQueryDTO; +import org.springblade.hcs.dto.HcsContractDetailVO; +import org.springblade.hcs.dto.HcsContractLegalResultDTO; import org.springblade.hcs.dto.HcsLegalResultDTO; -import org.springblade.hcs.dto.HcsMechanismsDTO; import org.springblade.hcs.dto.HcsResult; -import org.springblade.hcs.dto.HcsSpecContractSaveDTO; -import org.springblade.hcs.dto.HcsFormSaveVO; -import org.springblade.hcs.exception.HcsException; import org.springblade.hcs.feign.IHcsClient; import org.springblade.transport.constant.HcsSyncConstant; import org.springblade.transport.mapper.ContractManageMapper; @@ -51,15 +48,14 @@ import java.time.LocalDateTime; import java.util.List; /** - * HCS 合同特批同步支撑组件(C103-8 发起特批 / 合规特批结果推送接收,前端接入设计 §3.4) + * HCS 合同特批同步支撑组件(合规特批结果接收:contractLegal/result 推送 + C103-4 定时查询兜底 + 人工确认)。 *

- * 业务闭环:合同推送时 C101-1 风险校验发现黑名单 → 置 hcs_spec_status=need 挂起(推送链路门禁跳过)→ - * 内部特批审批通过后,前端上传特批材料(C103-2 取合规附件ID)并发起 C103-8 → 状态 processing(流程挂起)→ - * 集团审批结果经合规 contractLegal/result 接口推送 TMS(替代未建设的 B103)→ - * approved 恢复流程,rejected 可重新发起。 + * 业务闭环(2026-10-13 起):高风险/黑名单客商合同随 C103-1/C103-11 报文 fdSepcailContract=true 在合规侧走特批流程 + * (C103-8 独立发起接口合规未提供,已删除),TMS 挂起"特批审核"(processing)→ + * 集团审批结果经合规 contractLegal/result 接口推送 TMS(替代未建设的 B103),或定时 C103-4 查询兜底联动 → + * approved 恢复流程,rejected 联动合同审批驳回。 *

- * TODO 待联调确认(前端接入设计 §6-U1):C103-8 报文 v4 未提供,按 C106-3 模式预估(双层嵌套返回); - * 结果推送报文 {sourceSystem, requestId=合同ID, status=APPROVED/REJECTED, reason},原文留痕 blade_hcs_check_log。 + * 结果推送报文 {contractType, contractCode, requestId, success, reason, kingdeeId, sourceSystem=WCCK},原文留痕 blade_hcs_check_log。 * * @author Chill */ @@ -69,9 +65,19 @@ import java.util.List; public class HcsContractSpecSyncSupport { /** - * 特批附件字段标识(照 C106-3 fd_spc_approval_attach 惯例预估,§6-U1 以合规方报文为准) + * C103-4 合同审批状态:已审批(fdApprovalStatus,小写枚举) */ - private static final String SPEC_ATTACH_ENTITY_KEY = "fd_spc_approval_attach"; + private static final String LEGAL_STATUS_APPROVED = "approved"; + + /** + * C103-4 合同审批状态:审批作废(特批驳回映射待联调确认,暂按作废联动驳回) + */ + private static final String LEGAL_STATUS_INVALID = "approvalinvalid"; + + /** + * 合同特批结果回传来源系统标识(合规方接口文档约定固定传 WCCK) + */ + private static final String LEGAL_CALLBACK_SRC_SYSTEM = "WCCK"; /** * 结果推送原文留痕最大长度(blade_hcs_check_log.msg 为 varchar(512)) @@ -79,55 +85,56 @@ public class HcsContractSpecSyncSupport { private static final int CALLBACK_MSG_MAX_LENGTH = 500; private final IHcsClient hcsClient; - private final HcsProperties hcsProperties; private final ContractManageMapper contractManageMapper; private final HcsContractCheckLogMapper hcsContractCheckLogMapper; /** - * 发起合同特批(C103-8):校验合同与特批状态 → 组装预估报文 → 回填特批流程ID,状态置 processing + * 特批结果定时查询兜底(合规推送 contractLegal/result 未达/未配置时的补偿,2026-10-13): + * 扫描特批中(processing)的合同,按 C103-4 合同详情 fdApprovalStatus 联动—— + * approved 恢复"审批通过"、approvalinvalid 联动审批驳回(特批驳回的合规侧状态待联调确认,暂按作废映射)、其余等待中跳过; + * 与结果推送互不冲突(推送先到则状态已非 processing,查询自然跳过) * - * @param contractId 合同ID - * @param attachments 特批附件引用(fdId=C103-2 合规附件ID,fdFileName=文件名) - * @return 结果描述 + * @return 结果汇总(供任务日志) */ - public String applySpec(Long contractId, List attachments) { - ContractManage contractManage = requireAppliableContract(contractId); - if (attachments == null || attachments.isEmpty()) { - throw new ServiceException("请先上传特批申请材料(含内部审批流程附件)"); + public String syncProcessingSpecResults() { + List contracts = contractManageMapper.selectList(Wrappers.lambdaQuery() + .eq(ContractManage::getHcsSpecStatus, HcsSyncConstant.SPEC_STATUS_PROCESSING) + .isNotNull(ContractManage::getHcsFdId) + .last("limit 50")); + if (contracts.isEmpty()) { + return "特批结果查询:无特批中合同"; } - HcsSpecContractSaveDTO param = new HcsSpecContractSaveDTO(); - // 【必填】操作人登录名:配置 thirdParty.hcs.operator-login-name(默认 srvadmin,§9-U2) - param.setFdLoginName(hcsProperties.getOperatorLoginName()); - // 【必填】合规合同ID:blade_contract_manage.hcs_fd_id(非名称,照 C106-3 fd_contract_name 惯例) - param.setFdContractId(requireContractFdId(contractManage)); - // 【必填】合同编号 - param.setFdContractNo(contractManage.getContractNo()); - // 【必填】单据主题:"合同特批-" + 合同编号 - param.setFdDocSubject("合同特批-" + contractManage.getContractNo()); - // 特批事由:合同名称(非必传) - param.setFdReason(contractManage.getContractName()); - // 特批附件:发起带 fdBindType=ADD(entityKey 预估照 C106-3,§6-U1) - param.setMechanisms(buildMechanisms(attachments)); - // 特批材料留痕(含合规附件ID,供重新发起与排查) - contractManage.setHcsSpecFilesJson(JSONUtil.toJsonStr(attachments)); - try { - log.info("HCS合同特批发起开始:contractNo={},附件 {} 个", contractManage.getContractNo(), attachments.size()); - // TODO 待联调(§6-U1):报文按 C106-3 模式预估,双层嵌套 data.data.fdId - HcsResult> result = hcsClient.addSpecContract(param); - String specFdId = extractNestedFdId(contractManage, result); - contractManage.setHcsSpecFdId(specFdId); - markSpec(contractManage, HcsSyncConstant.SPEC_STATUS_PROCESSING, "C103-8 合同特批发起成功"); - writeCheckLog(contractManage, HcsSyncConstant.CHECK_RESULT_PASS, "C103-8 特批发起成功,特批流程ID=" + specFdId, result.getTraceId()); - log.info("HCS合同特批发起成功:contractNo={},specFdId={}", contractManage.getContractNo(), specFdId); - return "特批发起成功,等待集团审批"; - } catch (Exception exception) { - String message = StringUtil.isBlank(exception.getMessage()) ? "特批发起异常" : exception.getMessage(); - // 失败保持待特批(need),允许重试发起 - markSpec(contractManage, HcsSyncConstant.SPEC_STATUS_NEED, "C103-8 特批发起失败:" + message); - writeCheckLog(contractManage, HcsSyncConstant.CHECK_RESULT_FAIL, "C103-8 特批发起失败:" + message, null); - throw exception instanceof ServiceException serviceException ? serviceException - : new ServiceException("合同特批发起失败:" + message); + int approvedCount = 0; + int rejectedCount = 0; + for (ContractManage contractManage : contracts) { + try { + HcsContractDetailQueryDTO query = new HcsContractDetailQueryDTO(); + // 【定位】合规合同ID:C103-4 fdId 与 fdNumber 二选一 + query.setFdId(contractManage.getHcsFdId()); + HcsResult result = hcsClient.contractDetail(query); + if (result == null || !result.isSuccess() || result.getData() == null) { + log.warn("HCS特批结果查询失败响应:contractNo={},{}", contractManage.getContractNo(), + result == null ? "无响应" : result.getMsg()); + continue; + } + String approvalStatus = result.getData().getFdApprovalStatus(); + if (LEGAL_STATUS_APPROVED.equalsIgnoreCase(approvalStatus)) { + syncContractOnSpecResult(contractManage, true); + markSpec(contractManage, HcsSyncConstant.SPEC_STATUS_APPROVED, "特批结果查询联动:fdApprovalStatus=approved"); + writeCheckLog(contractManage, HcsSyncConstant.CHECK_RESULT_PASS, "特批结果查询联动:fdApprovalStatus=approved", null); + approvedCount++; + } else if (LEGAL_STATUS_INVALID.equalsIgnoreCase(approvalStatus)) { + syncContractOnSpecResult(contractManage, false); + markSpec(contractManage, HcsSyncConstant.SPEC_STATUS_REJECTED, "特批结果查询联动:fdApprovalStatus=approvalinvalid"); + writeCheckLog(contractManage, HcsSyncConstant.CHECK_RESULT_FAIL, "特批结果查询联动:fdApprovalStatus=approvalinvalid", null); + rejectedCount++; + } + } catch (Exception exception) { + // 单条失败不影响其余,下轮扫描自动重试 + log.warn("HCS特批结果查询单条失败(下轮重试):contractNo={},{}", contractManage.getContractNo(), exception.getMessage()); + } } + return "特批结果查询:扫描 " + contracts.size() + " 单,联动通过 " + approvedCount + ",联动驳回 " + rejectedCount; } /** @@ -158,120 +165,60 @@ public class HcsContractSpecSyncSupport { } /** - * 合同特批结果接收处理(合规 contractLegal/result 推送,替代未建设的 B103,D15 回传机制): - * sourceSystem 须与 third-party.hcs.src-system 配置一致(不符抛出"来源系统标识错误"异常), - * requestId=TMS 合同ID、status=APPROVED/REJECTED, - * approved 恢复合同"审批通过"展示;rejected 联动合同审批驳回;原文全量留痕 + * 合同特批结果接收处理(合规 contractLegal/result 推送,2026-10-13 按合规方最新字段表修正报文结构): + * 特批完成后合规侧同步金蝶并回调,报文 {contractType, contractCode, requestId, success, reason, kingdeeId, sourceSystem=WCCK}; + * sourceSystem 须为 WCCK(不符抛"来源系统标识错误"异常);contractCode=TMS 合同编号定位(requestId 仅请求头回显不可定位); + * success=true 联动恢复"审批通过"(kingdeeId 随留痕保存);success=false 联动合同审批驳回走重新提交闭环(reason 随原文留痕) * * @param param 合规推送报文 * @return 处理结果描述 */ - public String handleLegalResult(HcsLegalResultDTO param) { - // 来源系统校验:仅接受 third-party.hcs.src-system 配置的来源,防伪造回传 - if (!StrUtil.equalsIgnoreCase(param == null ? null : param.getSourceSystem(), hcsProperties.getSrcSystem())) { + public String handleLegalResult(HcsContractLegalResultDTO param) { + // 来源系统校验:仅接受合规方约定的 WCCK,防伪造回传 + if (!LEGAL_CALLBACK_SRC_SYSTEM.equalsIgnoreCase(param == null ? null : param.getSourceSystem())) { log.warn("合同特批结果推送来源系统标识错误:sourceSystem={}", param == null ? null : param.getSourceSystem()); throw new ServiceException("来源系统标识错误"); } - String raw = param == null ? "" : JSONUtil.toJsonStr(param); - String requestId = param == null ? null : param.getRequestId(); - ContractManage contractManage = locateContract(requestId); + String raw = JSONUtil.toJsonStr(param); + ContractManage contractManage = locateContractByNo(param.getContractCode()); if (contractManage == null) { - log.warn("合同特批结果推送未定位到合同:requestId={},报文已留痕", requestId); + log.warn("合同特批结果推送未定位到合同:contractCode={},报文已留痕", param.getContractCode()); writeCallbackLog(null, HcsSyncConstant.CHECK_RESULT_SKIP, "合同特批结果推送未定位到合同:" + raw); - return "已留痕:未定位到合同(requestId=" + requestId + ")"; + return "已留痕:未定位到合同(contractCode=" + param.getContractCode() + ")"; } - String normalizedStatus = param.getStatus() == null ? "" : param.getStatus().trim(); - boolean approved; - if (HcsSyncConstant.LEGAL_RESULT_APPROVED.equalsIgnoreCase(normalizedStatus)) { - approved = true; - } else if (HcsSyncConstant.LEGAL_RESULT_REJECTED.equalsIgnoreCase(normalizedStatus)) { - approved = false; - } else { - log.warn("合同特批结果状态未识别:contractNo={},status={},报文已留痕", contractManage.getContractNo(), param.getStatus()); - writeCallbackLog(contractManage, HcsSyncConstant.CHECK_RESULT_SKIP, "合同特批结果推送状态未识别:" + raw); - return "已留痕:状态字段未识别(contractNo=" + contractManage.getContractNo() + ")"; + if (param.getSuccess() == null) { + log.warn("合同特批结果推送 success 字段缺失:contractNo={},报文已留痕", contractManage.getContractNo()); + writeCallbackLog(contractManage, HcsSyncConstant.CHECK_RESULT_SKIP, "合同特批结果推送 success 字段缺失:" + raw); + return "已留痕:success 字段缺失(contractNo=" + contractManage.getContractNo() + ")"; } - String status = approved ? HcsSyncConstant.SPEC_STATUS_APPROVED : HcsSyncConstant.SPEC_STATUS_REJECTED; - // 特批结果联动合同审批状态(通过恢复展示,驳回联动审批驳回),随 markSpec 一并落库(reason 随原文留痕) - syncContractOnSpecResult(contractManage, approved); - markSpec(contractManage, status, "合同特批结果推送:" + raw); - writeCallbackLog(contractManage, approved ? HcsSyncConstant.CHECK_RESULT_PASS : HcsSyncConstant.CHECK_RESULT_FAIL, - "合同特批结果推送:" + raw); - log.info("合同特批结果推送处理完成:contractNo={},结果={},reason={}", contractManage.getContractNo(), status, param.getReason()); - return "特批结果已处理:" + status; + boolean success = param.getSuccess(); + // 成功:特批完成且金蝶同步成功,恢复"审批通过";kingdeeId 随 hcs_spec_msg/留痕保存 + if (success) { + syncContractOnSpecResult(contractManage, true); + markSpec(contractManage, HcsSyncConstant.SPEC_STATUS_APPROVED, + "合同特批结果推送:金蝶同步成功,kingdeeId=" + param.getKingdeeId()); + writeCallbackLog(contractManage, HcsSyncConstant.CHECK_RESULT_PASS, "合同特批结果推送:" + raw); + log.info("合同特批结果推送处理完成:contractNo={},结果=approved,kingdeeId={}", contractManage.getContractNo(), param.getKingdeeId()); + return "特批结果已处理:approved"; + } + // 失败:特批流程已完成但金蝶同步失败,联动合同审批驳回,走重新编辑→提交→审批→重新特批闭环(失败单独重试机制待联调确认) + syncContractOnSpecResult(contractManage, false); + markSpec(contractManage, HcsSyncConstant.SPEC_STATUS_REJECTED, "合同特批结果推送:金蝶同步失败:" + param.getReason()); + writeCallbackLog(contractManage, HcsSyncConstant.CHECK_RESULT_FAIL, "合同特批结果推送:" + raw); + log.info("合同特批结果推送处理完成:contractNo={},结果=rejected,reason={}", contractManage.getContractNo(), param.getReason()); + return "特批结果已处理:rejected"; } /** - * 校验可发起特批的合同:存在、审批通过、特批状态为待特批/已驳回 + * 按 ERP 合同编号定位合同(合规推送 contractCode,合同编号唯一) */ - private ContractManage requireAppliableContract(Long contractId) { - ContractManage contractManage = contractManageMapper.selectById(contractId); - if (contractManage == null) { - throw new ServiceException("合同单不存在:" + contractId); - } - if (!List.of("approved", "change_approved").contains(contractManage.getApprovalStatus())) { - throw new ServiceException("仅审批通过的合同可发起特批(当前状态:" + contractManage.getApprovalStatus() + ")"); - } - if (!List.of(HcsSyncConstant.SPEC_STATUS_NEED, HcsSyncConstant.SPEC_STATUS_REJECTED).contains(contractManage.getHcsSpecStatus())) { - throw new ServiceException("仅待特批/已驳回的合同可发起特批(当前状态:" + contractManage.getHcsSpecStatus() + ")"); - } - return contractManage; - } - - /** - * 合规合同ID(合同须已推送合规回填 hcs_fd_id) - */ - private String requireContractFdId(ContractManage contractManage) { - if (StringUtil.isBlank(contractManage.getHcsFdId())) { - throw new ServiceException("合同尚未推送合规,无法发起特批(contractNo=" + contractManage.getContractNo() + ")"); - } - return contractManage.getHcsFdId(); - } - - /** - * 特批附件挂载(发起带 fdBindType=ADD) - */ - private HcsMechanismsDTO buildMechanisms(List attachments) { - HcsMechanismsDTO mechanisms = new HcsMechanismsDTO(); - mechanisms.setAttachment(attachments.stream().map(ref -> { - HcsAttachmentRefDTO attachment = new HcsAttachmentRefDTO(); - // 附件ID:C103-2 转传返回的合规附件ID - attachment.setFdId(ref.getFdId()); - // 附件名(预估字段,§6-U1) - attachment.setFdFileName(ref.getFdFileName()); - // 特批附件字段标识 - attachment.setFdEntityKey(SPEC_ATTACH_ENTITY_KEY); - // 绑定类型:发起传 ADD - attachment.setFdBindType("ADD"); - return attachment; - }).toList()); - return mechanisms; - } - - /** - * 解析 C103-8 双层嵌套返回 data.data.fdId(照 C106-3 模式预估) - */ - private String extractNestedFdId(ContractManage contractManage, HcsResult> result) { - if (result == null || !result.isSuccess() || result.getData() == null || !result.getData().isSuccess() - || result.getData().getData() == null || StringUtil.isBlank(result.getData().getData().getFdId())) { - log.error("HCS合同特批发起失败响应:{},contractNo={}", result == null ? "无响应" : String.format("msg=%s, traceId=%s", result.getMsg(), result.getTraceId()), contractManage.getContractNo()); - throw new HcsException("C103-8 合同特批发起失败:" + (result == null ? "响应为空" : result.getMsg())); - } - return result.getData().getData().getFdId(); - } - - /** - * 按 TMS 合同ID 定位合同(合规推送 requestId) - */ - private ContractManage locateContract(String requestId) { - if (StringUtil.isBlank(requestId)) { - return null; - } - try { - return contractManageMapper.selectById(Long.valueOf(requestId.trim())); - } catch (NumberFormatException exception) { + private ContractManage locateContractByNo(String contractCode) { + if (StringUtil.isBlank(contractCode)) { return null; } + return contractManageMapper.selectOne(Wrappers.lambdaQuery() + .eq(ContractManage::getContractNo, contractCode.trim()) + .last("limit 1")); } /** 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 81090586..64ed055c 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 @@ -71,8 +71,9 @@ import java.util.Objects; *

* 扫描任务按序执行:⓪ 特批挂起门禁 → ① 客商风险校验(可配开关,仅留痕,高风险不再阻断)→ * ② 附件转传(v4 挂载点 fdFieldJson.attachment,随 C103-1 挂载)→ ③ C103-3 判重(§9-U4 查询能力联调确认)→ - * ④ C103-1 起草 / 变更单 C103-11 更新(§9-U5 定位方式待联调)→ ⑤ 高风险/黑名单自动特批 C103-8(外部客商管控, - * {@link HcsContractSpecSyncSupport},挂起"特批审核"待合规推送结果)→ ⑥ 履约规则 C103-9 行级同步({@link HcsExeStageSyncSupport})。 + * ④ C103-1 起草 / 变更单 C103-11 更新(§9-U5 定位方式待联调)→ ⑤ 高风险/黑名单挂起"特批审核" + * (外部客商管控:报文随 fdSepcailContract=true 在合规侧走特批,{@link HcsContractSpecSyncSupport} 接收结果)→ + * ⑥ 履约规则 C103-9 行级同步({@link HcsExeStageSyncSupport})。 * 结果留痕:风险校验写 blade_hcs_check_log 与合同 hcs_risk_* 字段;推送结果回填 hcs_fd_id/hcs_sync_status。 * * @author Chill @@ -103,7 +104,7 @@ public class HcsContractSyncSupport { /** * 推送合同到 HCS:特批挂起门禁 → 风险校验(仅留痕,高风险不再阻断)→ 附件转传 → 判重 → 起草/更新 → 回填合规 fdId 置 synced - * → 高风险/黑名单客商合同挂起"特批审核"并自动发起 C103-8 特批(外部客商管控) + * → 高风险/黑名单客商合同挂起"特批审核"等待合规特批结果(报文随 fdSepcailContract=true,外部客商管控) * * @param contractManage 合同单(approvalStatus 须为 approved/change_approved) * @return 推送结果描述(供任务汇总与 hcs_sync_msg 落库) @@ -112,10 +113,11 @@ public class HcsContractSyncSupport { log.info("HCS合同推送开始:contractNo={},approvalStatus={},首推={},hcsSpecStatus={}", contractManage.getContractNo(), contractManage.getApprovalStatus(), StringUtil.isBlank(contractManage.getHcsFdId()), contractManage.getHcsSpecStatus()); - // ⓪ 特批挂起门禁:待特批/特批中的合同跳过推送,等待合规推送特批结果后恢复(C103-8,前端接入设计 §3.4) - if (List.of(HcsSyncConstant.SPEC_STATUS_NEED, HcsSyncConstant.SPEC_STATUS_PROCESSING).contains(contractManage.getHcsSpecStatus())) { + // ⓪ 特批挂起门禁:特批中(processing)的合同跳过推送,等待合规推送/定时查询特批结果后恢复; + // need(存量待特批/历史卡单)不拦截——重推时随起草报文带 fdSepcailContract=true 自愈转特批 + if (HcsSyncConstant.SPEC_STATUS_PROCESSING.equals(contractManage.getHcsSpecStatus())) { log.info("HCS合同推送跳过(特批挂起中):contractNo={},hcsSpecStatus={}", contractManage.getContractNo(), contractManage.getHcsSpecStatus()); - return "合同特批挂起中(" + contractManage.getHcsSpecStatus() + "),跳过推送"; + return "合同特批挂起中(processing),跳过推送"; } // ① 客商风险校验(可配开关):留痕 hcs_risk_* 字段并返回高风险/黑名单标志,不再阻断推送(高风险合同起草后自动转特批) boolean risky = false; @@ -132,20 +134,20 @@ public class HcsContractSyncSupport { markSynced(contractManage, existFdId, "判重命中,回填已有合规合同ID"); resultMessage = "判重命中,回填已有合规合同ID"; } else { - String fdContractId = draftContract(contractManage, attachmentRefs); + String fdContractId = draftContract(contractManage, attachmentRefs, risky); // 先持久化合规合同ID(调用方必须保存),履约规则同步失败时下轮凭其走更新补偿 markSynced(contractManage, fdContractId, "C103-1 合同发起成功"); resultMessage = "C103-1 合同发起成功"; } } else { - updateContract(contractManage); + updateContract(contractManage, risky); markSynced(contractManage, contractManage.getHcsFdId(), "C103-11 合同更新成功"); resultMessage = "C103-11 合同更新成功"; } - // ⑤ 高风险/黑名单客商(外部客商管控):C103-1 起草成功后挂起"特批审核"并自动发起 C103-8; - // 特批已通过的合同不重复发起(单次有效),发起失败保持待特批可人工重发 + // ⑤ 高风险/黑名单客商(外部客商管控):起草/更新报文已随 fdSepcailContract=true 在合规侧发起特批流程, + // 此处挂起"特批审核"等待结果(合规推送 contractLegal/result 或定时 C103-4 查询联动恢复/驳回) if (risky) { - autoApplySpecIfNeeded(contractManage); + hangSpecReview(contractManage); } // ⑥ 履约规则 C103-9 行级同步(随合同链路,§5.3;一期暂不对接默认关,打开后失败抛出由任务落 failed,下轮凭 hcs_fd_id 走更新补偿) if (!hcsProperties.getExeStage().isSyncEnabled()) { @@ -158,7 +160,7 @@ public class HcsContractSyncSupport { /** * C101-1 客商风险校验:甲乙双方各查一次,留痕 check_log 与合同 hcs_risk_* 字段; * 返回是否高风险/黑名单(风险等级=2 或任一方黑名单),不再阻断推送—— - * 推送成功后由自动特批链路挂起处理(外部客商管控,见 {@link #autoApplySpecIfNeeded}) + * 推送成功后由自动特批链路挂起处理(外部客商管控,见 {@link #}) * * @return true=高风险或黑名单客商(触发自动特批) */ @@ -181,72 +183,26 @@ public class HcsContractSyncSupport { } /** - * 高风险/黑名单客商合同自动特批(C103-8,外部客商管控):C103-1 起草成功后置待特批并自动发起, - * TMS 流程挂起展示"特批审核"(currentNode),合规推送特批结果(contractLegal/result)后恢复或驳回; - * 特批已通过(单次有效)的合同不重复发起;发起失败保持待特批仅留痕,可人工重发或重新推送兜底 + * 高风险/黑名单客商合同挂起"特批审核":合规侧特批流程已随 C103-1/C103-11 报文 fdSepcailContract=true 发起 + * (C103-8 独立发起接口合规未提供,2026-10-13 联调确认),TMS 挂起展示"特批审核"(currentNode), + * 结果经合规推送(contractLegal/result)或定时 C103-4 查询联动后恢复或驳回;特批已通过(单次有效)不再重复挂起 */ - private void autoApplySpecIfNeeded(ContractManage contractManage) { - if (HcsSyncConstant.SPEC_STATUS_APPROVED.equals(contractManage.getHcsSpecStatus())) { - log.info("HCS合同高风险/黑名单但特批已通过(单次有效),跳过自动特批:contractNo={},hcsSpecStatus={}", + private void hangSpecReview(ContractManage contractManage) { + // 终态守卫:合规回调(秒批/秒驳)先于挂起执行时,不得覆盖已落地的结果 + if (List.of(HcsSyncConstant.SPEC_STATUS_APPROVED, HcsSyncConstant.SPEC_STATUS_REJECTED).contains(contractManage.getHcsSpecStatus())) { + log.info("HCS合同高风险/黑名单但特批已有终态(单次有效),跳过挂起:contractNo={},hcsSpecStatus={}", contractManage.getContractNo(), contractManage.getHcsSpecStatus()); return; } - contractManage.setHcsSpecStatus(HcsSyncConstant.SPEC_STATUS_NEED); + contractManage.setHcsSpecStatus(HcsSyncConstant.SPEC_STATUS_PROCESSING); contractManage.setHcsSpecTime(LocalDateTime.now()); - contractManage.setHcsSpecMsg("高风险/黑名单客商,合同推送合规成功后自动发起特批(C103-8)"); + contractManage.setHcsSpecMsg("高风险/黑名单客商,合同报文随 fdSepcailContract=true 走合规特批流程"); // TMS 流程挂起为"特批审核",特批通过恢复展示、驳回联动合同审批驳回 contractManage.setCurrentNode(HcsSyncConstant.SPEC_REVIEW_NODE); contractManageMapper.updateById(contractManage); - log.info("HCS合同高风险/黑名单触发自动特批(C103-8):contractNo={},riskLevel={},blackStatus={},挂起节点={}", + log.info("HCS合同高风险/黑名单挂起特批审核:contractNo={},riskLevel={},blackStatus={},挂起节点={}", contractManage.getContractNo(), contractManage.getHcsRiskLevel(), contractManage.getHcsBlackStatus(), contractManage.getCurrentNode()); - try { - List attachments = transferSpecExplanationAttachments(contractManage); - hcsContractSpecSyncSupport.applySpec(contractManage.getId(), attachments); - } catch (Exception exception) { - log.warn("HCS合同自动特批发起失败(保持待特批,可人工重发):contractNo={},{}", - contractManage.getContractNo(), exception.getMessage(), exception); - } - } - - /** - * 筛选合同「特批附件」类型附件(fileType=特批附件,业务字典 contract_attachment_type)并转传合规(C103-2), - * 返回特批附件引用(fdEntityKey=eopCdraftSpecial);无特批说明附件返回空列表(提交时已强制校验,此处由 C103-8 防御性拦截) - */ - private List transferSpecExplanationAttachments(ContractManage contractManage) { - List> specAttachments = new ArrayList<>(); - for (Object item : parseJsonArray(contractManage.getAttachmentsJson())) { - if (item instanceof Map attachment - && HcsSyncConstant.ATTACHMENT_TYPE_SPEC_EXPLANATION.equals(attachment.get(HcsSyncConstant.ATTACHMENT_TYPE_FIELD))) { - specAttachments.add(attachment); - } - } - if (specAttachments.isEmpty()) { - return List.of(); - } - String specJson = JsonUtil.toJson(specAttachments); - String loginName = hcsProperties.getOperatorLoginName(); - List attachmentRefs = hcsAttachmentSupport.transferAttachments( - HcsSyncConstant.BIZ_TYPE_CONTRACT, contractManage.getId(), specJson, loginName); - for (int index = 0; index < attachmentRefs.size(); index++) { - // 特批附件字段 key:与元数据行序一致 - attachmentRefs.get(index).setFdEntityKey(HcsSyncConstant.CONTRACT_ATTACH_KEY_SPECIAL); - attachmentRefs.get(index).setFdFileName(resolveAttachmentName(specAttachments.get(index))); - } - return attachmentRefs; - } - - /** - * 附件元数据文件名(name/originalName/fileName 依次取首个非空,照 HcsAttachmentSupport 惯例) - */ - private String resolveAttachmentName(Map attachment) { - for (String field : List.of("name", "originalName", "fileName")) { - Object value = attachment.get(field); - if (value != null && !String.valueOf(value).isBlank()) { - return String.valueOf(value); - } - } - return null; } /** @@ -321,21 +277,21 @@ public class HcsContractSyncSupport { } /** - * C103-1 合同发起,返回合规合同 fdContractId + * C103-1 合同发起,返回合规合同 fdContractId;risky=true 时报文带 fdSepcailContract=true 走合规特批流程 */ - private String draftContract(ContractManage contractManage, List attachmentRefs) { - HcsContractDraftDTO param = buildDraftParam(contractManage, attachmentRefs); - log.info("HCS合同推送开始:{}(C103-1 发起,挂载附件 {} 个)", contractManage.getContractNo(), attachmentRefs.size()); + private String draftContract(ContractManage contractManage, List attachmentRefs, boolean risky) { + HcsContractDraftDTO param = buildDraftParam(contractManage, attachmentRefs, risky); + log.info("HCS合同推送开始:{}(C103-1 发起,挂载附件 {} 个,特批流程={})", contractManage.getContractNo(), attachmentRefs.size(), risky); HcsResult result = hcsClient.contractDraft(param); return validateDraftResult(contractManage, result); } /** - * C103-11 合同更新(入参同发起,v4 新增顶层 fdId 定位已有合同) + * C103-11 合同更新(入参同发起,v4 新增顶层 fdId 定位已有合同);risky=true 时报文带 fdSepcailContract=true */ - private void updateContract(ContractManage contractManage) { - HcsContractDraftDTO param = buildDraftParam(contractManage, null); - log.info("HCS合同推送开始:{}(C103-11 更新,附件不重复挂载待联调确认)", contractManage.getContractNo()); + private void updateContract(ContractManage contractManage, boolean risky) { + HcsContractDraftDTO param = buildDraftParam(contractManage, null, risky); + log.info("HCS合同推送开始:{}(C103-11 更新,附件不重复挂载待联调确认,特批流程={})", contractManage.getContractNo(), 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()); @@ -347,7 +303,7 @@ public class HcsContractSyncSupport { * 组装 C103-1/C103-11 入参(字段标注照 §3.4 规范,映射表见设计文档 §5.2); * attachmentRefs 新建传合规附件引用列表(fdId+fdEntityKey,必填,无附件传空列表),更新传 null 不挂载 */ - private HcsContractDraftDTO buildDraftParam(ContractManage contractManage, List attachmentRefs) { + private HcsContractDraftDTO buildDraftParam(ContractManage contractManage, List attachmentRefs, boolean risky) { HcsContractDraftDTO param = new HcsContractDraftDTO(); // 【必填】合同ID:C103-11 更新顶层必填(传 C103-1 返回的 fdContractId),C103-1 新建不传(v4 新增) param.setFdId(contractManage.getHcsFdId()); @@ -360,7 +316,7 @@ public class HcsContractSyncSupport { // 【必填】保存类型:submit(提交) param.setSaveType("submit"); HcsContractFieldJsonDTO fieldJson = new HcsContractFieldJsonDTO(); - fieldJson.setXformFields(buildXformFields(contractManage)); + fieldJson.setXformFields(buildXformFields(contractManage, risky)); // 相对方(签署方):甲方/乙方,编号按名称反查 CustomerArchive(§9-U6) fieldJson.setSigner(buildSigners(contractManage)); // 【必填】附件数据:C103-1 必填(无附件传空列表),fdEntityKey=特批 eopCdraftSpecial/用印 eopCdraftSign/其他 eopCdraftOther, @@ -379,7 +335,7 @@ public class HcsContractSyncSupport { /** * xformFields 模板字段(字段名取 {@link HcsContractFieldConstant},中文名取自《桂物合同集成接口逻辑梳理》§5.1 合同字段说明) */ - private List buildXformFields(ContractManage contractManage) { + private List buildXformFields(ContractManage contractManage, boolean risky) { List fields = new ArrayList<>(); // 【必填】合同ID:更新时传合同发起返回的 fdContractId 的值(v4 合同字段说明) fields.add(field(HcsContractFieldConstant.FIELD_FD_ID, "合同ID", contractManage.getHcsFdId())); @@ -409,8 +365,9 @@ public class HcsContractSyncSupport { } // 结算模式:TMS 合同固定开口合同(open,v4 字段说明) fields.add(field(HcsContractFieldConstant.FIELD_FD_CONTRACT_GW_NATURE, "结算模式", HcsContractFieldConstant.CONTRACT_GW_NATURE_OPEN)); - // 特批流程:fdSepcailContract 固定 false(原文拼写笔误必须沿用,D15,配置项预留) - fields.add(field(HcsContractFieldConstant.FIELD_FD_SEPCAIL_CONTRACT, "特批流程", hcsProperties.getContract().isSpecialContractEnabled() ? "true" : "false")); + // 特批流程:高风险/黑名单客商报文带 true(合规侧随起草自动走特批流程,C103-8 独立接口未提供); + // 配置项 contract.special-contract-enabled 可强制全量走特批(原文拼写笔误必须沿用,D15) + fields.add(field(HcsContractFieldConstant.FIELD_FD_SEPCAIL_CONTRACT, "特批流程", risky || hcsProperties.getContract().isSpecialContractEnabled() ? "true" : "false")); // 合同类型:ContractManage.contractCategory fields.add(field(HcsContractFieldConstant.FIELD_CONTRACT_TYPE, "合同类型", contractManage.getContractCategory())); // 甲方名称/乙方名称:TMS 存名称字符串 @@ -515,8 +472,8 @@ public class HcsContractSyncSupport { if (!List.of("approved", "change_approved").contains(contractManage.getApprovalStatus())) { throw new ServiceException("仅审批通过的合同可推送合规(当前状态:" + contractManage.getApprovalStatus() + ")"); } - if (List.of(HcsSyncConstant.SPEC_STATUS_NEED, HcsSyncConstant.SPEC_STATUS_PROCESSING).contains(contractManage.getHcsSpecStatus())) { - throw new ServiceException("高风险客商合同需先完成特批(C103-8,当前特批状态:" + contractManage.getHcsSpecStatus() + ")"); + if (HcsSyncConstant.SPEC_STATUS_PROCESSING.equals(contractManage.getHcsSpecStatus())) { + throw new ServiceException("合同特批审核中,禁止重推(等待合规特批结果后恢复)"); } contractManage.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_UNSYNCED); contractManage.setHcsRetryCount(0); diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsSpecContractSaveDTO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractLegalResultDTO.java similarity index 55% rename from blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsSpecContractSaveDTO.java rename to blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractLegalResultDTO.java index 24b275ba..bfb4d3ea 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsSpecContractSaveDTO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractLegalResultDTO.java @@ -33,45 +33,45 @@ import java.io.Serial; import java.io.Serializable; /** - * 合同合规系统(HCS)C103-8 合同发起特批流程入参 + * 合同特批完成后合规系统回传 TMS 的结果报文(POST /hcs/contractLegal/result,iPaaS 网关 /gwzh/HTHG/contractLegal/result) *

- * TODO 待联调确认(前端接入设计 §6-U1):C103-8 报文 v4 未提供,本 DTO 按 C106-3 结算付款特批的 - * formData/mechanisms 模式预估,字段名以合规方最新接口说明为准。 + * 报文为"合同同步结果"结构:合规特批完成后同步金蝶,回调携带金蝶同步结果; + * 定位合同用 contractCode(ERP 合同编号),requestId 仅是 X-ERP-Request-Id 请求头原样回传、不能用于定位。 * * @author Chill */ @Data @JsonInclude(JsonInclude.Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) -public class HcsSpecContractSaveDTO implements Serializable { +public class HcsContractLegalResultDTO implements Serializable { @Serial private static final long serialVersionUID = 1L; /** - * 特批流程ID(更新必填,发起不传) + * 合同类型:deliverer=投送人;gc=钢厂;sett_center=结算中心 */ - private String fdId; + private String contractType; /** - * 【必填】操作人登录名(§9-U2) + * ERP 本次同步使用的合同编号(TMS blade_contract_manage.contract_no,定位合同用) */ - private String fdLoginName; + private String contractCode; /** - * 【必填】合规合同ID(blade_contract_manage.hcs_fd_id,非名称) + * 本次合同同步请求头 X-ERP-Request-Id,原样回传(不用于定位) */ - private String fdContractId; + private String requestId; /** - * 【必填】合同编号 + * 金蝶同步成功传 true,失败传 false */ - private String fdContractNo; + private Boolean success; /** - * 【必填】单据主题:"合同特批-" + 合同编号 + * 金蝶同步失败原因;失败时建议填写 */ - private String fdDocSubject; + private String reason; /** - * 特批事由(合同名称/特批原因,非必传) + * 金蝶实际返回的合同 ID;成功时用于保存留痕 */ - private String fdReason; + private String kingdeeId; /** - * 特批附件(C103-2 转传返回的合规附件ID 引用) + * 来源系统标识,约定传 WCCK(最长 64 字符) */ - private HcsMechanismsDTO mechanisms; + private String sourceSystem; } diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/feign/IHcsClient.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/feign/IHcsClient.java index f3bee019..d34a7a89 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/feign/IHcsClient.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/feign/IHcsClient.java @@ -55,7 +55,6 @@ import org.springblade.hcs.dto.HcsReceiptBillSaveDTO; import org.springblade.hcs.dto.HcsResult; import org.springblade.hcs.dto.HcsRiskQueryDTO; import org.springblade.hcs.dto.HcsRiskVO; -import org.springblade.hcs.dto.HcsSpecContractSaveDTO; import org.springblade.hcs.dto.HcsSpecPaySaveDTO; import org.springblade.hcs.dto.HcsTemplateVO; import org.springframework.cloud.openfeign.FeignClient; @@ -79,7 +78,7 @@ import org.springframework.web.multipart.MultipartFile; * * @author Chill */ -@FeignClient(name = "HCS", url = "${thirdParty.hcs.baseUrl}", configuration = HcsFeignClientConfig.class, fallbackFactory = HcsClientFallbackFactory.class) +@FeignClient(name = "HCS", url = "${thirdParty.hcs.baseUrl}", configuration = HcsFeignClientConfig.class, fallbackFactory = HcsClientFallbackFactory.class, primary = false) public interface IHcsClient { String PROJECT_ADD_URL = "${thirdParty.hcs.projectAddUrl:/openapi/sys-modeling/apis/data/km-project1/V1/projectApproval/add}"; @@ -99,7 +98,6 @@ public interface IHcsClient { String CREDIT_CHECK_URL = "${thirdParty.hcs.creditCheckUrl:/openapi/eop-cdraft/lcode/ext-cdraft/extEopCdraftMainOpen/contractCreditCheck}"; String SPEC_PAY_ADD_URL = "${thirdParty.hcs.specPayAddUrl:/openapi/sys-modeling/lcode/ext-pay-receive/extPayReceiveOpenService/addSpecApplyPay}"; String SPEC_PAY_UPDATE_URL = "${thirdParty.hcs.specPayUpdateUrl:/openapi/sys-modeling/lcode/ext-pay-receive/extPayReceiveOpenService/updateSpecApplyPay}"; - String SPEC_CONTRACT_ADD_URL = "${thirdParty.hcs.specContractAddUrl:/openapi/sys-modeling/lcode/ext-cdraft/extEopCdraftMainOpen/addSpecApplyContract}"; String PERF_RECORD_ADD_URL = "${thirdParty.hcs.perfRecordAddUrl:/openapi/sys-modeling/apis/data/km-pay-receive/V1/dataSync/add}"; String PERF_RECORD_UPDATE_URL = "${thirdParty.hcs.perfRecordUpdateUrl:/openapi/sys-modeling/apis/data/km-pay-receive/V1/dataSync/update}"; String RECEIPT_BILL_ADD_URL = "${thirdParty.hcs.receiptBillAddUrl:/openapi/sys-modeling/lcode/ext-invoice-receive/extInvoiceReceiveOpenService/addReceiveBill}"; @@ -267,19 +265,6 @@ public interface IHcsClient { @PostMapping(SPEC_PAY_UPDATE_URL) HcsResult> updateSpecApplyPay(@RequestBody HcsSpecPaySaveDTO param); - /** - * C103-8 合同发起特批流程(高风险客商签约特批) - *

- * TODO 待联调确认(前端接入设计 §6-U1):C103-8 报文与路径均未在 v4 接口说明中定义, - * 本端点按 C106-3 结算付款特批的报文结构预估(双层嵌套 data.data 承接返回), - * 路径可经 thirdParty.hcs.specContractAddUrl 覆盖,字段以合规方最新接口说明为准。 - * - * @param param 请求参数 - * @return data.data.{fdId, fdXFormId, docViewUrl}(fdId 为特批流程ID) - */ - @PostMapping(SPEC_CONTRACT_ADD_URL) - HcsResult> addSpecContract(@RequestBody HcsSpecContractSaveDTO param); - /** * C108-1 履约记录新建 *