From 076145d7f6731775c2152af4790f15464e96a72a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Wed, 14 Oct 2026 14:11:31 +0800 Subject: [PATCH] =?UTF-8?q?:feat:=20=E5=AE=A1=E6=89=B9=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=9B=E5=BB=BA=E5=B1=A5=E7=BA=A6=E8=AE=A1?= =?UTF-8?q?=E5=88=92=E8=A1=8C=EF=BC=8CC103-9=E5=90=8C=E6=AD=A5=E5=89=8D?= =?UTF-8?q?=E7=BD=AE=E8=87=B3=E7=89=B9=E6=89=B9=E6=8C=82=E8=B5=B7=E4=B9=8B?= =?UTF-8?q?=E5=89=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transport/constant/HcsSyncConstant.java | 37 +++++++ .../service/IContractExeStageService.java | 9 ++ .../impl/ContractExeStageServiceImpl.java | 55 ++++++++-- .../impl/ContractManageServiceImpl.java | 4 + .../support/hcs/HcsContractSyncSupport.java | 36 ++++--- .../hcs合同/2026-10-11-hcs合同推送流程梳理.md | 101 ++++++++++++++++-- 6 files changed, 209 insertions(+), 33 deletions(-) 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 e056a78a..3927006e 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 @@ -212,6 +212,43 @@ public final class HcsSyncConstant { */ public static final String SPEC_REVIEW_NODE = "特批审核"; + // ==================== 履约计划行(blade_contract_exe_stage,C103-9) ==================== + + /** + * 行级同步操作:无(同步成功后清除标记) + */ + public static final String ROW_OP_NONE = "none"; + + /** + * 行级同步操作:新增 + */ + public static final String ROW_OP_ADD = "add"; + + /** + * 行级同步操作:更新 + */ + public static final String ROW_OP_UPDATE = "update"; + + /** + * 行级同步操作:删除 + */ + public static final String ROW_OP_DELETE = "delete"; + + /** + * 履约类型:付款 + */ + public static final String PERFORM_TYPE_PAYMENT = "payment"; + + /** + * 履约类型:收款 + */ + public static final String PERFORM_TYPE_COLLECTION = "collection"; + + /** + * 款项性质:进度款 + */ + public static final String FUND_NATURE_PROGRESS = "progress"; + // ==================== Redis 缓存 key(照 BFI blade:third: 前缀惯例) ==================== /** diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IContractExeStageService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IContractExeStageService.java index 15133197..53421060 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IContractExeStageService.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IContractExeStageService.java @@ -26,6 +26,7 @@ package org.springblade.transport.service; import org.springblade.core.mp.base.BaseService; +import org.springblade.transport.pojo.entity.ContractManage; import org.springblade.transport.pojo.entity.HcsContractExeStage; import java.util.List; @@ -45,6 +46,14 @@ public interface IContractExeStageService extends BaseService listByContractId(Long contractId); + /** + * 审批通过自动创建默认履约计划行(合同下无规则行时):承运商合同=付款进度款(收票规则取合同结算模式), + * 客户合同=收款进度款;金额/资金日期留空,随合同链路推 C103-9 + * + * @param contractManage 合同单(审批通过) + */ + void createDefaultRowOnApprove(ContractManage contractManage); + /** * 保存合同履约规则行(按行差异置同步标记:新行/未同步行 add,已同步行 update) * diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractExeStageServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractExeStageServiceImpl.java index 08f0cc06..0589d8b8 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractExeStageServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractExeStageServiceImpl.java @@ -57,11 +57,6 @@ import java.util.List; @RequiredArgsConstructor public class ContractExeStageServiceImpl extends BaseServiceImpl implements IContractExeStageService { - /** - * 行级同步操作:无 - */ - private static final String ROW_OP_NONE = "none"; - private final ContractManageMapper contractManageMapper; private final HcsProperties hcsProperties; @@ -87,7 +82,7 @@ public class ContractExeStageServiceImpl extends BaseServiceImpllambdaQuery().eq(HcsContractExeStage::getContractId, contractId)) > 0) { + return; + } + HcsContractExeStage row = new HcsContractExeStage(); + row.setContractId(contractId); + if ("承运商合同".equals(contractManage.getContractCategory())) { + row.setPerformType(HcsSyncConstant.PERFORM_TYPE_PAYMENT); + row.setInvoiceRule(mapInvoiceRule(contractManage.getSettlementMode())); + } else if ("客户合同".equals(contractManage.getContractCategory())) { + row.setPerformType(HcsSyncConstant.PERFORM_TYPE_COLLECTION); + } else { + log.info("合同类别非承运商/客户,不自动创建履约计划行:contractNo={},contractCategory={}", contractManage.getContractNo(), contractManage.getContractCategory()); + return; + } + // 默认进度款计划行:金额/资金日期留空,随合同链路推 C103-9 + row.setFundNature(HcsSyncConstant.FUND_NATURE_PROGRESS); + row.setFundType(hcsProperties.getExeStage().getFundType()); + row.setIsFinish(0); + row.setRowOp(HcsSyncConstant.ROW_OP_ADD); + row.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_UNSYNCED); + row.setHcsSyncMsg("审批通过自动创建,待随合同链路同步(C103-9)"); + save(row); + log.info("审批通过自动创建履约计划行:contractNo={},contractCategory={},performType={},invoiceRule={}", + contractManage.getContractNo(), contractManage.getContractCategory(), row.getPerformType(), row.getInvoiceRule()); + } + + /** + * 结算模式文本映射 C103-9 开票规则:先款后票=payFirst、先票后款=invoiceFirst,其余(月结/现结等)不传 + */ + private String mapInvoiceRule(String settlementMode) { + if ("先款后票".equals(settlementMode)) { + return "payFirst"; + } + if ("先票后款".equals(settlementMode)) { + return "invoiceFirst"; + } + return null; + } + /** * 行字段校验 */ @@ -144,7 +181,7 @@ public class ContractExeStageServiceImpl extends BaseServiceImpllambdaUpdate() .eq(HcsContractExeStage::getContractId, contractManage.getId()) .isNull(HcsContractExeStage::getHcsStageFdId) 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 e0cc305d..f7884112 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 @@ -72,9 +72,9 @@ import java.util.Objects; *

* 扫描任务按序执行:⓪ 特批挂起门禁 → ① 客商风险校验(可配开关,仅留痕,高风险不再阻断)→ * ② 附件转传(v4 挂载点 fdFieldJson.attachment,随 C103-1 挂载)→ ③ C103-3 判重(§9-U4 查询能力联调确认)→ - * ④ C103-1 起草 / 变更单 C103-11 更新(§9-U5 定位方式待联调)→ ⑤ 高风险/黑名单挂起"特批审核" - * (外部客商管控:报文随 fdSepcailContract=true 在合规侧走特批,{@link HcsContractSpecSyncSupport} 接收结果)→ - * ⑥ 履约规则 C103-9 行级同步({@link HcsExeStageSyncSupport})。 + * ④ C103-1 起草 / 变更单 C103-11 更新(§9-U5 定位方式待联调)→ ⑤ 履约计划 C103-9 行级同步({@link HcsExeStageSyncSupport}, + * 仅依赖 hcs_fd_id,先于特批挂起执行,失败补偿不被特批门禁阻塞)→ ⑥ 高风险/黑名单挂起"特批审核" + * (外部客商管控:报文随 fdSepcailContract=true 在合规侧走特批,{@link HcsContractSpecSyncSupport} 接收结果)。 * 结果留痕:风险校验写 blade_hcs_check_log 与合同 hcs_risk_* 字段;推送结果回填 hcs_fd_id/hcs_sync_status。 * * @author Chill @@ -94,6 +94,11 @@ public class HcsContractSyncSupport { */ private static final String BLACK_STATUS_YES = "yes"; + /** + * signer 相对方单位类型:暂统一传 customer(客户,2026-10-14 联调确认,§9-U6 后续细化) + */ + private static final String SIGNER_FD_TYPE_CUSTOMER = "customer"; + private final IHcsClient hcsClient; private final HcsProperties hcsProperties; private final ContractManageMapper contractManageMapper; @@ -105,7 +110,7 @@ public class HcsContractSyncSupport { /** * 推送合同到 HCS:特批挂起门禁 → 风险校验(仅留痕,高风险不再阻断)→ 附件转传 → 判重 → 起草/更新 → 回填合规 fdId 置 synced - * → 高风险/黑名单客商合同挂起"特批审核"等待合规特批结果(报文随 fdSepcailContract=true,外部客商管控) + * → 履约计划行级同步(C103-9,先于特批挂起)→ 高风险/黑名单客商合同挂起"特批审核"等待合规特批结果(报文随 fdSepcailContract=true,外部客商管控) * * @param contractManage 合同单(approvalStatus 须为 approved/change_approved) * @return 推送结果描述(供任务汇总与 hcs_sync_msg 落库) @@ -145,17 +150,17 @@ public class HcsContractSyncSupport { markSynced(contractManage, contractManage.getHcsFdId(), "C103-11 合同更新成功"); resultMessage = "C103-11 合同更新成功"; } - // ⑤ 高风险/黑名单客商(外部客商管控):起草/更新报文已随 fdSepcailContract=true 在合规侧发起特批流程, + // ⑤ 履约规则 C103-9 行级同步(随合同链路,§5.3;仅依赖 hcs_fd_id 与特批无关,先于特批挂起执行—— + // 失败抛出落 failed 时特批未挂起,修复后可直接重推补偿,不被特批门禁阻塞) + if (hcsProperties.getExeStage().isSyncEnabled()) { + resultMessage = resultMessage + ";" + hcsExeStageSyncSupport.syncExeStages(contractManage); + } + // ⑥ 高风险/黑名单客商(外部客商管控):起草/更新报文已随 fdSepcailContract=true 在合规侧发起特批流程, // 此处挂起"特批审核"等待结果(合规推送 contractLegal/result 或定时 C103-4 查询联动恢复/驳回) if (risky) { hangSpecReview(contractManage); } - // ⑥ 履约规则 C103-9 行级同步(随合同链路,§5.3;一期暂不对接默认关,打开后失败抛出由任务落 failed,下轮凭 hcs_fd_id 走更新补偿) - if (!hcsProperties.getExeStage().isSyncEnabled()) { - return resultMessage; - } - String exeStageResult = hcsExeStageSyncSupport.syncExeStages(contractManage); - return resultMessage + ";" + exeStageResult; + return resultMessage; } /** @@ -361,7 +366,10 @@ public class HcsContractSyncSupport { settlementType = HcsContractFieldConstant.SETTLEMENT_TYPE_COLLECTION; } if (StringUtil.isNotBlank(settlementType)) { - fields.add(field(HcsContractFieldConstant.FIELD_FD_SETTLEMENT_TYPE, "合同结算类型", settlementType)); + HcsXformFieldDTO settlementField = field(HcsContractFieldConstant.FIELD_FD_SETTLEMENT_TYPE, "合同结算类型", settlementType); + // 字典类字段需带 fdIsSystem=true(合规侧按系统字典值解析,2026-10-14 联调确认) + settlementField.setFdIsSystem("true"); + fields.add(settlementField); } else { log.warn("HCS合同结算类型无法确定:contractCategory=[{}] 非承运商合同/客户合同,fdSettlementType 不传", contractManage.getContractCategory()); } @@ -409,7 +417,7 @@ public class HcsContractSyncSupport { } /** - * signer 相对方(签署方):甲/乙双方,fdType(inner/外部)判定规则待联调(§9-U6)暂不传 + * signer 相对方(签署方):甲/乙双方,fdType 暂统一传 customer(客户,2026-10-14 联调确认) */ private List buildSigners(ContractManage contractManage) { List signers = new ArrayList<>(); @@ -431,6 +439,8 @@ public class HcsContractSyncSupport { signer.setFdName(partyName); // 相对方编号:按名称反查 CustomerArchive 客商编码,反查不到留空(§9-U6) signer.setFdNumber(queryCustomerCode(partyName)); + // 单位类型:暂统一传 customer(客户),inner/外部判定规则后续联调细化(§9-U6) + signer.setFdType(SIGNER_FD_TYPE_CUSTOMER); return signer; } diff --git a/doc/docs/hcs合同/2026-10-11-hcs合同推送流程梳理.md b/doc/docs/hcs合同/2026-10-11-hcs合同推送流程梳理.md index 6bdeb710..9eb25194 100644 --- a/doc/docs/hcs合同/2026-10-11-hcs合同推送流程梳理.md +++ b/doc/docs/hcs合同/2026-10-11-hcs合同推送流程梳理.md @@ -1,7 +1,7 @@ # 新建合同推送 HCS(合同合规系统)流程梳理 > 依据代码现状整理,核心类:`HcsContractSyncSupport`(blade-service/blade-transport/.../support/hcs)。 -> 对接接口:C101-1 风险校验、C103-2 附件上传、C103-3 合同判重、C103-1 合同发起、C103-11 合同更新、C103-8 特批、C103-9 履约规则;特批结果接收 `/hcs/contractLegal/result`(合规推送,替代未建设的 B103,见 §9.4)。 +> 对接接口:C101-1 风险校验、C103-2 附件上传、C103-3 合同判重、C103-1 合同发起、C103-11 合同更新、C103-8 特批、C103-9 履约计划、C108-1/C108-2 履约记录;特批结果接收 `/hcs/contractLegal/result`(合规推送,替代未建设的 B103,见 §9.4)。 > "必填" 标注来源:代码注释中标注的 v4 接口文档要求(HCS 侧),以及 TMS 推送前强校验(缺失直接失败)。 --- @@ -34,13 +34,13 @@ ④ 合同发起/更新 首推且未判重命中 → C103-1 发起(返回 fdContractId,必须持久化) 已有 hcsFdId(变更单)→ C103-11 更新(顶层 fdId 定位) -⑤ 自动特批(C103-8,高风险/黑名单 且 hcsSpecStatus ≠ approved 时) - 置 hcsSpecStatus=need + currentNode="特批审核"(TMS 流程挂起展示) - → 筛选「特批说明」附件(attachmentsJson 中 attachmentType=spec_explanation)转传 C103-2 - → 自动发起 C103-8 → hcsSpecStatus=processing - 发起失败保持 need 仅留痕,可人工经 /hcs/contract/spec-apply 重发 -⑥ 履约规则同步(C103-9,开关 exe-stage.sync-enabled,一期默认关闭) - 随合同链路行级同步,失败抛出走下轮凭 hcs_fd_id 更新补偿 +⑤ 履约计划同步(C103-9,开关 exe-stage.sync-enabled,一期默认关闭,详见 §十) + 仅依赖 hcs_fd_id,先于特批挂起执行(2026-10-14 调整); + 失败抛出走下轮凭 hcs_fd_id 更新补偿,不被特批门禁阻塞 +⑥ 自动特批挂起(高风险/黑名单 且 hcsSpecStatus ≠ approved 时) + 报文随 fdSepcailContract=true 在合规侧发起特批流程(2026-10-13 起,无独立 C103-8 发起接口) + → 置 hcsSpecStatus=processing + currentNode="特批审核"(TMS 流程挂起展示, + 等待合规推送 contractLegal/result 或 C103-4 定时查询联动;发起异常仅留痕) ``` 结果回填: @@ -139,7 +139,11 @@ | `contract.require-risk-check` | 推送前客商风险校验开关 | — | | `risk.block-blacklist` | 黑名单阻断付款提交(付款链路);合同链路不再阻断推送,高风险/黑名单转自动特批(§九) | — | | `attachment.transfer-enabled` | 附件转传开关 | 关闭时不挂附件 | -| `exe-stage.sync-enabled` | C103-9 履约规则同步开关(一期默认关) | — | +| `exe-stage.sync-enabled` | C103-9 履约计划同步开关(一期默认关) | — | +| `exe-stage.fund-type` | C103-9 行金额类型缺省值(默认 byAmount) | — | +| `operator-login-name` | C103-9 报文操作人登录名(默认 srvadmin,非承办人) | — | +| `perf-record.sync-enabled` | C108-1/2 履约记录同步开关(一期默认关) | — | +| `perf-record.xform-id` | 履约记录表单模板ID(待合规方提供) | 未配置不传 fd_xform_id | --- @@ -148,6 +152,7 @@ | 字段 | 含义 | | --- | --- | | `hcs_fd_id` | 合规合同ID(C103-1 返回的 fdContractId,判重命中也回填) | +| `hcs_exeplan_id` | 履约计划ID(C103-9 返回的 fdExeplanId,整体 update 定位用) | | `hcs_sync_status` | unsynced / synced / failed | | `hcs_retry_count` | 推送重试次数 | | `hcs_sync_time` / `hcs_sync_msg` | 最近推送时间 / 结果描述 | @@ -193,8 +198,8 @@ TMS 审批通过(approved / change_approved) → 即时推送 / 扫描兜底 → pushContract → ① 风险校验留痕(risky 标志,不阻断) → ④ C103-1 起草成功(hcs_sync_status=synced,回填 hcs_fd_id) - → ⑤ 置 hcs_spec_status=need + currentNode="特批审核"(TMS 流程挂起) - → 筛「特批说明」附件转传 C103-2 → 自动发起 C103-8 → hcs_spec_status=processing + → ⑤ C103-9 履约计划同步(先于特批挂起;失败单据落 failed,修复后重推不被特批门禁阻塞) + → ⑥ 置 hcs_spec_status=processing + currentNode="特批审核"(TMS 流程挂起,合规侧随报文 fdSepcailContract=true 走特批) ``` - 原设计"黑名单挂起不推送、人工发起特批"存在死锁(挂起时无 `hcs_fd_id`,C103-8 报文必填合规合同ID 永远失败),本次变更为 **先 C103-1 起草、后 C103-8 特批**,特批通过即合规侧放行签约,无需恢复推送; @@ -218,3 +223,77 @@ TMS 审批通过(approved / change_approved) | rejected | `approvalStatus=rejected` + `currentNode="已驳回"`,走重新编辑 → 提交 → 审批 → 重新特批闭环(重新推送时 C103-11 更新后再次自动特批),reason 随原文见 `hcs_spec_msg` | > 等效兜底:页面人工确认(`POST /hcs/contract/spec/confirm`,合同)与(`POST /hcs/spec-pay/confirm`,付款)与合规推送等效,二者均以先到为准。原推测性接收端点 `POST /hcs/callback/spec-result`(B103 候选键解析)已删除。 + +--- + +## 十、履约计划(C103-9)与履约记录(C108-1/C108-2)同步 + +> 业务定位:涉及收付款的合同须在合规侧建立履约计划,付款履约记录凭计划阶段ID(`hcs_stage_fd_id`)关联阶段。 +> 一期 `exe-stage.sync-enabled=false`、`perf-record.sync-enabled=false` 暂不上报 HCS(2026-10-09 范围调整),但 `blade_contract_exe_stage` 表、维护端点与审批标记逻辑均在运行。 + +### 10.1 数据模型与维护入口 + +`blade_contract_exe_stage` 是 TMS 侧的**合同履约计划行项目表**:合同的收付款资金计划逐行存储(如"预付款 30 万 / 进度款 50 万 / 质保金 20 万"各一行),是 C103-9 推送 HCS 的数据源。单独建表而非挂合同主表 JSON 的原因: + +- **行级同步**:C103-9 是行级 add/update/delete 操作,每行需独立 `row_op` 标记、独立回填合规阶段ID、独立同步状态 +- **删除不可逆**:已同步行必须软删后凭 `hcs_stage_fd_id` 上报 delete,直接物理删会在合规侧留孤儿数据 +- **重试粒度**:单行失败(如 add 未匹配到返回阶段ID)可单独保持 failed 下轮重试,不拖累整单 +- **一期攒数据**:开关关闭不上报,但表与维护端点照常运行,打开后可凭已有数据补推 + +行字段(`HcsContractExeStage`): + +| 字段 | 说明 | +| --- | --- | +| `perform_type` | 履约类型 payment=付款 / collection=收款 | +| `fund_nature` | 款项性质 prepayment=预付 / progress=进度 / acceptance=验收 / retention=质保 | +| `fund_amount` / `fund_date` | 计划金额(元)/ 计划资金日期 | +| `invoice_rule` / `invoice_cycle` | 开票规则 payFirst=先款后票 / invoiceFirst=先票后款;账期(天) | +| `fund_type` / `is_finish` | 金额类型(空取配置 `exe-stage.fund-type`)/ 是否完成 | +| `row_op` | 行级同步标记 none / add / update / delete | +| `hcs_stage_fd_id` | 合规阶段ID(C103-9 返回,行 update/delete 全靠它,必须持久化) | +| `hcs_sync_status` / `hcs_sync_msg` | 行级同步状态与结果 | + +> `fund_type`(金额类型)是 HCS 报文要求的**金额口径声明**(byAmount=按固定金额),一期三级兜底恒为 byAmount(建表默认 → 行值为空取 `exe-stage.fund-type` → 推送组装时再兜底);其他口径(如按比例)值域 HCS 文档未给出,待联调后放开,代码不做枚举校验。 + +维护端点 `ContractExeStageController`(列表 / 批量提交 / 删除,`ContractExeStageServiceImpl`): + +- 校验:`performType` 必填且仅 payment/collection,计划金额非负 +- 新行置 `row_op=add` 待随合同链路首推;已同步行(有 `hcs_stage_fd_id`)编辑置 update、未同步行保持 add +- 删除:已同步行软删 + `row_op=delete`(须凭合规阶段ID 上报删除,不可物理删除);未同步行直接物理删除 + +### 10.2 同步时机 + +- 合同审批通过(`ContractManageServiceImpl#approve`):未同步行(`hcs_stage_fd_id is null`)统一置 `row_op=add` +- 执行位置:`pushContract` 第⑤步(先于特批挂起,2026-10-14 调整);前置强约束:合同须已有 `hcs_fd_id`(先 C103-1 起草、后 C103-9);开关关闭时直接跳过 + +### 10.3 C103-9 报文与回填(`HcsExeStageSyncSupport`) + +顶层(`HcsExeplanSyncDTO`):`fdContractId`=`hcs_fd_id`(合规合同ID,非 TMS 主键)、`fdOuterSystem`=`src-system`、`fdLoginName`=配置 `operator-login-name`(默认 srvadmin)、`fdEopExeplanOperateType` 首次 add / 已同步 update(看 `hcs_exeplan_id`,已同步则同时传 `fdExeplanId`)。 + +行级 `fdStages[]`(对应待同步行): + +| HCS 字段 | TMS 取值 | 备注 | +| --- | --- | --- | +| `fdId` | `hcs_stage_fd_id` | add 行不传;update/delete 必传 | +| `fdEopExeplanOperateType` | `row_op` | add / update / delete | +| `fdPerformType` | `perform_type` | 必填 | +| `fdFundNature` / `fdFundAmount` / `fdFundDate` | 同名字段 | 资金日期转毫秒时间戳 | +| `fdInvoiceRule` / `fdInvoiceCycle` | 同名字段 | 账期(天) | +| `fdFundType` | `fund_type`,空取 `exe-stage.fund-type` | 默认 byAmount | +| `fdIsFinish` | `is_finish` | boolean | +| `fdExtendContent` | 固定 `"{}"` | | + +取数与回填: + +- 取数 `selectSyncRows`:`row_op <> 'none'` 的行,**含软删的 delete 行**(原生 SQL 绕过逻辑删除过滤) +- 成功回填三件事:`fdExeplanId` → `blade_contract_manage.hcs_exeplan_id`;`fdChangeStages[]` 各行合规 fdId → `hcs_stage_fd_id`;成功行清 `row_op=none` 并置行级 synced +- `fdChangeStages` 与请求行对应关系 v4 未明确(待联调):行数一致按请求行序对应;不一致按 履约类型|款项性质|金额|资金日期 组合键匹配;add 行匹配不到保持 failed 待下轮重试 +- 失败抛异常走合同 `markFailed`,下轮凭 `hcs_fd_id` 整体重推补偿(§二⑥) + +### 10.4 履约记录(付款链路,C108-1/C108-2) + +`HcsPerfRecordSyncSupport`,随付款推送链路执行(`HcsPaymentSyncSupport`,开关 `perf-record.sync-enabled`,一期默认关): + +- 付款审批通过 → C108-1 新建,返回 fdId 回填付款申请 `hcs_perf_fd_id`(立即持久化) +- 实际付款推进(`paidAmount` 变化置待同步)→ C108-2 更新,`formData.fdId`=`hcs_perf_fd_id` 必填(响应无 data,success=true 即成功) +- 关联履约阶段:按合同 + 付款类型匹配**已同步**的计划行(`hcs_stage_fd_id` 非空),无关联不传 fd_id —— 履约计划同步是履约记录关联的前置