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 new file mode 100644 index 00000000..b937c7b7 --- /dev/null +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsContractFieldConstant.java @@ -0,0 +1,179 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + *

+ * Use of this software is governed by the Commercial License Agreement + * obtained after purchasing a license from BladeX. + *

+ * 1. This software is for development use only under a valid license + * from BladeX. + *

+ * 2. Redistribution of this software's source code to any third party + * without a commercial license is strictly prohibited. + *

+ * 3. Licensees may copyright their own code but cannot use segments + * from this software for such purposes. Copyright of this software + * remains with BladeX. + *

+ * Using this software signifies agreement to this License, and the software + * must not be used for illegal purposes. + *

+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is + * not liable for any claims arising from secondary or illegal development. + *

+ * Author: Chill Zhuang (bladejava@qq.com) + */ +package org.springblade.transport.constant; + +/** + * HCS(合同合规系统)C103-1/C103-11 合同发起 xformFields 字段名常量 + *

+ * 字段名取自 v4 接口文档「合同字段说明」,fdSepcailContract 为文档原文拼写(Special 笔误,必须沿用); + * 命名照 {@link HcsSyncConstant} 惯例。 + * + * @author Chill + */ +public final class HcsContractFieldConstant { + + // ==================== 合同发起 xformFields 字段名(fdXformField.name) ==================== + + /** + * 合同ID(更新时传 C103-1 返回的 fdContractId) + */ + public static final String FIELD_FD_ID = "fdId"; + + /** + * 合同编号(fd 模板字段) + */ + public static final String FIELD_FD_NUMBER = "fdNumber"; + + /** + * 合同编号(CONTRACT 模板字段) + */ + public static final String FIELD_CONTRACT_NO = "CONTRACT_NO"; + + /** + * 合同标题(fd 模板字段) + */ + public static final String FIELD_FD_SUBJECT = "fdSubject"; + + /** + * 合同名称(CONTRACT 模板字段) + */ + public static final String FIELD_CONTRACT_NAME = "CONTRACT_NAME"; + + /** + * 合同金额(fd 模板字段) + */ + public static final String FIELD_FD_AMOUNT = "fdAmount"; + + /** + * 合同金额(AMOUNT 模板字段) + */ + public static final String FIELD_AMOUNT = "AMOUNT"; + + /** + * 币种(fd 模板字段) + */ + public static final String FIELD_FD_CURRENCY_ID = "fdCurrencyId"; + + /** + * 币种(CURRENCY 模板字段) + */ + public static final String FIELD_CURRENCY = "CURRENCY"; + + /** + * 合同结算类型:payment=付款,payment_collection=收支双向,collection=收款,none=不结算 + */ + public static final String FIELD_FD_SETTLEMENT_TYPE = "fdSettlementType"; + + /** + * 特批流程(文档原文拼写笔误,必须沿用) + */ + public static final String FIELD_FD_SEPCAIL_CONTRACT = "fdSepcailContract"; + + /** + * 合同类型 + */ + public static final String FIELD_CONTRACT_TYPE = "CONTRACT_TYPE"; + + /** + * 甲方名称 + */ + public static final String FIELD_PARTY_A = "PARTY_A"; + + /** + * 乙方名称 + */ + public static final String FIELD_PARTY_B = "PARTY_B"; + + /** + * 签订日期(yyyy-MM-dd,fdType=timestamp) + */ + public static final String FIELD_SIGN_DATE = "SIGN_DATE"; + + /** + * 预计开始时间(合同开始期限为指定日期时必填) + */ + public static final String FIELD_FD_ESTIMATE_START_TIME = "fdEstimateStartTime"; + + /** + * 预计结束时间(合同结束期限为指定日期时必填) + */ + public static final String FIELD_FD_ESTIMATE_END_TIME = "fdEstimateEndTime"; + + /** + * 合同开始期限:signDate=签订之日起算,specifiedDate=指定日期 + */ + public static final String FIELD_FD_START_TERM = "fdStartTerm"; + + /** + * 合同结束期限:signTerm=按签订后期限,specifiedDate=指定日期,noTerm=无固定期限 + */ + public static final String FIELD_FD_END_TERM = "fdEndTerm"; + + /** + * 创建时间(yyyy-MM-dd,fdType=timestamp) + */ + public static final String FIELD_CREATE_TIME = "CREATE_TIME"; + + /** + * 创建时间(fd 模板字段,yyyy-MM-dd,fdType=timestamp) + */ + public static final String FIELD_FD_CREATE_TIME = "fdCreateTime"; + + /** + * 同步时间(yyyy-MM-dd,fdType=timestamp) + */ + public static final String FIELD_FD_SYN_TIME = "fd_syn_time"; + + /** + * 承办人名称 + */ + public static final String FIELD_CREATE_USER_NAME = "CREATE_USER_NAME"; + + /** + * 合同状态:draft/approving/approved 等(v4 必填) + */ + public static final String FIELD_CONTRACT_STATUS = "CONTRACT_STATUS"; + + /** + * 合同份数(v4 必填) + */ + public static final String FIELD_FD_SERVINGS = "fdServings"; + + /** + * 合同说明(选填) + */ + public static final String FIELD_FD_DESC = "fdDesc"; + + // ==================== 期限枚举值 ==================== + + /** + * 期限取值:指定日期(fdStartTerm/fdEndTerm,TMS 固定按指定日期起算) + */ + public static final String TERM_SPECIFIED_DATE = "specifiedDate"; + + private HcsContractFieldConstant() { + } +} 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 6ade9dc4..80667201 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 @@ -31,6 +31,7 @@ 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.HcsContractDraftDTO; import org.springblade.hcs.dto.HcsContractDraftVO; import org.springblade.hcs.dto.HcsContractFieldJsonDTO; @@ -47,6 +48,7 @@ import org.springblade.hcs.exception.HcsException; import org.springblade.hcs.feign.IHcsClient; import org.springblade.system.cache.UserCache; import org.springblade.system.pojo.entity.User; +import org.springblade.transport.constant.HcsContractFieldConstant; import org.springblade.transport.constant.HcsSyncConstant; import org.springblade.transport.mapper.ContractManageMapper; import org.springblade.transport.mapper.CustomerArchiveMapper; @@ -68,7 +70,7 @@ import java.util.Objects; /** * HCS 合同同步支撑组件(C103-1 发起 / C103-11 更新,设计文档 §5.2) *

- * 扫描任务按序执行:① 客商风险校验(可配开关,黑名单阻断)→ ② 附件转传(挂载点待 §9-U8 确认,先转传缓存)→ + * 扫描任务按序执行:① 客商风险校验(可配开关,黑名单阻断)→ ② 附件转传(v4 挂载点 fdFieldJson.attachment,随 C103-1 挂载)→ * ③ C103-3 判重(§9-U4 查询能力联调确认)→ ④ C103-1 起草 / 变更单 C103-11 更新(§9-U5 定位方式待联调)→ * ⑤ 履约规则 C103-9 行级同步({@link HcsExeStageSyncSupport})。 * 结果留痕:风险校验写 blade_hcs_check_log 与合同 hcs_risk_* 字段;推送结果回填 hcs_fd_id/hcs_sync_status。 @@ -81,10 +83,9 @@ import java.util.Objects; public class HcsContractSyncSupport { /** - * 合同金额等 xformFields 值一律字符串传值 + * 合同金额等 xformFields 值一律字符串传值;时间字段 v4 要求 yyyy-MM-dd(fdType=timestamp) */ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); /** * C101-1 黑名单状态取值(示例 no 表示非黑名单,§9-U3 字典值联调确认) @@ -117,8 +118,8 @@ public class HcsContractSyncSupport { return "高风险客商,合同已挂起待特批(C103-8)"; } } - // ② 附件转传(先转传并缓存合规附件ID,C103-1 挂载方式待 §9-U8 确认后接线) - transferAttachmentsIfEnabled(contractManage); + // ② 附件转传(v4 已明确挂载点:C103-1 fdFieldJson.attachment,转传取得合规附件ID 后随发起报文挂载) + List attachmentFdIds = transferAttachmentsIfEnabled(contractManage); // ③④ 首推判重后起草(C103-1);已有合规ID(变更单)走更新(C103-11) String resultMessage; if (StringUtil.isBlank(contractManage.getHcsFdId())) { @@ -127,7 +128,7 @@ public class HcsContractSyncSupport { markSynced(contractManage, existFdId, "判重命中,回填已有合规合同ID"); resultMessage = "判重命中,回填已有合规合同ID"; } else { - String fdContractId = draftContract(contractManage); + String fdContractId = draftContract(contractManage, attachmentFdIds); // 先持久化合规合同ID(调用方必须保存),履约规则同步失败时下轮凭其走更新补偿 markSynced(contractManage, fdContractId, "C103-1 合同发起成功"); resultMessage = "C103-1 合同发起成功"; @@ -232,19 +233,19 @@ public class HcsContractSyncSupport { /** * C103-1 合同发起,返回合规合同 fdContractId */ - private String draftContract(ContractManage contractManage) { - HcsContractDraftDTO param = buildDraftParam(contractManage); - log.info("HCS合同推送开始:{}(C103-1 发起)", contractManage.getContractNo()); + private String draftContract(ContractManage contractManage, List attachmentFdIds) { + HcsContractDraftDTO param = buildDraftParam(contractManage, attachmentFdIds); + log.info("HCS合同推送开始:{}(C103-1 发起,挂载附件 {} 个)", contractManage.getContractNo(), attachmentFdIds.size()); HcsResult result = hcsClient.contractDraft(param); return validateDraftResult(contractManage, result); } /** - * C103-11 合同更新(入参同发起;TODO 待联调(§9-U5):HCS 侧如何定位已有合同 v4 未说明) + * C103-11 合同更新(入参同发起,v4 新增顶层 fdId 定位已有合同) */ private void updateContract(ContractManage contractManage) { - HcsContractDraftDTO param = buildDraftParam(contractManage); - log.info("HCS合同推送开始:{}(C103-11 更新,§9-U5 定位方式待联调)", contractManage.getContractNo()); + HcsContractDraftDTO param = buildDraftParam(contractManage, null); + log.info("HCS合同推送开始:{}(C103-11 更新,附件不重复挂载待联调确认)", contractManage.getContractNo()); 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()); @@ -253,10 +254,13 @@ public class HcsContractSyncSupport { } /** - * 组装 C103-1/C103-11 入参(字段标注照 §3.4 规范,映射表见设计文档 §5.2) + * 组装 C103-1/C103-11 入参(字段标注照 §3.4 规范,映射表见设计文档 §5.2); + * attachmentFdIds 新建传合规附件ID 列表(必填,无附件传空列表),更新传 null 不挂载 */ - private HcsContractDraftDTO buildDraftParam(ContractManage contractManage) { + private HcsContractDraftDTO buildDraftParam(ContractManage contractManage, List attachmentFdIds) { HcsContractDraftDTO param = new HcsContractDraftDTO(); + // 【必填】合同ID:C103-11 更新顶层必填(传 C103-1 返回的 fdContractId),C103-1 新建不传(v4 新增) + param.setFdId(contractManage.getHcsFdId()); // 【必填】合同模板ID:template-mapping[contractCategory](§9-U7 待合规方提供模板ID清单) param.setFdTemplateId(requireTemplateId(contractManage)); // 【必填】外部系统标识:fd_sources,配置 thirdParty.hcs.src-system(D14) @@ -269,54 +273,84 @@ public class HcsContractSyncSupport { fieldJson.setXformFields(buildXformFields(contractManage)); // 相对方(签署方):甲方/乙方,编号按名称反查 CustomerArchive(§9-U6) fieldJson.setSigner(buildSigners(contractManage)); + // 【必填】附件数据:C103-1 必填(无附件传空列表),fdBindType=ADD;更新不挂载(传 null) + if (attachmentFdIds != null) { + fieldJson.setAttachment(attachmentFdIds.stream().map(fdId -> { + HcsAttachmentRefDTO attachment = new HcsAttachmentRefDTO(); + // 【必填】附件ID(C103-2 转传返回) + attachment.setFdId(fdId); + // 【必填】操作类型:ADD 新增 + attachment.setFdBindType("ADD"); + return attachment; + }).toList()); + } param.setFdFieldJson(fieldJson); return param; } /** - * xformFields 模板字段(字段名/中文名取自《桂物合同集成接口逻辑梳理》§5.1 合同字段说明) + * xformFields 模板字段(字段名取 {@link HcsContractFieldConstant},中文名取自《桂物合同集成接口逻辑梳理》§5.1 合同字段说明) */ private List buildXformFields(ContractManage contractManage) { List fields = new ArrayList<>(); + // 【必填】合同ID:更新时传合同发起返回的 fdContractId 的值(v4 合同字段说明) + fields.add(field(HcsContractFieldConstant.FIELD_FD_ID, "合同ID", contractManage.getHcsFdId())); // 【必填】合同编号:ContractManage.contractNo - fields.add(field("fdNumber", "合同编号", contractManage.getContractNo())); - fields.add(field("CONTRACT_NO", "合同编号", contractManage.getContractNo())); + fields.add(field(HcsContractFieldConstant.FIELD_FD_NUMBER, "合同编号", contractManage.getContractNo())); + fields.add(field(HcsContractFieldConstant.FIELD_CONTRACT_NO, "合同编号", contractManage.getContractNo())); // 【必填】合同标题:ContractManage.contractName - fields.add(field("fdSubject", "合同标题", contractManage.getContractName())); - fields.add(field("CONTRACT_NAME", "合同名称", contractManage.getContractName())); + fields.add(field(HcsContractFieldConstant.FIELD_FD_SUBJECT, "合同标题", contractManage.getContractName())); + fields.add(field(HcsContractFieldConstant.FIELD_CONTRACT_NAME, "合同名称", contractManage.getContractName())); // 【必填】合同金额:contractAmount(字符串传值) - fields.add(field("fdAmount", "合同金额", toPlainString(contractManage.getContractAmount()))); - fields.add(field("AMOUNT", "合同金额", toPlainString(contractManage.getContractAmount()))); + fields.add(field(HcsContractFieldConstant.FIELD_FD_AMOUNT, "合同金额", toPlainString(contractManage.getContractAmount()))); + fields.add(field(HcsContractFieldConstant.FIELD_AMOUNT, "合同金额", toPlainString(contractManage.getContractAmount()))); // 币种:TMS 结算币种经 currency-name-mapping 映射(默认 RMB→人民币,照金蝶惯例) - fields.add(field("fdCurrencyId", "币种", mapCurrencyName(contractManage.getSettlementCurrency()))); - fields.add(field("CURRENCY", "币种", mapCurrencyName(contractManage.getSettlementCurrency()))); - // 合同结算类型:settlement-type-mapping[settlementMode](映射到"付款/收款"待联调,§9-U3,未配置不传) + fields.add(field(HcsContractFieldConstant.FIELD_FD_CURRENCY_ID, "币种", mapCurrencyName(contractManage.getSettlementCurrency()))); + fields.add(field(HcsContractFieldConstant.FIELD_CURRENCY, "币种", mapCurrencyName(contractManage.getSettlementCurrency()))); + // 合同结算类型:settlement-type-mapping[settlementMode](必填:payment/payment_collection/collection/none,映射到"付款/收款"待联调,§9-U3,未配置不传) String settlementType = hcsProperties.getContract().getSettlementTypeMapping().get(contractManage.getSettlementMode()); if (StringUtil.isNotBlank(settlementType)) { - fields.add(field("fdSettlementType", "合同结算类型", settlementType)); + fields.add(field(HcsContractFieldConstant.FIELD_FD_SETTLEMENT_TYPE, "合同结算类型", settlementType)); } else { log.warn("HCS合同结算类型映射缺失:settlementMode=[{}] 不在 contract.settlement-type-mapping,fdSettlementType 不传(§9-U3)", contractManage.getSettlementMode()); } // 特批流程:fdSepcailContract 固定 false(原文拼写笔误必须沿用,D15,配置项预留) - fields.add(field("fdSepcailContract", "特批流程", hcsProperties.getContract().isSpecialContractEnabled() ? "true" : "false")); + fields.add(field(HcsContractFieldConstant.FIELD_FD_SEPCAIL_CONTRACT, "特批流程", hcsProperties.getContract().isSpecialContractEnabled() ? "true" : "false")); // 合同类型:ContractManage.contractCategory - fields.add(field("CONTRACT_TYPE", "合同类型", contractManage.getContractCategory())); + fields.add(field(HcsContractFieldConstant.FIELD_CONTRACT_TYPE, "合同类型", contractManage.getContractCategory())); // 甲方名称/乙方名称:TMS 存名称字符串 - fields.add(field("PARTY_A", "甲方名称", contractManage.getPartyA())); - fields.add(field("PARTY_B", "乙方名称", contractManage.getPartyB())); - // 【必填】签订日期:signDate(fdType=timestamp) - fields.add(timestampField("SIGN_DATE", "签订日期", contractManage.getSignDate())); - // 预计开始/结束时间:startDate/endDate(fdType=timestamp) - fields.add(timestampField("fdEstimateStartTime", "预计开始时间", contractManage.getStartDate())); - fields.add(timestampField("fdEstimateEndTime", "预计结束时间", contractManage.getEndDate())); - // 创建时间:createTime(fdType=timestamp) - fields.add(timestampField("CREATE_TIME", "创建时间", contractManage.getCreateTime())); - fields.add(timestampField("fdCreateTime", "创建时间", contractManage.getCreateTime())); - // 同步时间:推送时刻(fdType=timestamp) - fields.add(timestampField("fd_syn_time", "同步时间", LocalDateTime.now())); - // 承办人名称:handlerUserName - fields.add(field("CREATE_USER_NAME", "承办人名称", contractManage.getHandlerUserName())); - // TODO 待确认:合同状态 CONTRACT_STATUS,TMS 无直接对应,是否必传联调确认(§9-U3),一期不传 + fields.add(field(HcsContractFieldConstant.FIELD_PARTY_A, "甲方名称", contractManage.getPartyA())); + fields.add(field(HcsContractFieldConstant.FIELD_PARTY_B, "乙方名称", contractManage.getPartyB())); + // 【必填】签订日期:signDate(yyyy-MM-dd,fdType=timestamp) + fields.add(timestampField(HcsContractFieldConstant.FIELD_SIGN_DATE, "签订日期", contractManage.getSignDate())); + // 预计开始/结束时间:startDate/endDate(fdType=timestamp,期限为指定日期时必填) + fields.add(timestampField(HcsContractFieldConstant.FIELD_FD_ESTIMATE_START_TIME, "预计开始时间", contractManage.getStartDate())); + fields.add(timestampField(HcsContractFieldConstant.FIELD_FD_ESTIMATE_END_TIME, "预计结束时间", contractManage.getEndDate())); + // 【必填】合同开始期限:TMS 固定指定日期起算,日期取 fdEstimateStartTime(v4 合同字段说明) + fields.add(field(HcsContractFieldConstant.FIELD_FD_START_TERM, "合同开始期限", contractManage.getStartDate() == null ? null : HcsContractFieldConstant.TERM_SPECIFIED_DATE)); + // 【必填】合同结束期限:TMS 固定指定日期,日期取 fdEstimateEndTime(v4 合同字段说明) + fields.add(field(HcsContractFieldConstant.FIELD_FD_END_TERM, "合同结束期限", contractManage.getEndDate() == null ? null : HcsContractFieldConstant.TERM_SPECIFIED_DATE)); + // 【必填】创建时间:createTime(yyyy-MM-dd,fdType=timestamp) + fields.add(timestampField(HcsContractFieldConstant.FIELD_CREATE_TIME, "创建时间", contractManage.getCreateTime())); + fields.add(timestampField(HcsContractFieldConstant.FIELD_FD_CREATE_TIME, "创建时间", contractManage.getCreateTime())); + // 【必填】同步时间:推送时刻(yyyy-MM-dd,fdType=timestamp) + fields.add(timestampField(HcsContractFieldConstant.FIELD_FD_SYN_TIME, "同步时间", LocalDateTime.now())); + // 【必填】承办人名称:handlerUserName + fields.add(field(HcsContractFieldConstant.FIELD_CREATE_USER_NAME, "承办人名称", contractManage.getHandlerUserName())); + // 【必填】合同状态:status-mapping[approvalStatus](v4 必填,draft/approving/approved 等,§9-U3 待联调后配置,未配置不传) + String contractStatus = hcsProperties.getContract().getStatusMapping().get(contractManage.getApprovalStatus()); + if (StringUtil.isNotBlank(contractStatus)) { + fields.add(field(HcsContractFieldConstant.FIELD_CONTRACT_STATUS, "合同状态", contractStatus)); + } else { + log.warn("HCS合同状态映射缺失:approvalStatus=[{}] 不在 contract.status-mapping,CONTRACT_STATUS 不传(§9-U3)", contractManage.getApprovalStatus()); + } + // 【必填】合同份数:copyCount(v4 合同字段说明) + fields.add(field(HcsContractFieldConstant.FIELD_FD_SERVINGS, "合同份数", contractManage.getCopyCount() == null ? null : String.valueOf(contractManage.getCopyCount()))); + // 合同说明:remark(选填) + fields.add(field(HcsContractFieldConstant.FIELD_FD_DESC, "合同说明", contractManage.getRemark())); + // TODO 待联调(v4 选填字段,暂不传):fdCoTakers 协办人(TMS 无对应)、fdUnderTaker/fdUnderTakerDept 承办人及部门(组织架构对象传值方式待确认)、 + // fdRelations 关联合同(数组)、fdProject 关联项目 {"fdId": 合规项目ID}(对象传值方式待确认,TMS projectId 可经立项 hcs_fd_id 关联)、 + // fdContractGwNature 结算模式 open/close、fdContractAttribute 合同属性(枚举值文档未给出,TMS 无对应)、fdUrgencyLevel 紧急程度(TMS 无对应) return fields; } @@ -347,16 +381,16 @@ public class HcsContractSyncSupport { } /** - * 附件转传(可配开关):合同主文件 approved=true + 其它附件,合规附件ID 走映射缓存 + * 附件转传(可配开关):合同主文件 approved=true + 其它附件,返回合规附件ID 列表(挂载 C103-1 fdFieldJson.attachment) */ - private void transferAttachmentsIfEnabled(ContractManage contractManage) { + private List transferAttachmentsIfEnabled(ContractManage contractManage) { if (!hcsProperties.getAttachment().isTransferEnabled()) { - return; + return List.of(); } List attachmentFdIds = hcsAttachmentSupport.transferContractAttachments( contractManage.getContractFileJson(), contractManage.getAttachmentsJson(), requireLoginName(contractManage)); - // TODO 待联调(§9-U8):C103-1 未定义附件字段,转传后的合规附件ID 暂存映射缓存,挂载方式确认后接线 - log.info("HCS合同附件转传完成:contractNo={},共 {} 个附件(挂载点待 §9-U8 确认)", contractManage.getContractNo(), attachmentFdIds.size()); + log.info("HCS合同附件转传完成:contractNo={},共 {} 个附件(随 C103-1 挂载)", contractManage.getContractNo(), attachmentFdIds.size()); + return attachmentFdIds; } /** @@ -487,7 +521,7 @@ public class HcsContractSyncSupport { } /** - * 时间模板字段(fdType=timestamp,日期传 yyyy-MM-dd,时间传 yyyy-MM-dd HH:mm:ss) + * 时间模板字段(fdType=timestamp,v4 要求传 yyyy-MM-dd) */ private HcsXformFieldDTO timestampField(String name, String label, Object value) { if (value == null) { @@ -497,11 +531,11 @@ public class HcsContractSyncSupport { if (value instanceof LocalDate localDate) { text = localDate.format(DATE_FORMATTER); } else if (value instanceof LocalDateTime localDateTime) { - text = localDateTime.format(DATETIME_FORMATTER); + text = localDateTime.format(DATE_FORMATTER); } else { // BaseEntity.createTime 为 Date 类型 - text = DATETIME_FORMATTER.format(((java.util.Date) value).toInstant() - .atZone(java.time.ZoneId.systemDefault()).toLocalDateTime()); + text = DATE_FORMATTER.format(((java.util.Date) value).toInstant() + .atZone(java.time.ZoneId.systemDefault()).toLocalDate()); } HcsXformFieldDTO field = field(name, label, text); // 时间字段需带 fdType=timestamp diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java index 9c1cbf6e..089bd915 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsExeStageSyncSupport.java @@ -133,15 +133,15 @@ public class HcsExeStageSyncSupport { stage.setFdEopExeplanOperateType(row.getRowOp()); // 【必填】履约类型:payment=付款 / collection=收款 stage.setFdPerformType(row.getPerformType()); - // 款项性质:prepayment/progress/acceptance/retention + // 【必填】款项性质:prepayment/progress/acceptance/retention stage.setFdFundNature(row.getFundNature()); - // 计划金额(元) + // 【必填】计划金额(元) stage.setFdFundAmount(row.getFundAmount()); - // 资金日期(毫秒时间戳) + // 【必填】资金日期(毫秒时间戳) stage.setFdFundDate(toMillis(row.getFundDate())); - // 开票规则(如 payFirst) + // 【必填】开票规则:payFirst=先款后票 / invoiceFirst=先票后款 stage.setFdInvoiceRule(row.getInvoiceRule()); - // 账期 + // 【必填】账期(天) stage.setFdInvoiceCycle(row.getInvoiceCycle()); // 金额类型:行维护值,空取配置 thirdParty.hcs.exe-stage.fund-type(默认 byAmount) stage.setFdFundType(StringUtil.isBlank(row.getFundType()) ? hcsProperties.getExeStage().getFundType() : row.getFundType()); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsInvoiceRegSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsInvoiceRegSyncSupport.java index b130a851..59466cf8 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsInvoiceRegSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsInvoiceRegSyncSupport.java @@ -38,6 +38,7 @@ import org.springblade.hcs.dto.HcsInvoiceRegUpdateDTO; import org.springblade.hcs.dto.HcsPageQueryDTO; import org.springblade.hcs.dto.HcsPageVO; import org.springblade.hcs.dto.HcsInvoiceRegVO; +import org.springblade.hcs.dto.HcsRefVO; import org.springblade.hcs.dto.HcsResult; import org.springblade.hcs.exception.HcsException; import org.springblade.hcs.feign.IHcsClient; @@ -47,10 +48,12 @@ import org.springblade.system.cache.UserCache; import org.springblade.system.pojo.entity.Dept; import org.springblade.system.pojo.entity.User; import org.springblade.transport.constant.HcsSyncConstant; +import org.springblade.transport.mapper.ContractManageMapper; import org.springblade.transport.mapper.InvoiceApplicationInvoiceMapper; import org.springblade.transport.mapper.InvoiceApplicationMapper; import org.springblade.transport.mapper.InvoiceApplicationSettlementMapper; import org.springblade.transport.mapper.FormalSettlementMapper; +import org.springblade.transport.pojo.entity.ContractManage; import org.springblade.transport.pojo.entity.FormalSettlement; import org.springblade.transport.pojo.entity.InvoiceApplication; import org.springblade.transport.pojo.entity.InvoiceApplicationInvoice; @@ -83,6 +86,7 @@ public class HcsInvoiceRegSyncSupport { private final InvoiceApplicationSettlementMapper invoiceApplicationSettlementMapper; private final InvoiceApplicationInvoiceMapper invoiceApplicationInvoiceMapper; private final FormalSettlementMapper formalSettlementMapper; + private final ContractManageMapper contractManageMapper; private final HcsAttachmentSupport hcsAttachmentSupport; /** @@ -149,7 +153,10 @@ public class HcsInvoiceRegSyncSupport { // 登记日期:applicationDate(毫秒时间戳) param.setFdRegisterDate(toMillis(application.getApplicationDate())); // 【必填】合同编号:经应收结算链路回溯(§9-U10 关联字段确认后细化) - param.setFdContractNumber(requireContractNumber(application)); + ContractRef contractRef = requireContractRef(application); + param.setFdContractNumber(contractRef.contractNo()); + // 合同 {fdId, fdName}:fdId 传合规合同ID(未推送不传),名称取结算单合同名称(v4 新增) + param.setFdContract(contractRef.contract()); // 发票类型:invoice-type-mapping 字典映射(§9-U3,未配置不传) param.setFdInvoiceType(hcsProperties.getInvoice().getInvoiceTypeMapping().get(application.getInvoiceType())); if (param.getFdInvoiceType() == null) { @@ -228,22 +235,37 @@ public class HcsInvoiceRegSyncSupport { } /** - * 应收结算链路回溯合同编号:开票申请 → 应收结算关联 → 正式结算单合同编号(§9-U10) + * 应收结算链路回溯合同引用:开票申请 → 应收结算关联 → 正式结算单合同(§9-U10); + * fdContractNumber 必填,fdContract 随链路回填(fdId 为合规合同ID,未推送不传) */ - private String requireContractNumber(InvoiceApplication application) { + private ContractRef requireContractRef(InvoiceApplication application) { InvoiceApplicationSettlement relation = invoiceApplicationSettlementMapper.selectOne(Wrappers.lambdaQuery() .eq(InvoiceApplicationSettlement::getInvoiceApplicationId, application.getId()) .last("limit 1")); if (relation != null && relation.getFormalSettlementId() != null) { FormalSettlement settlement = formalSettlementMapper.selectById(relation.getFormalSettlementId()); if (settlement != null && StringUtil.isNotBlank(settlement.getContractNo())) { - return settlement.getContractNo(); + HcsRefVO contract = new HcsRefVO(); + contract.setFdName(settlement.getContractName()); + if (settlement.getContractId() != null) { + ContractManage contractManage = contractManageMapper.selectById(settlement.getContractId()); + if (contractManage != null) { + contract.setFdId(contractManage.getHcsFdId()); + } + } + return new ContractRef(settlement.getContractNo(), contract); } } throw new HcsException("C111 开票登记推送失败,应收结算链路回溯不到合同编号(applicationNo=" + application.getApplicationNo() + ",§9-U10 待确认关联字段)"); } + /** + * 合同引用(fdContractNumber / fdContract) + */ + private record ContractRef(String contractNo, HcsRefVO contract) { + } + /** * 结算币种ID(currency-id-mapping,必填;TMS 无币种字段按 RMB 取映射) */ diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsMasterDataSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsMasterDataSupport.java index d09c6836..0c123fd8 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsMasterDataSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsMasterDataSupport.java @@ -177,10 +177,11 @@ public class HcsMasterDataSupport { } /** - * 分页查询基础参数(columns 必填) + * 分页查询基础参数(offset/pageSize 必填,columns 各主数据接口选填) */ private HcsPageQueryDTO baseQuery() { HcsPageQueryDTO query = new HcsPageQueryDTO(); + // 【必填】每页条数 query.setPageSize(PAGE_SIZE); return query; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPerfRecordSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPerfRecordSyncSupport.java index 0ed6a3b1..740cfbc7 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPerfRecordSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsPerfRecordSyncSupport.java @@ -122,8 +122,13 @@ public class HcsPerfRecordSyncSupport { // 【必填】当前操作人 {fdLoginName}(付款申请创建人,§9-U2) param.setCurUser(HcsUserRefVO.ofLoginName(operatorLoginName)); param.setFormData(buildFormData(payment)); - // 附件挂载:attachmentsJson 转传,fdEntityKey=fd_plan_att - param.setMechanisms(buildMechanisms(payment, operatorLoginName)); + // 【必填】机制数据(附件):C108-1 必填,无附件传空列表(附件转传开关关闭或无附件时) + HcsMechanismsDTO mechanisms = buildMechanisms(payment, operatorLoginName); + if (mechanisms == null) { + mechanisms = new HcsMechanismsDTO(); + mechanisms.setAttachment(List.of()); + } + param.setMechanisms(mechanisms); return param; } @@ -152,9 +157,9 @@ public class HcsPerfRecordSyncSupport { props.setFdApplyAmount(payment.getAppliedAmount() == null ? null : payment.getAppliedAmount().toPlainString()); // 实际金额:paidAmount(实际付款推进后更新) props.setFdFactAmount(payment.getPaidAmount() == null ? null : payment.getPaidAmount().toPlainString()); - // 申请编号:付款申请单号(接口文档 §8.3 字段) + // 【必填】申请编号:付款申请单号 props.setFdApplyNo(payment.getPaymentNo()); - // 计划日期:applyDate(毫秒时间戳) + // 【必填】计划日期:applyDate(毫秒时间戳) props.setFdPlanDate(toMillis(payment.getApplyDate())); // 计划类型:paymentType(原文拼写 fd_paln_type 必须沿用) props.setFdPalnType(payment.getPaymentType()); @@ -162,10 +167,17 @@ public class HcsPerfRecordSyncSupport { props.setFdProperty(stageRow == null ? null : stageRow.getFundNature()); // 来源履约计划项ID:关联履约阶段 hcs_stage_fd_id(无关联则不传,§5.6) props.setFdId(stageRow == null ? null : stageRow.getHcsStageFdId()); - // 合同ID:HCS 合同ID(合同未推送时不传) + // 【必填】合同ID:HCS 合同ID(合同未推送时为空,联调确认兜底口径) props.setFdContractId(contractManage == null ? null : contractManage.getHcsFdId()); + // 业务ID:TMS 付款申请单主键(方便溯源,v4 新增) + props.setFdBusinessId(payment.getId() == null ? null : String.valueOf(payment.getId())); + // 创建时间:createTime(毫秒时间戳,v4 新增) + props.setFdCreateTime(payment.getCreateTime() == null ? null : payment.getCreateTime().toInstant().toEpochMilli()); // 表单模板ID:配置 perf-record.xform-id(环境值,§9-U9,未配置不传) - props.setFdXformId(StringUtil.isBlank(hcsProperties.getPerfRecord().getXformId()) ? null : hcsProperties.getPerfRecord().getXformId()); + String xformId = StringUtil.isBlank(hcsProperties.getPerfRecord().getXformId()) ? null : hcsProperties.getPerfRecord().getXformId(); + props.setFdXformId(xformId); + // 【必填】表单模板ID(formData 顶层 fd_xform_id,v4 必填) + formData.setFdXformId(xformId); formData.setDynamicProps(props); return formData; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsProjectSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsProjectSyncSupport.java index dc18fad1..a946cbfe 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsProjectSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsProjectSyncSupport.java @@ -45,8 +45,6 @@ import org.springblade.hcs.dto.HcsSaveOptionDTO; import org.springblade.hcs.dto.HcsUserRefVO; import org.springblade.hcs.exception.HcsException; import org.springblade.hcs.feign.IHcsClient; -import org.springblade.system.cache.UserCache; -import org.springblade.system.pojo.entity.User; import org.springblade.transport.constant.HcsSyncConstant; import org.springblade.transport.mapper.ProjectApplyMapper; import org.springblade.transport.pojo.entity.ProjectApply; @@ -112,7 +110,7 @@ public class HcsProjectSyncSupport { HcsProjectAddDTO param = new HcsProjectAddDTO(); HcsBpmOperationDTO bpmOperation = new HcsBpmOperationDTO(); - // 操作类型:固定 drafter_submit(以起草人身份直接提交流程) + // 【必填】操作类型:固定 drafter_submit(以起草人身份直接提交流程) bpmOperation.setOperationType("drafter_submit"); // 【必填】立项表单模板编码:配置 thirdParty.hcs.project.template-code(环境值,§9-U9) bpmOperation.setTemplateCode(requireTemplateCode()); @@ -123,7 +121,7 @@ public class HcsProjectSyncSupport { param.setCurUser(HcsUserRefVO.ofLoginName(operatorLoginName)); param.setFormData(buildFormData(projectApply, null)); HcsSaveOptionDTO saveOption = new HcsSaveOptionDTO(); - // saveDraft=false 直接提交 + // 【必填】是否保存草稿:saveDraft=false 直接提交 saveOption.setSaveDraft(false); param.setSaveOption(saveOption); @@ -176,8 +174,8 @@ public class HcsProjectSyncSupport { props.setFdCreatorUnit(creatorUnit); // 项目负责人:负责人登录名 {fdLoginName}(§9-U2) props.setFdHead(resolveUserRef(projectApply.getPrincipalUserId())); - // 承接部门:TMS 承接部门名称(同 fd_creator_unit 先传名称) - props.setFdTakerDept(HcsRefVO.ofName(projectApply.getUndertakeDeptName())); + // 承接部门:与创建单位一致,取配置 thirdParty.hcs.creator-unit-id/name(测试线联调固定广西物产城矿发展有限公司) + props.setFdTakerDept(creatorUnit); // 承接人:项目经办人登录名 {fdLoginName} props.setFdTaker(resolveUserRef(projectApply.getHandlerUserId())); // 付款额度:TMS fundLimit(万元)× 10000 转 HCS 元 @@ -186,7 +184,7 @@ public class HcsProjectSyncSupport { props.setFdOutInvoiceLimit(toYuan(projectApply.getReceivableLimit())); // 项目建设内容:ProjectApply.situationRemark props.setFdProContent(projectApply.getSituationRemark()); - // 是否可用:固定 true + // 【必填】是否可用:固定 true props.setFdIsAvailable(true); // 可用单位列表:与创建单位一致(同走 creator-unit 配置) props.setFdAvailUnits(List.of(creatorUnit)); @@ -199,7 +197,7 @@ public class HcsProjectSyncSupport { // TODO 待确认:项目收入目标 fd_pro_income_goal,TMS 无直接对应字段,一期不传(§5.1) // 金蝶同步状态:固定 "1" props.setFdKingdeeSyncStatus("1"); - // 来源标识:fd_sources,配置 thirdParty.hcs.src-system(约定值 WLTMS,D14) + // 【必填】来源标识:fd_sources,配置 thirdParty.hcs.src-system(约定值 WLTMS,D14) props.setFdSources(hcsProperties.getSrcSystem()); // 来源系统主键 ID:TMS 项目立项单主键(D14,对账/幂等候选键) props.setFdKingdeeId(String.valueOf(projectApply.getId())); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsReceiptBillSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsReceiptBillSyncSupport.java index 143d94e8..af7cdf54 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsReceiptBillSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsReceiptBillSyncSupport.java @@ -161,21 +161,21 @@ public class HcsReceiptBillSyncSupport { param.setFdLoginName(operatorLoginName); HcsReceiptBillFormDataDTO formData = new HcsReceiptBillFormDataDTO(); HcsReceiptBillPropsDTO props = new HcsReceiptBillPropsDTO(); - // 发票号码:invoiceNo + // 【必填】发票号码:invoiceNo props.setFdInvoiceCode(invoiceReceipt.getInvoiceNo()); - // 开票/收票日期:invoiceDate(YYYY-MM-DD 字符串) + // 【必填】开票/收票日期:invoiceDate(YYYY-MM-DD 字符串) props.setFdBillDate(formatBillDate(invoiceReceipt.getInvoiceDate())); // 开票方(销方):issuerName props.setFdInvoicer(invoiceReceipt.getIssuerName()); // 收票方(购方):receiverName props.setFdBuyer(invoiceReceipt.getReceiverName()); - // 价税合计金额:invoiceAmount + // 【必填】价税合计金额:invoiceAmount props.setFdInvoiceAmtTaxIncl(invoiceReceipt.getInvoiceAmount()); - // 税率(小数):TMS taxRate(如 13)÷ 100 → 0.13 + // 【必填】税率(小数):TMS taxRate(如 13)÷ 100 → 0.13 props.setFdTaxRate(toTaxRate(invoiceReceipt.getTaxRate())); - // 发票类型:receipt-bill.invoice-type-mapping 字典映射(§9-U3,未配置不传) + // 【必填】发票类型:receipt-bill.invoice-type-mapping 字典映射(§9-U3,未配置不传) props.setFdInvoiceType(hcsProperties.getReceiptBill().getInvoiceTypeMapping().get(invoiceReceipt.getInvoiceType())); - // 合同主题/编号:应付结算链路回溯,回溯不到取人工补录(D13) + // 【必填】合同主题/编号:应付结算链路回溯,回溯不到取人工补录(D13,均为空不传待联调兜底口径) ContractReference contractReference = resolveContract(invoiceReceipt); props.setFdContractSubject(contractReference.subject()); props.setFdContractNo(contractReference.contractNo()); diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsReconSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsReconSupport.java index 8b45eb5c..fdf1765b 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsReconSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsReconSupport.java @@ -92,7 +92,7 @@ public class HcsReconSupport { /** * 合同详情回查(C103-4,fdId 与 fdNumber 二选一) *

- * TODO 待联调确认:出参 data 结构 v4 未定义,原样返回实际响应(设计文档 §5.9) + * v4 已定义详情响应字段表(HcsContractDetailVO),级联/集合字段内部结构以实际返回为准(设计文档 §5.9) * * @param fdId 合同ID(可空) * @param fdNumber 合同编号(可空) diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsSpecPaySyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsSpecPaySyncSupport.java index 98370a1d..40ea1383 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsSpecPaySyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/hcs/HcsSpecPaySyncSupport.java @@ -123,30 +123,30 @@ public class HcsSpecPaySyncSupport { props.setFdContractName(requireContractFdId(payment, contractManage)); // 合同编号 props.setFdContractNo(payment.getContractNo()); - // 单据编号:付款申请单号(来源付款单标识) + // 【必填】单据编号:付款申请单号(来源付款单标识) props.setFdDocNo(payment.getPaymentNo()); - // 单据主题:"结算付款特批-" + 付款单号 + // 【必填】单据主题:"结算付款特批-" + 付款单号 props.setFdDocSubject("结算付款特批-" + payment.getPaymentNo()); // 来源付款单ID:付款申请单号(§5.5 映射表) props.setFdId(payment.getPaymentNo()); - // 付款金额:appliedAmount + // 【必填】付款金额:appliedAmount props.setFdPayAmount(payment.getAppliedAmount()); - // 合计金额:settlementAmount + // 【必填】合计金额:settlementAmount props.setFdTotalAmount(payment.getSettlementAmount() == null ? BigDecimal.ZERO : payment.getSettlementAmount()); - // 付款人 / 收款人 + // 【必填】付款人 / 收款方 props.setFdPayer(payment.getPayerName()); props.setFdPayee(payment.getPayeeName()); - // 收款账户名 / 收款账号 / 开户行 + // 【必填】收款账户名 / 收款账号 / 开户行名称 props.setFdReceiveAccountName(payment.getReceiptAccountName()); props.setFdReceiveAccount(payment.getBankAccount()); props.setFdBankName(payment.getBankName()); - // 结算币种:TMS 无币种字段,按 currency-name-mapping 默认值(人民币) + // 【必填】结算币种:TMS 无币种字段,按 currency-name-mapping 默认值(人民币) props.setFdSettleCurrency(hcsProperties.getContract().getCurrencyNameMapping().getOrDefault("RMB", "人民币")); - // 付款用途 / 付款性质 / 付款类型:字典值配置(§9-U3 待联调后配置) + // 【必填】付款用途 / 款项性质 / 款项类型:字典值配置(§9-U3 待联调后配置) props.setFdPaymentPurpose(hcsProperties.getSpecPay().getPaymentPurpose()); props.setFdPaymentNature(hcsProperties.getSpecPay().getPaymentNature()); props.setFdPaymentType(hcsProperties.getSpecPay().getPaymentType()); - // 事由 / 补充说明:remark + // 【必填】事由 / 补充说明:remark props.setFdReason(payment.getRemark()); props.setFdSupplementNote(payment.getRemark()); // 单据状态:配置 spec-pay.doc-status(示例 10) @@ -154,7 +154,7 @@ public class HcsSpecPaySyncSupport { // 特批附件字段标识:固定 fd_spc_approval_attach props.setFdSpcApprovalAttach(SPEC_ATTACH_ENTITY_KEY); formData.setDynamicProps(props); - // 表单层单据主题 + // 【必填】表单层单据主题 formData.setFdDocSubject("结算付款特批-" + payment.getPaymentNo()); // 表单层单据状态:配置 spec-pay.doc-status formData.setFdDocStatus(hcsProperties.getSpecPay().getDocStatus()); diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/config/HcsProperties.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/config/HcsProperties.java index 2bb06b09..72a3876b 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/config/HcsProperties.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/config/HcsProperties.java @@ -165,6 +165,10 @@ public class HcsProperties { * TMS 结算方式 -> 付款|收款(fdSettlementType,§9-U3 字典映射待联调) */ private Map settlementTypeMapping = new HashMap<>(); + /** + * TMS 审核状态 -> HCS 合同状态(xformFields CONTRACT_STATUS 必填,draft/approving/approved 等,§9-U3 待联调后配置) + */ + private Map statusMapping = new HashMap<>(); /** * TMS 币种码 -> HCS 币种名称(照金蝶 RMB->CNY 映射惯例) */ diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsCategoryVO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsCategoryVO.java index a477400e..e497b40c 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsCategoryVO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsCategoryVO.java @@ -56,7 +56,23 @@ public class HcsCategoryVO implements Serializable { */ private HcsRefVO fdParent; /** - * 状态:enable / disable + * 状态:enable=启用 / disable=停用 */ private String fdStatus; + /** + * 层级ID:由各级分类 fdId 以 x 包裹拼接(x+上级fdId+x+fdId+x,v4 新增) + */ + private String fdHierarchyId; + /** + * 创建人 + */ + private HcsRefVO fdCreator; + /** + * 创建人部门 + */ + private HcsRefVO fdCreatorDept; + /** + * 创建时间(毫秒时间戳) + */ + private Long fdCreateTime; } diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractDetailVO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractDetailVO.java new file mode 100644 index 00000000..6b841977 --- /dev/null +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractDetailVO.java @@ -0,0 +1,519 @@ +/** + * BladeX Commercial License Agreement + * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved. + *

+ * Use of this software is governed by the Commercial License Agreement + * obtained after purchasing a license from BladeX. + *

+ * 1. This software is for development use only under a valid license + * from BladeX. + *

+ * 2. Redistribution of this software's source code to any third party + * without a commercial license is strictly prohibited. + *

+ * 3. Licensees may copyright their own code but cannot use segments + * from this software for such purposes. Copyright of this software + * remains with BladeX. + *

+ * Using this software signifies agreement to this License, and the software + * must not be used for illegal purposes. + *

+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is + * not liable for any claims arising from secondary or illegal development. + *

+ * Author: Chill Zhuang (bladejava@qq.com) + */ +package org.springblade.hcs.dto; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +/** + * 合同合规系统(HCS)C103-4 合同详情出参(v4 字段表) + *

+ * 级联/集合类字段(对象/数组)内部结构 v4 标注以实际返回为准,暂以 Object/List<Object> 承接, + * 联调确认后细化。fdSepcailContract 为接口文档原文拼写(Special 笔误,必须沿用)。 + * + * @author Chill + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class HcsContractDetailVO implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + /** + * 合同ID + */ + private String fdId; + /** + * 租户ID + */ + private String fdTenantId; + /** + * 可阅读标示 + */ + private String fdReaderFlag; + /** + * 不可阅读标记(可阅读者在文档发布前生效) + */ + private String fdNotReaderFlag; + /** + * 可阅读者(在文档发布前生效) + */ + private String fdRBPFlag; + /** + * 修改人 + */ + private String fdAlter; + /** + * 修改时间(毫秒时间戳) + */ + private Long fdAlterTime; + /** + * 描述 + */ + private String fdDesc; + /** + * 是否隐藏 + */ + private Boolean fdIsHidden; + /** + * 最后修改时间(毫秒时间戳) + */ + private Long fdLastModifiedTime; + /** + * 合同名称 + */ + private String fdSubject; + /** + * 合同分类(层级ID) + */ + private String fdCateHierarchyId; + /** + * 编号 + */ + private String fdNumber; + /** + * 状态:draft=草稿; approving=审批中; approved=已审批; tosign=待签订; signing=签订中; signerror=签订异常; signed=已签订等 + */ + private String fdStatus; + /** + * 合同发起ID + */ + private String fdDraftMainId; + /** + * 合同模板ID + */ + private String fdTemplateId; + /** + * 审批状态:approving=审批中; approved=已审批; approvalinvalid=审批作废 + */ + private String fdApprovalStatus; + /** + * 签订状态:tosign=待签订; signing=签订中; signerror=签订异常; signed=已签订; signinvalid=签订作废 + */ + private String fdSignStatus; + /** + * 签订异常信息 + */ + private String fdSignErrorMsg; + /** + * 进入待签订时间(毫秒时间戳) + */ + private Long fdToSignTime; + /** + * 签订发起时间(毫秒时间戳) + */ + private Long fdSignCreateTime; + /** + * 完成签订时间(毫秒时间戳) + */ + private Long fdSignedTime; + /** + * 归档状态:toarchive=待归档; archiving=归档中; archived=已归档; archiveerror=归档异常 + */ + private String fdArchiveStatus; + /** + * 变更状态:changing=变更中; changed=已变更; terminated=已终止 + */ + private String fdChangeStatus; + /** + * 履约状态:toplan=待履约; planing=履约中; planerror=履约异常; planed=已履约; planterminate=履约终止 + */ + private String fdPlanStatus; + /** + * 进入待履约时间(毫秒时间戳) + */ + private Long fdToPlanTime; + /** + * 完成履约时间(毫秒时间戳) + */ + private Long fdPlanedTime; + /** + * 关闭状态:toclose=待关闭; closing=关闭中; closed=已关闭 + */ + private String fdCloseStatus; + /** + * 进入待关闭时间(毫秒时间戳) + */ + private Long fdToCloseTime; + /** + * 关闭时间(毫秒时间戳) + */ + private Long fdClosedTime; + /** + * 签署提供者:psign=物理签署; esign=电子签署; qjsign=智能用印签署 + */ + private String fdSignProvider; + /** + * 签署实体ID + */ + private String fdSignEntityId; + /** + * 归档方式:auto=一键申请; review=流程申请 + */ + private String fdFileWay; + /** + * 归档实体ID + */ + private String fdArchiveEntityId; + /** + * 进入待归档时间(毫秒时间戳) + */ + private Long fdToArchiveTime; + /** + * 完成归档时间(毫秒时间戳) + */ + private Long fdArchivedTime; + /** + * 履约计划创建时机:draft=起草环节创建; toplan=履约环节创建 + */ + private String fdPlanCreateMoment; + /** + * 关闭方式:auto=一键关闭; review=流程关闭 + */ + private String fdCloseWay; + /** + * 关闭实体ID + */ + private String fdCloseEntityId; + /** + * 是否锁定 + */ + private Boolean fdIsLocked; + /** + * 锁定原因:invalid=合同作废; change=合同变更; termination=合同终止 + */ + private String fdLockReason; + /** + * 合同作废实体ID + */ + private String fdInvalidEntityId; + /** + * 上次合同变动发起实体ID + */ + private String fdLastChangeEntityId; + /** + * 合同终止发起实体ID + */ + private String fdTerminationEntityId; + /** + * 批量发起任务ID + */ + private String fdBatchTaskId; + /** + * 是否关联交易 + */ + private Boolean fdIsRelaDeal; + /** + * 是否补录 + */ + private Boolean fdIsRecord; + /** + * 履约计划(级联字段,结构以实际返回为准) + */ + private Object fdPlan; + /** + * 验收计划(级联字段,结构以实际返回为准) + */ + private Object fdAcptPlan; + /** + * 外部合同数据(级联字段,结构以实际返回为准) + */ + private Object fdOuterAttr; + /** + * 订单明细配置ID + */ + private String fdOrderDetailConfigId; + /** + * 收付款进度(结构以实际返回为准) + */ + private Object fdPayColProgress; + /** + * 开票进度(结构以实际返回为准) + */ + private Object fdInvoiceProgress; + /** + * 履约状态(新):0=正常; 1=低风险; 2=中风险; 3=高风险 + */ + private Integer fdPlanStatusNew; + /** + * 是否冻结 + */ + private Boolean fdIsFreeze; + /** + * 解冻表单关联ID + */ + private String fdUnfreezeFormId; + /** + * 合同履约流程状态:00/01/02/10/11/12/20/21/29/30/39 + */ + private String fdPlanFlowStatus; + /** + * 合同履约流程ID + */ + private String fdPlanFlowId; + /** + * 是否评分 + */ + private Boolean fdRated; + /** + * 完成审批时间(毫秒时间戳) + */ + private Long fdApprovedTime; + /** + * 是否同步金蝶 + */ + private Boolean fdIsSyncJd; + /** + * 同步金蝶状态:0/1/2 + */ + private Integer fdSyncJdStatus; + /** + * 特批合同(字段名原文拼写笔误,必须沿用) + */ + private Boolean fdSepcailContract; + /** + * 合同结算模式:open=开口合同; close=闭口合同 + */ + private String fdContractGwNature; + /** + * 合同类型:standard=标准合同; halfstandard=半标准合同; notstandard=非标准合同 + */ + private String fdContractCharacter; + /** + * 合同性质:general=普通合同; framework=框架协议 + */ + private String fdContractNature; + /** + * 引用范本ID + */ + private String fdModelId; + /** + * 合同属性:main=主合同; child=子合同; common=普通 + */ + private String fdContractAttribute; + /** + * 承办人 + */ + private HcsRefVO fdUnderTaker; + /** + * 承办人部门 + */ + private HcsRefVO fdUnderTakerDept; + /** + * 预计开始时间(毫秒时间戳) + */ + private Long fdEstimateStartTime; + /** + * 预计结束时间(毫秒时间戳) + */ + private Long fdEstimateEndTime; + /** + * 实际开始时间(毫秒时间戳) + */ + private Long fdStartTime; + /** + * 实际结束时间(毫秒时间戳) + */ + private Long fdEndTime; + /** + * 合同发起来源:inner=内部发起; outer=外部发起 + */ + private String fdContractSource; + /** + * 外部来源系统 + */ + private String fdOuterSystem; + /** + * 合同结算类型:payment=付款; payment_collection=收支双向; collection=收款; none=不结算 + */ + private String fdSettlementType; + /** + * 合同金额 + */ + private BigDecimal fdAmount; + /** + * 币种 + */ + private String fdCurrencyId; + /** + * 是否原始合同 + */ + private Boolean fdIsOrigin; + /** + * 原始合同ID + */ + private String fdOriginContractId; + /** + * 合同变更类型:change=合同变更; termination=合同终止 + */ + private String fdChangeType; + /** + * 是否含税 + */ + private Boolean fdIncludeTax; + /** + * 是否引用范本 + */ + private Boolean fdUseModel; + /** + * 引用范本名称 + */ + private String fdModelName; + /** + * 引用范本版本 + */ + private String fdModelVersion; + /** + * 是否固定期限 + */ + private Boolean fdIsFixedTerm; + /** + * 合同开始期限 + */ + private String fdStartTerm; + /** + * 合同结束期限 + */ + private String fdEndTerm; + /** + * 有效期限 + */ + private String fdValidTerm; + /** + * 项目立项ID + */ + private String fdProjectId; + /** + * 合同份数 + */ + private Integer fdServings; + /** + * 合同说明 + */ + private String fdContractDescription; + /** + * 合同的变更流程状态:changing=变更中; changed=已变更; noChangeProcess=无变更流程 + */ + private String fdChangeLbpmStatus; + /** + * 紧急程度:1=普通; 2=急件; 3=特急 + */ + private Integer fdUrgencyLevel; + /** + * 创建人 + */ + private HcsRefVO fdCreator; + /** + * 创建时间(毫秒时间戳) + */ + private Long fdCreateTime; + /** + * 创建者部门 + */ + private HcsRefVO fdCreatorDept; + /** + * 权限(级联字段,结构以实际返回为准) + */ + private Object fdPermissions; + /** + * 可阅读者(结构以实际返回为准) + */ + private List fdReaders; + /** + * 所有可阅读者(结构以实际返回为准) + */ + private List fdAllReaders; + /** + * 所有可阅读者ID(结构以实际返回为准) + */ + private List fdAllReaderIds; + /** + * 可维护者(结构以实际返回为准) + */ + private List fdEditors; + /** + * 所有可编辑者(结构以实际返回为准) + */ + private List fdAllEditors; + /** + * 协办人(结构以实际返回为准) + */ + private List fdCoTakers; + /** + * 合同时间线(结构以实际返回为准) + */ + private List fdTimeLines; + /** + * 合同关联(结构以实际返回为准) + */ + private List fdRelations; + /** + * 合同签约方及地位(结构以实际返回为准) + */ + private List fdStandingSigners; + /** + * 签印文件(结构以实际返回为准) + */ + private List fdSignFiles; + /** + * 业务明细(结构以实际返回为准) + */ + private List fdBusinessDetails; + /** + * 付款记录(结构以实际返回为准) + */ + private List fdPaymentRecords; + /** + * 收款记录(结构以实际返回为准) + */ + private List fdCollectionRecords; + /** + * 收票记录(结构以实际返回为准) + */ + private List fdInInvoices; + /** + * 开票记录(结构以实际返回为准) + */ + private List fdOutInvoices; + /** + * 预填写物理签印信息(结构以实际返回为准) + */ + private List fdPsignContents; + /** + * 审批人(结构以实际返回为准) + */ + private List fdApprovers; + /** + * 履约规则(结构以实际返回为准) + */ + private List fdExePlanRules; +} diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractDraftDTO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractDraftDTO.java index bad3366b..d105f8ba 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractDraftDTO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractDraftDTO.java @@ -43,6 +43,10 @@ import java.io.Serializable; public class HcsContractDraftDTO implements Serializable { @Serial private static final long serialVersionUID = 1L; + /** + * 合同ID(C103-11 合同更新顶层必填,传 C103-1 返回的 fdContractId;C103-1 新建不传) + */ + private String fdId; /** * 合同模板ID(C103-6 模板列表获取,配置 template-mapping,§9-U7) */ diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractFieldJsonDTO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractFieldJsonDTO.java index 702bcbea..718c39b4 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractFieldJsonDTO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsContractFieldJsonDTO.java @@ -36,7 +36,7 @@ import java.util.List; /** * 合同合规系统(HCS)C103-1 合同发起 fdFieldJson 节点(C103-1 新建 / C103-11 更新共用) *

- * §9-U8 待联调确认:v4 未定义合同附件传递字段,附件挂载方式待合规方确认后补充。 + * v4 文档已定义 attachment 附件挂载(fdId/fdBindType 必填,fdEntityKey 仅给出特批附件枚举 eopCdraftSpecial)。 * * @author Chill */ @@ -54,4 +54,8 @@ public class HcsContractFieldJsonDTO implements Serializable { * 签署方(相对方)列表 */ private List signer; + /** + * 附件数据(C103-1 必填,C103-11 更新不传;fdEntityKey 普通附件枚举待合规方给出,暂不传) + */ + private List attachment; } diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsCurrencyVO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsCurrencyVO.java index 09d2a3fe..f3f98a61 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsCurrencyVO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsCurrencyVO.java @@ -75,4 +75,12 @@ public class HcsCurrencyVO implements Serializable { * 是否本位币 */ private Boolean fdIsStandardCurrency; + /** + * 创建人 + */ + private HcsRefVO fdCreator; + /** + * 创建时间(毫秒时间戳) + */ + private Long fdCreateTime; } diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsInvoiceRegAddDTO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsInvoiceRegAddDTO.java index e1d90bf1..705b5207 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsInvoiceRegAddDTO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsInvoiceRegAddDTO.java @@ -60,6 +60,10 @@ public class HcsInvoiceRegAddDTO implements Serializable { * 合同编号(必填,经应收结算链路回溯,§9-U10) */ private String fdContractNumber; + /** + * 合同 {fdId, fdName}(v4 新增,fdId 为合规合同ID,随编号一并回溯) + */ + private HcsRefVO fdContract; /** * 发票类型(字典映射 invoice-type-mapping,§9-U3) */ diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsPerfRecordPropsDTO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsPerfRecordPropsDTO.java index 799bb389..20fcbcf3 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsPerfRecordPropsDTO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsPerfRecordPropsDTO.java @@ -97,6 +97,16 @@ public class HcsPerfRecordPropsDTO implements Serializable { */ @JsonProperty("fd_contract_id") private String fdContractId; + /** + * 创建时间(毫秒时间戳,v4 新增) + */ + @JsonProperty("fd_create_time") + private Long fdCreateTime; + /** + * 业务ID(方便溯源用,v4 新增,TMS 传付款申请单ID) + */ + @JsonProperty("fd_business_id") + private String fdBusinessId; /** * 附件不可下载 */ diff --git a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsTemplateVO.java b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsTemplateVO.java index c0270741..8b738772 100644 --- a/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsTemplateVO.java +++ b/blade-third-party-api/blade-hcs-api/src/main/java/org/springblade/hcs/dto/HcsTemplateVO.java @@ -59,6 +59,10 @@ public class HcsTemplateVO implements Serializable { * 合同性质(如 standard) */ private String fdContractCharacter; + /** + * 分类层级ID(v4 新增) + */ + private String fdCateHierarchyId; /** * 创建时间(毫秒时间戳) */ @@ -71,6 +75,18 @@ public class HcsTemplateVO implements Serializable { * 创建部门 */ private HcsRefVO fdCreatorDept; + /** + * 是否禁止更新主数据权限 + */ + private Boolean fdDisableUpdateMainAuth; + /** + * 主数据授权时间点(如 afterapproved) + */ + private String fdAuthToMainTime; + /** + * 是否强制自动编号 + */ + private Boolean fdForceAutoNumber; /** * 模板扩展属性(含中文名) */ 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 e545d6ec..f3bee019 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 @@ -31,6 +31,7 @@ import org.springblade.hcs.dto.HcsAttachmentDownloadDTO; import org.springblade.hcs.dto.HcsAttachmentVO; import org.springblade.hcs.dto.HcsCategoryVO; import org.springblade.hcs.dto.HcsContractDetailQueryDTO; +import org.springblade.hcs.dto.HcsContractDetailVO; import org.springblade.hcs.dto.HcsContractDraftDTO; import org.springblade.hcs.dto.HcsContractDraftVO; import org.springblade.hcs.dto.HcsContractVO; @@ -173,13 +174,13 @@ public interface IHcsClient { /** * C103-4 合同详情(fdId 与 fdNumber 二选一) *

- * TODO 待联调确认:出参 data 结构 v4 未定义,暂以对象承接,联调后补充(设计文档 §5.9) + * v4 已定义详情响应字段表({@link HcsContractDetailVO});级联/集合字段内部结构以实际返回为准。 * * @param param 请求参数 - * @return 合同详情(结构待联调确认) + * @return 合同详情 */ @PostMapping(CONTRACT_DETAIL_URL) - HcsResult contractDetail(@RequestBody HcsContractDetailQueryDTO param); + HcsResult contractDetail(@RequestBody HcsContractDetailQueryDTO param); /** * C103-9(新) 合同履约规则同步(行级增删改,与废弃旧接口同路径不同入参,务必用本新版结构)