diff --git a/doc/docs/hcs合同/2026-09-27-桂物合同合规系统HCS接入技术设计.md b/doc/docs/hcs合同/2026-09-27-桂物合同合规系统HCS接入技术设计.md new file mode 100644 index 00000000..64822019 --- /dev/null +++ b/doc/docs/hcs合同/2026-09-27-桂物合同合规系统HCS接入技术设计.md @@ -0,0 +1,423 @@ +# 桂物合同合规系统(HCS)接入技术设计 + +> **日期**:2026-09-27 +> **依据**:《桂物合同集成相关接口说明-v4.docx》及其整理稿 [桂物合同集成接口逻辑梳理.md](../桂物合同集成接口逻辑梳理.md)、接口调试文件 [桂物合同集成接口-apifox导入.json](../桂物合同集成接口-apifox导入.json) +> **说明**:设计过程已明确排除《TMS业财融合-集成流程图文字版与业务流程梳理.md》,本文所有场景与规则仅以上述 v4 接口文档与 TMS 代码现状为依据 +> **关联决策**:[ADR-0001 定时扫描推送模式](../../adr/0001-hcs推送采用定时扫描模式.md)、[ADR-0002 履约规则独立数据表](../../adr/0002-履约规则独立数据表.md)、[ADR-0003 收款流水与认领记录不由TMS推送](../../adr/0003-收款流水与认领记录不由TMS推送.md) + +--- + +## 1. 决策记录(共识摘要) + +以下决策已经在设计评审中逐项确认: + +| # | 决策点 | 结论 | +|---|---|---| +| D1 | 客户端模块 | 新建 `blade-third-party-api/blade-hcs-api`,客户端 `IHcsClient`,配置前缀 `thirdParty.hcs.*`(照 blade-bfi-api 模式) | +| D2 | 认证 | v4 接口说明:所有接口固定携带 `Authorization`(整值可配)+ `Key-Auth` 两个静态请求头,由拦截器统一注入,不再调用 getToken 取令牌 | +| D3 | 网络 | 直连 `base-url` 可配置(Nacos),预留 iPaaS 前缀能力,代码不感知 | +| D4 | 范围 | 一期 24 个接口:C101-1、C102-1/2/3、C103-1/2/3/4/6/7/9(新)/11/12、C106-1/3/4、C108-1/2、C109-1/2、C111-1/2/3;排除 C104、C107、废弃旧履约接口 | +| D5 | TMS 角色 | TMS 是业务发起方:立项/合同/履约规则/特批/开票/收票/履约记录由 TMS 推送 | +| D6 | 落库模式 | 业务表加 `hcs_*` 集成字段;新建履约规则表 `blade_contract_exe_stage`;不建合规镜像库 | +| D7 | 可靠性 | 同步状态机 + `@Scheduled` 扫描首推/补偿 + 页面手动重推;Feign 无自动 Retryer;写前判重查询 | +| D8 | 交付物 | 本设计文档 + CONTEXT.md + ADR,落 `doc/docs/hcs合同/`(ADR 落 `doc/adr/`) | +| D9 | 触发模式 | 审批代码零埋点:approve/MK 回调只落 `approved + hcs_sync_status=unsynced`,扫描任务准实时首推(R3-Q1→(c))。付款申请/开票/收票的 MK 处理器由其他团队补齐,不在本设计范围 | +| D10 | 履约规则源头 | 新建 `blade_contract_exe_stage`,合同维度维护,C103-9 行级同步,合规 fdId 回填 | +| D11 | 履约记录来源 | 付款申请为主线:审批通过→C108-1 新增;实际付款推进→C108-2 更新 | +| D12 | 开票登记时机 | 审批通过即推 C111-2(票据日期空);金蝶开票完成后 C111-3 回填 | +| D13 | 收票合同关联 | 应付结算链路自动回溯;回溯不到收票表单加合同字段人工补录 | +| D14 | 来源标识 | `fd_sources="TMS"`(Nacos `src-system` 可配);`fd_kingdee_id`=TMS 业务单据主键 | +| D15 | 特批载体 | 付款申请表加 `hcs_credit_*`/`hcs_spec_*` 字段组;C106-1 提交时同步;超额转 C106-3;**特批结果回传方式未决**(过渡:页面人工确认);合同 `fdSepcailContract` 一期固定 false | + +--- + +## 2. 范围 + +### 2.1 接口范围(24 个) + +| 场景组 | 接口 | TMS 触发业务 | +|---|---|---| +| 项目立项 | C102-1 新建 / C102-2 更新 / C102-3 查询 | ProjectApply 审批通过 / 变更审批通过 / 判重与回查 | +| 合同 | C103-1 发起 / C103-11 更新 / C103-3 列表 / C103-4 详情 | ContractManage 审批通过 / 变更审批通过 / 判重与回查 | +| 附件 | C103-2 上传(下载 C103-5 备用) | 各单据推送前附件转传 | +| 主数据 | C103-6 模板 / C103-7 分类 / C103-12 币种 | 下拉/映射(模板ID、币种ID 缓存) | +| 履约规则 | C103-9(新) 行级同步 | blade_contract_exe_stage(合同维度) | +| 客商风险 | C101-1 | 合同推送前 + 付款提交前校验 | +| 额度与特批 | C106-1 校验 / C106-3 特批发起 / C106-4 特批更新 | PaymentApplication 提交时 / 审批通过后 | +| 履约记录 | C108-1 新增 / C108-2 更新 | PaymentApplication 审批通过 / 实际付款推进 | +| 开票登记 | C111-1 查询 / C111-2 新增 / C111-3 更新 | InvoiceApplication 审批通过 / 金蝶开票完成 | +| 收票单 | C109-1 新建 / C109-2 更新 | InvoiceReceipt 审批通过 / 票据变更 | + +### 2.2 明确排除(No-s) + +- **C104 收款流水(C104-1/2/3)、C107 认领记录(C107-1/2/3)**:不由 TMS 推送,推送方与链路待定(见 ADR-0003)。 +- **C103-9旧 / C103-10旧**:合规方已废弃,不接。 +- 附件下载 C103-5:仅在对账/排查需要时备用接入。 + +--- + +## 3. 总体架构 + +### 3.1 模块与包结构 + +``` +blade-third-party-api/blade-hcs-api/ (新建,照 blade-bfi-api 模式) +org.springblade.hcs +├── constant/HcsConstant.java # URI 常量(可被配置覆盖)、认证头名称 +├── config/HcsProperties.java # @ConfigurationProperties("thirdParty.hcs") +├── config/HcsFeignClientConfig.java # 覆盖全局拦截器、超时(connect 10s / read 60s) +├── interceptor/HcsAuthInterceptor.java # 所有请求注入 Authorization + Key-Auth 两个静态认证头(v4) +├── feign/IHcsClient.java # @FeignClient(name="HCS", url="${thirdParty.hcs.base-url}") +├── dto/ # 各接口请求/响应 DTO(HcsResult、HcsPageVO) +└── util/HcsPageUtil.java # queryAllPages 翻页工具(照 BfiUtil,默认上限 50 页) + +blade-service/blade-transport/ (业务侧扩展) +org.springblade.transport +├── support/hcs/ +│ ├── HcsProjectSyncSupport.java # 立项 C102 +│ ├── HcsContractSyncSupport.java # 合同 C103-1/11 + 前置:风险校验、附件转传、履约规则 +│ ├── HcsExeStageSyncSupport.java # 履约规则 C103-9 +│ ├── HcsCreditCheckSupport.java # C106-1 + C101-1(付款提交时同步校验) +│ ├── HcsSpecPaySyncSupport.java # 特批 C106-3/4 +│ ├── HcsInvoiceRegSyncSupport.java # 开票登记 C111 +│ ├── HcsReceiptBillSyncSupport.java # 收票单 C109 +│ └── HcsAttachmentSupport.java # 附件转传 + TMS→HCS 附件ID映射缓存 +├── task/HcsPushTask.java # @Scheduled 扫描首推/补偿(照 PaymentKingdeeResultTask 模式) +├── controller/HcsSyncController.java # 手动推送/重推、校验重放、对账查询端点 +└── entity/HcsContractExeStage.java # 履约规则实体(blade-transport-api) +``` + +依赖方向:`blade-transport` → `blade-hcs-api`(同 blade-transport → blade-bfi-api)。`blade-hcs-api` 不依赖业务模块。 + +### 3.2 认证设计(D2,v4 接口说明已变更) + +- **静态双请求头**:所有接口统一携带 `Authorization` 与 `Key-Auth` 两个请求头,由 `HcsAuthInterceptor` 注入,不再调用 getToken、不做令牌缓存。 +- 两个头的值均为整值可配(Nacos + 环境变量注入):`third-party.hcs.authorization`(含 `Basic ` 前缀,如 `Basic d2Njazp...`)、`third-party.hcs.key-auth`。前缀/密钥轮换只改配置,不改代码。 +- 未配置时拦截器告警并放行,由对端 401 暴露问题(便于环境配置缺失排查)。 + +### 3.3 超时与重试(D7) + +- Feign:connect 10s / read 60s(照 BfiFeignClientConfig),**不配 Retryer**——写接口重试会造成 HCS 重复建单。 +- 重试职责归扫描任务:失败落 `failed` 状态,下轮扫描按 `hcs_retry_count < max-retry` 自动重试,超限仅人工重推。 +- 幂等:写前判重(见 §5.1/§5.2),并依赖 `fd_kingdee_id`=TMS 主键作为对账/幂等候选键(HCS 侧是否按其幂等,联调确认,见 §9)。 + +### 3.4 字段标注规范(DTO 组装,照 `pushArBill` 惯例) + +所有 Support 组装 HCS 请求 DTO 时,**每个字段赋值的上一行必须以注释标注外部接口字段**,格式照 `KingdeeArBillSyncSupport#pushArBill` 的既有惯例: + +- 必填字段:`// 【必填】外部字段中文名`(层级用"主.子"表示,如"往来户.编码") +- 非必传字段:`// 外部字段中文名(非必传):TMS 取值来源说明` +- 取值来源统一跟在冒号后说明;字段中文名以《桂物合同集成接口逻辑梳理.md》各接口入参表的中文说明为准 +- 待联调确认的字段:`// TODO 待确认:...`,并标注对应设计文档 §9 未决事项编号 + +示例(C111-2 开票登记 DTO 组装): + +```java +HcsInvoiceRegAddDTO param = new HcsInvoiceRegAddDTO(); +// 【必填】合同编号:经应收结算链路回溯的合同编号 +param.setFdContractNumber(contractNo); +// 单据编号:开票申请单号(同租户唯一,判重候选键) +param.setFdNumber(application.getApplicationNo()); +// 【必填】结算币种:TMS 币种码映射 HCS 币种ID(currency-id-mapping,§9-U3) +param.setFdCurrencyId(currencyFdId); +// 开票金额(含税):本次开票金额 invoiceAmount +param.setFdInvoiceAmount(application.getInvoiceAmount()); +// TODO 待确认:款项性质,默认 progress,字典值联调后配置(§9-U3) +param.setFdFundNature(hcsProperties.getInvoice().getFundNatureDefault()); +``` + +§5 各场景的"字段映射"表即本规范的标注依据:表中"HCS 字段 / TMS 来源 / 备注"三列直接翻译成上述逐字段注释,一一对应,不得遗漏或凭空造字段。 + +--- + +## 4. 数据模型变更 + +SQL 脚本落 `tms-api/doc/sql/transport/`,命名照既有惯例 `blade_xxx_hcs_yyyymmdd.sql`。所有业务表统一追加的集成字段组: + +```sql +hcs_fd_id varchar(64) COMMENT '合规系统单据ID(fdId/fdContractId)', +hcs_sync_status varchar(16) DEFAULT 'unsynced' COMMENT '同步状态 unsynced/synced/failed', +hcs_retry_count int DEFAULT 0 COMMENT '推送失败重试次数', +hcs_sync_time datetime COMMENT '最近同步时间', +hcs_sync_msg varchar(512) COMMENT '最近同步结果信息/失败原因' +``` + +| 表 | 变更 | 用途 | +|---|---|---| +| `blade_project_apply` | +统一字段组 | C102 回填 fdId、状态 | +| `blade_contract_manage` | +统一字段组、`hcs_exeplan_id varchar(64)`、`hcs_risk_level varchar(8)`、`hcs_black_status varchar(8)`、`hcs_risk_time datetime` | C103 回填、履约计划ID、风险留痕 | +| `blade_payment_application` | +统一字段组、特批字段组:`hcs_credit_status varchar(16)`(pass/over)、`hcs_credit_msg varchar(512)`、`hcs_credit_time datetime`、`hcs_spec_fd_id varchar(64)`、`hcs_spec_status varchar(16)`(none/need/pushing/processing/approved/rejected) | C106-1 结果、C106-3 流程ID 与状态 | +| `blade_payment_application` | +履约记录字段:`hcs_perf_fd_id varchar(64)` | C108-1 返回 fdId | +| `blade_invoice_application` | +统一字段组 | C111 回填 | +| `blade_invoice_receipt` | +统一字段组、`hcs_contract_id bigint`、`hcs_contract_no varchar(64)`(人工补录兜底) | C109 回填、合同补录 | +| **`blade_contract_exe_stage`(新建)** | 见 §4.1 | 履约规则 | +| **`blade_hcs_check_log`(新建)** | id、biz_type、biz_id、check_type(risk/credit)、result、msg、trace_id、create_time | 风险/额度校验留痕(照 ops 日志惯例) | + +### 4.1 履约规则表 `blade_contract_exe_stage`(D10) + +```sql +CREATE TABLE blade_contract_exe_stage ( + id bigint PRIMARY KEY, + contract_id bigint NOT NULL COMMENT '合同ID(blade_contract_manage.id)', + perform_type varchar(16) NOT NULL COMMENT '履约类型 payment=付款/collection=收款', + fund_nature varchar(16) COMMENT '款项性质 prepayment/progress/acceptance/retention', + fund_amount decimal(18,2) COMMENT '计划金额(元)', + fund_date datetime COMMENT '计划资金日期', + invoice_rule varchar(16) COMMENT '开票规则(如 payFirst)', + invoice_cycle int COMMENT '账期', + fund_type varchar(16) DEFAULT 'byAmount' COMMENT '金额类型', + is_finish tinyint DEFAULT 0 COMMENT '是否完成', + row_op varchar(8) DEFAULT 'none' COMMENT '行级同步操作 none/add/update/delete', + hcs_stage_fd_id varchar(64) COMMENT '合规阶段ID(C103-9 返回,update/delete 必用)', + hcs_sync_status varchar(16) DEFAULT 'unsynced', + hcs_sync_msg varchar(512), + tenant_id varchar(12), create_user bigint, create_time datetime, + update_user bigint, update_time datetime, is_deleted tinyint DEFAULT 0 +); +``` + +维护入口:合同新建/变更表单的"履约规则"页签。合同审批通过置 `row_op=add`;后续编辑按行差异置 add/update/delete,由扫描任务随合同链路调 C103-9。 + +--- + +## 5. 场景设计 + +> 本节各"字段映射"表是 §3.4 标注规范的依据:Support 组装 DTO 时逐字段照表标注,字段中文名取自《桂物合同集成接口逻辑梳理.md》。 + +### 5.0 推送引擎(全部场景共用,D9) + +```mermaid +flowchart LR + A[业务操作\n提交/审批/变更/付款推进] -->|事务内| B[置 hcs_sync_status=unsynced\n(+特批/履约等业务标记)] + B --> C{HcsPushTask\n@Scheduled cron 可配} + C -->|扫 unsynced & failed(retry<max)| D[Support 判重查询] + D -->|已存在| E[回填 hcs_fd_id → synced] + D -->|不存在| F[调 HCS 写接口] + F -->|success| E + F -->|失败| G[failed + retry_count+1 + msg] + H[页面 手动推送/重推] --> F +``` + +- **审批零埋点**:`approve()` 与 `MkProcessBizHandlers.approveFromProcess` 只置状态;两审批入口(/approve 与 MK 回调)与未来新入口天然全覆盖。付款申请/开票/收票目前未注册 MK 处理器,**由其他团队补齐,不在本设计范围**——新处理器只要遵循既有约定置 `approvalStatus=approved`,HCS 扫描即自动覆盖,本设计无需任何配套改造。 +- **任务顺序**:项目 → 合同(内含:风险校验→附件转传→C103-1→履约规则 C103-9)→ 付款特批/履约记录 → 开票登记 → 收票单。每类批量 `push.batch-size`(默认 50)。 +- **多实例部署**:任务体加 Redis 分布式锁(照既有 BladeRedis 用法);若维持单实例部署则与既有金蝶任务一致。 +- **手动入口**:`HcsSyncController` 提供 `POST /hcs/sync/{bizType}/{id}`(单条重推,重置 unsynced)与批量端点,前端列表页加"推送合规/重推"按钮(照"同步金蝶"按钮模式)。 + +### 5.1 项目立项(C102-1/2/3 ← ProjectApply) + +**触发与链路**:审批通过(approve / MK 回调 `project-apply` 处理器)→ `unsynced`;变更审批通过(change_approved)→ 走 C102-2 更新。推送前判重:C102-3 `conditions={"fd_num": projectCode}`,命中则直接回填 `fdId` 置 synced(跳过新建)。 + +**字段映射**(dynamicProps): + +| HCS 字段 | TMS 来源(ProjectApply) | 备注 | +|---|---|---| +| fd_pro_name | projectName | | +| fd_pro_simple_name | projectShortName | | +| fd_num | projectCode | | +| fd_creator_unit | businessDeptName → `{fdName}` | ⚠️ HCS 组织 fdId 无法映射,先传名称(见 §9-U2) | +| fd_head | principalUserId → 用户登录名 `{fdLoginName}` | | +| fd_taker_dept | undertakeDeptName → `{fdName}` | 同上 | +| fd_taker | handlerUserName 对应用户 `{fdLoginName}` | | +| fd_pay_limit | fundLimit × 10000 | TMS 万元 → HCS 元 | +| fd_out_invoice_limit | receivableLimit × 10000 | 同上 | +| fd_pro_content | situationRemark | | +| fd_is_available | true | 固定 | +| fd_avail_units | [{fdName: businessDeptName}] | 同 fd_creator_unit | +| fd_settlement_type | settlementMode | ⚠️ 字典映射待联调(§9-U3) | +| fd_pro_plan_deposit | fundDemand × 10000 | ⚠️ 变更映射曾名"履约保证金",语义联调确认 | +| fd_is_self_pro / fd_pro_income_goal | 无直接对应 | 一期默认 "1" / 不传,联调确认 | +| fd_kingdee_sync_status | "1" | | +| fd_sources / fd_kingdee_id | "TMS" / ProjectApply.id | D14 | +| fd_creator | 当前操作人 `{fdLoginName}` | | + +顶层:`bpmOperation.templateCode` ← 配置 `thirdParty.hcs.project.template-code`(环境相关值,§9-U9);`saveOption.saveDraft=false`。**出参**:`data.fdId` → `hcs_fd_id`。 + +### 5.2 合同发起/更新(C103-1/11 ← ContractManage)+ 附件 + 履约规则 + +**触发与链路**:合同审批通过(含变更单 change_approved)→ `unsynced`。扫描任务按序执行: +1. **风险校验**(可配开关):C101-1 查甲方/乙方客商风险,结果写 `blade_hcs_check_log` + 合同 `hcs_risk_level/hcs_black_status`;黑名单且 `risk.block-blacklist=true` 时该单置 failed、msg 提示"客商黑名单,禁止推送"。 +2. **判重**:C103-3 `conditions={"fdNumber": contractNo}`(HCS 条件能力联调确认,§9-U4),命中回填跳过。 +3. **C103-1 起草**:成功回填 `data.fdContractId → hcs_fd_id`。 +4. **履约规则 C103-9**(§5.3)。 +5. 变更单(change_approved)→ C103-11 `updateDraft`,入参同发起;⚠️ HCS 侧如何定位已有合同 v4 未说明(§9-U5)。 + +**xformFields 字段映射**: + +| name | TMS 来源(ContractManage) | 备注 | +|---|---|---| +| fdNumber / CONTRACT_NO | contractNo | | +| fdSubject / CONTRACT_NAME | contractName | | +| fdAmount / AMOUNT | contractAmount | 字符串传值 | +| fdCurrencyId / CURRENCY | settlementCurrency → "人民币" | 配置 `currency-name-mapping: {"RMB":"人民币"}`(照金蝶 RMB→CNY 惯例) | +| fdSettlementType | settlementMode | ⚠️ 映射到"付款/收款"待联调(§9-U3) | +| fdSepcailContract | "false" | D15,配置项预留 | +| CONTRACT_TYPE | contractCategory | | +| PARTY_A / PARTY_B | partyA / partyB | TMS 存名称字符串 | +| SIGN_DATE | signDate | fdType=timestamp | +| fdEstimateStartTime / fdEstimateEndTime | startDate / endDate | fdType=timestamp | +| CREATE_TIME / fdCreateTime | createTime | fdType=timestamp | +| fd_syn_time | 推送时刻 | fdType=timestamp | +| CREATE_USER_NAME | handlerUserName(承办人) | | +| CONTRACT_STATUS | — | ⚠️ 无对应,联调确认是否必传(§9-U3) | + +**signer[](相对方)**:`{fdStanding:"甲", fdName:partyA, fdNumber:←按名称反查 CustomerArchive 编码}`、乙方同理。⚠️ TMS 合同只存甲乙方名称,编号反查不到时留空;`fdType`(inner/外部)判定规则联调确认(§9-U6)。 + +**顶层**:`fdTemplateId` ← `template-mapping[contractCategory]`(Nacos,需合规方提供模板ID清单,§9-U7);`fdOuterSystem` ← src-system;`fdLoginName` ← handlerUser 登录名;`saveType=submit`。 + +**合同附件**:⚠️ v4 的 C103-1 入参未定义附件字段——合同附件向 HCS 的传递方式**待合规方确认**(§9-U8);本设计先按 `HcsAttachmentSupport` 通用转传能力建设(合同主文件 `contractFileJson` 中 approved=true 的文件 + `attachmentsJson`),确认后按其要求挂载。 + +### 5.3 履约规则同步(C103-9新 ← blade_contract_exe_stage) + +- 数据源与表结构见 §4.1(ADR-0002)。 +- **行级同步算法**:扫描任务对 `hcs_sync_status=unsynced` 的合同聚合其规则行:`row_op=add` 的行入 fdStages(不带 fdId);`update/delete` 行必须带 `hcs_stage_fd_id`。整体 `fdEopExeplanOperateType=add`(或 update,随场景)。顶层 `fdContractId` 传 **HCS 合同ID(hcs_fd_id)**。 +- **回填**:`data.fdExeplanId` → `blade_contract_manage.hcs_exeplan_id`;`data.fdChangeStages[].fdId` 按行回填 `hcs_stage_fd_id`。**合规返回的 fdId 必须持久化**——后续行更新/删除全靠它。 +- fdStages 行字段:fdPerformType、fdFundNature、fdFundAmount(元)、fdFundDate(毫秒)、fdInvoiceRule、fdInvoiceCycle、fdFundType(默认 byAmount)、fdIsFinish、fdExtendContent="{}"。 + +### 5.4 客商风险 + 额度校验(C101-1 / C106-1 ← PaymentApplication 提交时) + +付款申请**提交(submit)事务内同步调用**(查询类同步,D15/R2-Q3): +1. **C101-1**:`fdNumber` ← 收款方客商编号(按 payeeName 反查 CustomerArchive;编号体系联调确认 §9-U6)。结果写 `blade_hcs_check_log`;黑名单且 `risk.block-blacklist=true` → 阻断提交。 +2. **C106-1**:`{fdContractId: 合同.hcs_fd_id, fdApplyAmount: appliedAmount}`。`fdIsCredit=true` → `hcs_credit_status=pass` 正常提交;`false` → `hcs_credit_status=over` + `hcs_credit_msg=fdMessage`,**不拦截提交**,标记 `hcs_spec_status=need`(走特批链路,D15/R2-Q2)。 + +> 校验依赖合同已推送(hcs_fd_id 存在);合同未推送时按 `credit.require-contract-synced` 配置决定阻断或跳过校验。 + +### 5.5 结算付款特批(C106-3/4 ← PaymentApplication) + +**触发**:审批通过且 `hcs_spec_status=need` → 扫描任务发起 C106-3;返回 `data.data.fdId`(双层嵌套)→ `hcs_spec_fd_id`,状态置 `processing`(特批中)。 + +**dynamicProps 映射**: + +| HCS 字段 | TMS 来源 | 备注 | +|---|---|---| +| fd_contract_name | ContractManage.hcs_fd_id | ⚠️ 传**合规合同ID**,非名称 | +| fd_contract_no | contractNo | | +| fd_doc_subject | "结算付款特批-" + paymentNo | | +| fd_doc_no / fd_id | paymentNo | 来源付款单标识 | +| fd_pay_amount | appliedAmount | | +| fd_total_amount | settlementAmount | | +| fd_payer / fd_payee | payerName / payeeName | | +| fd_receive_account_name / fd_receive_account / fd_bank_name | receiptAccountName / bankAccount / bankName | | +| fd_settle_currency | "人民币"(映射) | | +| fd_payment_purpose / fd_payment_nature / fd_payment_type | 配置映射(示例 2001 / 1 / 1) | 字典值联调确认(§9-U3) | +| fd_reason / fd_supplement_note | remark | | +| fd_doc_subject / fd_doc_status | 表单层主题 / 配置 "10" | | +| fd_spc_approval_attach | 固定 "fd_spc_approval_attach" | 特批附件标识 | + +`mechanisms.attachment`:`attachmentsJson` 经 C103-2 转传,特批附件 `fdEntityKey=fd_spc_approval_attach` 且带 `fdBindType=ADD`。更新(C106-4):单据变更且特批流程存在时调用,顶层 `fdId=hcs_spec_fd_id`,附件不带 fdBindType。 + +**特批结果**:v4 无结果查询/回调接口 → `approved/rejected` 一期由页面人工确认(未决 §9-U1)。 + +### 5.6 履约记录(C108-1/2 ← PaymentApplication,D11) + +- **新增**:付款申请审批通过 → 随推送链路调 C108-1:`fd_apply_amount`=appliedAmount、`fd_plan_date`=applyDate(毫秒)、`fd_paln_type`=paymentType、`fd_property`=款项性质(取关联履约规则行/结算性质)、`fd_id`=关联履约阶段 `hcs_stage_fd_id`(无关联则不传)、`fd_contract_id`=合同ID、`fd_xform_id` ← 配置(环境值)。附件经转传 `fdEntityKey=fd_plan_att`。返回 `data.fdId → hcs_perf_fd_id`。 +- **更新**:`paidAmount` 变化/付清 → C108-2:`formData.fdId=hcs_perf_fd_id` 必填,传 `fd_fact_amount`(实际金额)、`fd_contract_id` 等;响应无 data,success 即成功。 + +### 5.7 开票登记(C111-1/2/3 ← InvoiceApplication,D12) + +- **新增**:审批通过 → 扫描推 C111-2;**更新**:金蝶开票完成(`kingdeeStatus=invoiced`,由既有 PaymentKingdeeResultTask 开票回写时置"待更新")→ 扫描推 C111-3 回填 `fdBillDate`/`fdStatus`。 +- **映射**:fdNumber←applicationNo;fdRegisterDate←applicationDate(毫秒);fdInvoiceAmount←invoiceAmount(含税);fdInvoiceParty←issuerName(销方);fdInvoiceType←invoiceType 字典映射(electronic_normal/electronic_special,§9-U3);fdCurrencyId←RMB→币种fdId(启动时经 C103-12 缓存币种表,配置 `currency-id-mapping`);fdRemark←remark;fdThirdCreatorCode/DeptCode←申请人工号/部门编码;fdStatus=0;fdAttIds←附件转传。 +- ⚠️ **fdContractNumber 缺口**:InvoiceApplication 无合同字段,需经应收结算链路回溯(具体关联字段开发时确认,§9-U10)。 +- 判重:C111-1 `conditions={"fdNumber": applicationNo}`(联调确认)。 + +### 5.8 收票单(C109-1/2 ← InvoiceReceipt,D13) + +- **触发**:审批通过 → C109-1;票据变更/作废 → C109-2(顶层 `fdId=hcs_fd_id` 必填,只传变更字段,不带文档状态)。 +- **映射**:fd_invoice_code←invoiceNo;fd_bill_date←invoiceDate(`YYYY-MM-DD`);fd_invoicer←issuerName(销方);fd_buyer←receiverName(购方);fd_invoice_amt_tax_incl←invoiceAmount;fd_tax_rate←taxRate÷100(13→0.13);fd_invoice_type←字典映射(§9-U3);fd_remark←remark;fd_contract_subject/fd_contract_no←**应付结算链路回溯**(收票→应付结算 FormalSettlement.contractId/No),回溯不到→页面补录 `hcs_contract_id/hcs_contract_no`;fd_ap_bill_src_subject←收票认领应付单号(键联调确认 §9-U11);附件转传 `fdEntityKey=fd_attach`、`fdBindType=ADD`。 +- 返回 `data.data.fdId → hcs_fd_id`(双层嵌套)。 + +### 5.9 主数据接口(C103-6/7/12)与查询(C103-3/4) + +- **启动/首次使用时拉取并缓存**(Redis,照 BFI token 缓存惯例,TTL 可配):模板列表(供 template-mapping 校验)、合同分类树、币种表(fdId 映射)。提供管理端"刷新缓存"端点。 +- **C103-3/C103-4**:判重与对账回查(按 fdNumber/fdId);C103-4 的 data 结构 v4 未定义,对账功能联调后补充。 + +--- + +## 6. 附件转传设计(HcsAttachmentSupport,D 补充 R2-Q5) + +1. 输入:单据 `attachmentsJson`/`contractFileJson`(JSON 元素含 url/fileType/approved 等,去重键照 `attachmentKey` 惯例 url|link|fileUrl|downloadUrl|uid|originalName)。 +2. 下载:按元数据 URL 从文件服务拉取流(文件服务基址可配 `attachment.file-download-base`)。 +3. 上传:C103-2 multipart(fdFile、fdAnonymous=false、fdLoginName=操作人)→ 附件 `fdId`。 +4. 映射缓存:Redis `hcs:att:{attachmentKey}` → 合规 fdId(TTL 7d),未命中重传(重复上传仅浪费存储,无业务风险,故不做持久化映射表)。 +5. 任一附件转传失败 → 整单推送失败进补偿重试。 + +--- + +## 7. 配置项清单(Nacos `third-party-api.yaml` → `thirdParty.hcs.*`) + +```yaml +thirdParty: + hcs: + base-url: http://172.16.203.134:8000/gwzh/HTHG # 网关前缀,直连/iPaaS 部署时改此处 + authorization: ${HCS_AUTHORIZATION:} # Authorization 头整值(含 Basic 前缀) + key-auth: ${HCS_KEY_AUTH:} # Key-Auth 头整值 + src-system: TMS # fd_sources + push: + sync-enabled: false # 总开关(默认关,灰度打开) + cron: "0 */5 * * * ?" + batch-size: 50 + max-retry: 5 + project: + template-code: "" # bpmOperation.templateCode(环境值) + contract: + template-mapping: {} # {TMS合同类别: HCS模板ID} + settlement-type-mapping: {} # {TMS结算方式: 付款|收款} + currency-name-mapping: {"RMB": "人民币"} + special-contract-enabled: false + require-risk-check: true + exe-stage: + fund-type: byAmount + risk: + check-on-contract: true + check-on-payment: true + block-blacklist: true + credit: + require-contract-synced: true + spec-pay: + doc-status: "10" + payment-purpose: "" # 字典值联调后配置 + payment-nature: "" + payment-type: "" + invoice: + invoice-type-mapping: {"electronic_normal": "", "electronic_special": ""} + currency-id-mapping: {"RMB": ""} # {TMS币种码: HCS币种fdId} + fund-nature-default: progress + receipt-bill: + invoice-type-mapping: {} + attachment: + transfer-enabled: true + file-download-base: "" +``` + +--- + +## 8. 实施拆分(建议排期) + +| 阶段 | 内容 | 依赖 | +|---|---|---| +| P0 基础 | blade-hcs-api 骨架:Feign/拦截器/认证头/DTO(24 接口全量 DTO)/分页工具;Nacos 配置段;统一字段组 SQL | 合规方提供测试环境地址与凭据 | +| P1 立项与合同 | ProjectApply/ContractManage 字段+Support+扫描任务+手动端点;C102-3/C103-3 判重;C103-6/7/12 缓存 | P0;模板ID清单(§9-U7) | +| P2 履约规则 | blade_contract_exe_stage 表+表单维护+C103-9 行级同步 | P1(合同先推送) | +| P3 付款链 | C106-1/C101-1 提交校验+check_log;特批字段组+C106-3/4;C108-1/2 | P1(合同 fdId) | +| P4 开票与收票 | C111-1/2/3(含金蝶回写联动);C109-1/2(含合同回溯/补录) | P0;开票/收票关联字段确认 | +| P5 运维收尾 | 对账查询页、失败重推批量、监控埋点(traceId 落日志)、多实例锁 | 全部 | + +**全部阶段通用**:Support 组装 HCS 请求 DTO 时按 §3.4 规范逐字段标注外部字段中文名与 TMS 取值来源(照 `pushArBill` 惯例),代码评审以此为一票否决项。 + +--- + +## 9. 未决事项(需合规方/联调确认) + +| # | 事项 | 影响 | +|---|---|---| +| U1 | **特批流程结果回传方式**:v4 无查询/回调接口 | 特批 approved/rejected 一期人工确认 | +| U2 | 组织/人员引用体系:HCS `{fdId,fdName}` 的 fdId 与 TMS 部门ID 不同源;登录名是否同源(见原文登录名截图) | 立项/合同操作人字段解析方式 | +| U3 | 字典值映射:fd_settlement_type、fd_invoice_type、付款用途/性质/类型、CONTRACT_STATUS 是否必传 | 各映射配置 | +| U4 | C103-3/C102-3/C111-1 conditions 是否支持 fdNumber/fd_num/fdKingdeeId 精确查询;HCS 是否按 fd_kingdee_id 幂等 | 判重与防重方案 | +| U5 | C103-11 updateDraft 如何定位已有合同 | 合同更新链路 | +| U6 | signer 相对方编号体系与 fdType(inner/外部)判定;C101-1 的 fdNumber 用客商哪个编码 | 合同签署方、风险校验 | +| U7 | 合规模板ID清单(template-mapping 数据源) | 合同推送 | +| U8 | **合同附件向 HCS 的传递方式**(C103-1 未定义附件字段) | 附件转传挂载点 | +| U9 | 立项 bpmOperation.templateCode 环境值;C108 fd_xform_id 环境值 | 立项/履约记录推送 | +| U10 | 开票申请→合同/应收结算的关联字段确认 | C111 fdContractNumber | +| U11 | 收票 fd_ap_bill_src_subject 关联键(应付单号体系) | C109 | +| U12 | C104/C107 收款流水与认领的推送方及链路 | 范围外备忘(ADR-0003) | diff --git a/doc/docs/hcs合同/2026-09-28-HCS接入实施状态与确认清单.md b/doc/docs/hcs合同/2026-09-28-HCS接入实施状态与确认清单.md index 570f222a..131f400d 100644 --- a/doc/docs/hcs合同/2026-09-28-HCS接入实施状态与确认清单.md +++ b/doc/docs/hcs合同/2026-09-28-HCS接入实施状态与确认清单.md @@ -15,9 +15,8 @@ | 组件 | 内容 | 状态 | |---|---|---| -| `feign/IHcsClient` | `@FeignClient(name="HCS", url="${thirdParty.hcs.baseUrl}")`,**24 个业务接口端点全部建成**(C101-1、C102-1/2/3、C103-1/2/3/4/5/6/7/9/11/12、C106-1/3/4、C108-1/2、C109-1/2、C111-1/2/3)+ OAuth2 getToken;URI 均可被 `thirdParty.hcs.*Url` 覆盖 | ✅ | -| `interceptor/HcsAuthInterceptor` | oauth2(URL 追加 access_token)/ basic(Authorization 头)双模式并存,切换只改配置;取令牌请求有路径+空令牌双重守卫 | ✅ | -| `token/HcsTokenService` | getToken → Redis(`blade:third:hcs:token`,120s 过期缓冲),`refreshAccessToken()` 供 401 强刷重放 | ✅ | +| `feign/IHcsClient` | `@FeignClient(name="HCS", url="${thirdParty.hcs.baseUrl}")`,**24 个业务接口端点全部建成**(C101-1、C102-1/2/3、C103-1/2/3/4/5/6/7/9/11/12、C106-1/3/4、C108-1/2、C109-1/2、C111-1/2/3);URI 均可被 `thirdParty.hcs.*Url` 覆盖 | ✅ | +| `interceptor/HcsAuthInterceptor` | 所有请求注入 `Authorization`(整值可配)+ `Key-Auth` 两个静态认证头(v4 接口说明,2026-10-01 变更;原 oauth2/getToken 与 basic 双模式已删除) | ✅ | | `config/HcsProperties` | `third-party.hcs.*` 全量配置(§7 清单 + master-data.ttl-minutes + perf-record.xform-id 两个落实性补充),含默认值 | ✅ | | `config/HcsFeignClientConfig` | connect 10s / read 60s,空拦截器覆盖全局,**无 Retryer**(D7) | ✅ | | `dto/`(49 个文件) | 24 接口全量请求/响应 DTO + `HcsResult`/`HcsPageVO`/引用对象等公共结构;字段按《桂物合同集成接口逻辑梳理》核对,双层嵌套(C106-3/4、C109-1/2)以 `HcsResult>` 承接 | ✅ | @@ -188,5 +187,5 @@ | `HcsInvoiceRegSyncSupport#requireContractNumber` | 应收结算回溯口径(§9-U10) | | `HcsInvoiceRegSyncSupport#latestInvoiceDate` | 票据日期取值口径(发票日期 vs 回写时间) | | `HcsReceiptBillSyncSupport#buildSaveParam` | fd_ap_bill_src_subject(§9-U11);作废推送缺接口依据 | -| `HcsTokenVO` / `HcsTokenService#cacheToken` | getToken 响应字段与 expires_in 单位(v4 未给出示例) | +| `HcsAuthInterceptor` | Authorization/Key-Auth 头对全部接口(含 C103-2 附件上传/下载)是否同样生效;网关密钥轮换时仅改 Nacos 配置 | | `HcsReconSupport#reconContractDetail` | C103-4 出参结构 | diff --git a/doc/nacos/third-party-api.yaml b/doc/nacos/third-party-api.yaml index d25cd9ad..d9736a3c 100644 --- a/doc/nacos/third-party-api.yaml +++ b/doc/nacos/third-party-api.yaml @@ -65,17 +65,12 @@ thirdParty: # 调度 cron,默认每10分钟 cron: ${BFI_PAY_RESULT_CRON:0 */10 * * * ?} hcs: - # 合同合规系统(HCS)开放接口地址,直连可配(网关/iPaaS 部署时改此处,代码不感知) - base-url: ${HCS_BASE_URL:http://127.0.0.1:8050} - # 认证方式:oauth2(默认,URL 追加 access_token)| basic(Authorization 请求头),切换不改代码 - auth-type: ${HCS_AUTH_TYPE:oauth2} - # OAuth2 应用 appKey - app-key: ${HCS_APP_KEY:} - # OAuth2 应用 appSecret,敏感值通过环境变量注入 - app-secret: ${HCS_APP_SECRET:} - # Basic 认证用户名/密码(auth-type=basic 时生效) - basic-username: ${HCS_BASIC_USER:} - basic-password: ${HCS_BASIC_PASSWORD:} + # 合同合规系统(HCS)开放接口地址(v4 接口说明:带网关前缀,直连可配,代码不感知) + base-url: ${HCS_BASE_URL:http://172.16.203.134:8000/gwzh/HTHG} + # Authorization 请求头整值(含 Basic 前缀,敏感值通过环境变量注入) + authorization: ${HCS_AUTHORIZATION:} + # Key-Auth 请求头值(v4 接口说明:所有接口固定携带 Authorization + Key-Auth 两个头) + key-auth: ${HCS_KEY_AUTH:} # 来源系统标识(fd_sources,约定值 TMS) src-system: ${HCS_SRC_SYSTEM:TMS} # 推送任务(扫描首推/补偿,P1 接线)