From 6f774d50c7cfd211ad672d1c78df155252e82e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Mon, 12 Oct 2026 11:18:35 +0800 Subject: [PATCH] =?UTF-8?q?:docs:=20=E6=9B=B4=E6=96=B0HCS=E7=89=B9?= =?UTF-8?q?=E6=89=B9=E7=BB=93=E6=9E=9C=E5=9B=9E=E4=BC=A0=E6=9C=BA=E5=88=B6?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...026-09-27-桂物合同合规系统HCS接入技术设计.md | 6 +- .../2026-09-28-HCS接入实施状态与确认清单.md | 4 +- .../2026-10-09-项目立项与合同HCS前端接入设计.md | 26 +- .../hcs合同/2026-10-11-hcs合同推送流程梳理.md | 19 +- ...2026-10-12-合同特批与结算付款特批流程梳理.md | 272 ++++++++++++++++++ 5 files changed, 305 insertions(+), 22 deletions(-) create mode 100644 doc/docs/hcs合同/2026-10-12-合同特批与结算付款特批流程梳理.md diff --git a/doc/docs/hcs合同/2026-09-27-桂物合同合规系统HCS接入技术设计.md b/doc/docs/hcs合同/2026-09-27-桂物合同合规系统HCS接入技术设计.md index db524d0b..dde633b5 100644 --- a/doc/docs/hcs合同/2026-09-27-桂物合同合规系统HCS接入技术设计.md +++ b/doc/docs/hcs合同/2026-09-27-桂物合同合规系统HCS接入技术设计.md @@ -27,7 +27,7 @@ | D12 | 开票登记时机 | 审批通过即推 C111-2(票据日期空);金蝶开票完成后 C111-3 回填 | | D13 | 收票合同关联 | 应付结算链路自动回溯;回溯不到收票表单加合同字段人工补录 | | D14 | 来源标识 | `fd_sources="WLTMS"`(Nacos `src-system` 可配);`fd_kingdee_id`=TMS 业务单据主键 | -| D15 | 特批载体 | 付款申请表加 `hcs_credit_*`/`hcs_spec_*` 字段组;C106-1 提交时同步;超额转 C106-3;**特批结果回传方式未决**(过渡:页面人工确认);合同 `fdSepcailContract` 一期固定 false | +| D15 | 特批载体 | 付款申请表加 `hcs_credit_*`/`hcs_spec_*` 字段组;C106-1 提交时同步;超额转 C106-3;~~特批结果回传方式未决~~ **已决(2026-10-12):合规经 contractLegal/paymentLegal result 接口推送 TMS**;合同 `fdSepcailContract` 一期固定 false | --- @@ -306,7 +306,7 @@ flowchart LR `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)。 +**特批结果**:v4 无结果查询/回调接口 → 一期由页面人工确认;**2026-10-12 已决**:合规审批完成后经 `POST /hcs/paymentLegal/result` 主动推送 TMS(`requestId`=付款申请ID,`status=APPROVED/REJECTED`),人工确认保留等效兜底(§9-U1 闭环)。 ### 5.6 履约记录(C108-1/2 ← PaymentApplication,D11) @@ -415,7 +415,7 @@ thirdParty: | # | 事项 | 影响 | |---|---|---| -| U1 | **特批流程结果回传方式**:v4 无查询/回调接口 | 特批 approved/rejected 一期人工确认 | +| U1 | **特批流程结果回传方式**:v4 无查询/回调接口 → **已决(2026-10-12)**:合规经 `contractLegal/result`(合同)/`paymentLegal/result`(付款)主动推送 TMS | 推送接收端点已实现(PERMIT_ALL);人工确认保留等效兜底 | | 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 幂等 | 判重与防重方案 | diff --git a/doc/docs/hcs合同/2026-09-28-HCS接入实施状态与确认清单.md b/doc/docs/hcs合同/2026-09-28-HCS接入实施状态与确认清单.md index ed57b841..31285bef 100644 --- a/doc/docs/hcs合同/2026-09-28-HCS接入实施状态与确认清单.md +++ b/doc/docs/hcs合同/2026-09-28-HCS接入实施状态与确认清单.md @@ -62,6 +62,8 @@ | `POST /hcs/sync/{bizType}/{id}` | 单条重推(bizType:project / contract / payment / invoice-application / invoice-receipt),重置 unsynced+清零计数后立即推送 | | `POST /hcs/sync/{bizType}` | 批量推送一轮(复用扫描逻辑) | | `POST /hcs/spec-pay/confirm?id=&result=approved|rejected` | 特批结果人工确认(仅 processing 可确认) | +| `POST /hcs/contractLegal/result` | 合同特批结果回传接收(合规推送,PERMIT_ALL,2026-10-12 替代 B103) | +| `POST /hcs/paymentLegal/result` | 付款特批结果回传接收(合规推送,PERMIT_ALL) | | `POST /hcs/master-data/refresh` | 刷新主数据缓存并校验模板映射 | | `GET /hcs/recon/project?projectCode=` | 项目立项对账(C102-3) | | `GET /hcs/recon/contract?contractNo=` | 合同对账(C103-3) | @@ -126,7 +128,7 @@ | # | 事项 | 当前代码/配置占位 | |---|---|---| -| U1 | 特批流程结果回传方式 | 人工确认端点 `POST /hcs/spec-pay/confirm`(过渡方案);若有回调/查询接口需改造 | +| U1 | ~~特批流程结果回传方式~~ **已决(2026-10-12)**:合规经 `POST /hcs/contractLegal/result`、`POST /hcs/paymentLegal/result` 主动推送结果(报文 `{sourceSystem, requestId, status=APPROVED/REJECTED, reason}`) | 人工确认端点保留作等效兜底;原 B103 推测性回调端点 `/hcs/callback/spec-result` 已删除 | | U2 | 组织/人员 fdId 体系与登录名同源性 | 引用一律先传名称或登录名(经办人/创建人经 UserCache 解析 account) | | U3 | 字典值映射:fd_settlement_type、fd_invoice_type、付款用途/性质/类型、CONTRACT_STATUS 是否必传、fdBlackStatus 取值(示例 no) | Nacos 各 mapping 空占位;未配置时该字段不传并 warn(黑名单判定按 "yes" 等值,联调校准);CONTRACT_STATUS 一期不传 | | U4 | 判重 conditions 是否支持 fd_num/fdNumber 精确查询;HCS 是否按 fd_kingdee_id 幂等 | 按文档 conditions 精确匹配实现,联调验证;判重查询 C102-3 额外携带 curUser(文档示例如此) | diff --git a/doc/docs/hcs合同/2026-10-09-项目立项与合同HCS前端接入设计.md b/doc/docs/hcs合同/2026-10-09-项目立项与合同HCS前端接入设计.md index f166d009..b23a0d7a 100644 --- a/doc/docs/hcs合同/2026-10-09-项目立项与合同HCS前端接入设计.md +++ b/doc/docs/hcs合同/2026-10-09-项目立项与合同HCS前端接入设计.md @@ -35,7 +35,7 @@ | C103-3 合同列表查询 | `GET /hcs/recon/contract` 已有 | 已有 | 合同列表"合规对账"弹窗 | | C103-4 合同详情查询 | `GET /hcs/recon/contract/detail` 已有 | 已有 | 对账弹窗"查看合规详情" | | C103-5 合同附件下载 | 仅 Feign 端点 | **`GET /hcs/attachment/download`(新增)** | 对账弹窗/合同详情中下载 HCS 侧附件 | -| C103-8 合同发起特批 | **本期正式接入**(业务闭环见集成流程梳理:高风险客商签约必走;B103 结果回传) | **`POST /hcs/contract/spec-apply`(新增)+ `POST /hcs/callback/spec-result`(B103 接收,新增)** | 合同详情"发起特批"、特批状态展示、回传后自动恢复推送 | +| C103-8 合同发起特批 | **本期正式接入**(业务闭环见集成流程梳理:高风险客商签约必走;结果经 contractLegal/result 推送,2026-10-12 替代 B103) | **`POST /hcs/contract/spec-apply`(新增)+ `POST /hcs/contractLegal/result`(结果推送接收,新增)** | 合同详情"发起特批"、特批状态展示、结果推送后自动恢复展示 | --- @@ -77,7 +77,7 @@ GET /hcs/risk?customerCode=... > 前端仅用于**展示与提示**,不作为安全边界:强制校验仍在合同推送链路(`risk.block-blacklist`)与付款提交事务内。 -### 3.4 合同发起特批(C103-8)+ 结果回传(B103)——本期正式接入 +### 3.4 合同发起特批(C103-8)+ 结果推送接收(contractLegal/result)——本期正式接入 **业务闭环**(依据《TMS业财融合-集成流程图文字版与业务流程梳理.md》§3.3/§8): @@ -88,8 +88,8 @@ GET /hcs/risk?customerCode=... → TMS 内部特批审批(按原审批流) → 前端补特批申请材料 + 内部审批流程附件 → C103-8 发起特批(hcs_spec_status=processing) → 合同系统集团审批(流程在合同系统预配置) - → B103 特批结果回传 TMS(hcs_spec_status=approved/rejected) - → approved → 自动恢复 C103-1 推送 → 完成签订;rejected → 前端提示,重新发起 + → 合规推送特批结果 TMS:POST /hcs/contractLegal/result(hcs_spec_status=approved/rejected) + → approved → 恢复"审批通过"展示(C103-1 已起草,无需再推送)→ 完成签订;rejected → 前端提示,重新发起 ``` **数据模型**:`blade_contract_manage` 追加特批字段组(照付款申请 `hcs_spec_*` 惯例),SQL 落 `doc/sql/transport/`: @@ -112,12 +112,12 @@ POST /hcs/contract/spec-apply (body:{ contractId, attachments: [{fdId, → 返回 data.fdId → hcs_spec_fd_id,状态置 processing;失败置 need 并记 hcs_spec_msg → C103-8 v4 未含报文,联调前按上述预估实现并加 TODO 标注(§7-U1) -POST /hcs/callback/spec-result (B103 合规→TMS 回调接收端点) - 公开端点(@PreAuth(AuthConstant.PERMIT_ALL) + 报文验签字段待合规方口径,先记录原文留痕) - body:{ 合同标识/特批流程fdId, 审批结果, 审批意见 } ← 字段名待 B103 报文(§7-U1) - 处理:定位合同 → 回写 hcs_spec_status=approved/rejected + hcs_spec_msg - → approved 时把合同 hcs_sync_status 重置 unsynced,由既有扫描任务自动走 C103-1(零新增链路) - → B103 报文未到位前端点先落库留痕不置状态,联调时接线 +POST /hcs/contractLegal/result (合规系统推送特批结果,2026-10-12 替代未建设的 B103) + 公开端点(@PreAuth(AuthConstant.PERMIT_ALL)),iPaaS 网关注册映射 /gwzh/HTHG/contractLegal/result → 本端点 + body(HcsLegalResultDTO):{ sourceSystem="WLTMS", requestId=TMS合同ID, status=APPROVED|REJECTED, reason } + 处理:按 requestId 定位合同 → status 大小写不敏感识别 → 回写 hcs_spec_status + 原文(含 reason)留痕 blade_hcs_check_log + → approved 恢复 currentNode="审批通过"(C103-1 已起草,无需再推送);rejected 联动审批驳回,reason 随原文见 hcs_spec_msg + → 未定位到合同/状态未识别仅留痕返回,不报错 ``` **状态展示与操作权限**: @@ -230,7 +230,7 @@ export const applyContractSpec = data => - **入口**:合同详情页【发起特批】按钮,仅 `hcsSpecStatus ∈ {need, rejected}` 时可用;权限码 `hcs_spec_apply`。 - **交互**:弹窗选择/确认特批申请材料(先经 §4.5 `uploadAttachment` 取 fdId,弹窗内表格展示已传材料,含内部审批流程附件)→ 确认调 `applyContractSpec({ contractId, attachments })` → 成功后详情刷新为"特批中"。 - **状态展示**:合同列表与详情按 §3.4 状态表展示特批标签(need/processing/approved/rejected);`need` 时列表"推送合规"按钮禁用并 tooltip 提示。 -- **结果回传**:B103 回调由后端接收并自动恢复推送,前端无需轮询;详情页打开时实时拉取最新状态即可,`rejected` 时展示 `hcsSpecMsg` 驳回原因。 +- **结果推送**:合规推送(`/hcs/contractLegal/result`)由后端接收并自动联动状态,前端无需轮询;详情页打开时实时拉取最新状态即可,`rejected` 时展示 `hcsSpecMsg` 驳回原因。 --- @@ -241,7 +241,7 @@ export const applyContractSpec = data => | F1 基础 | `GET /hcs/master-data/template` + `@PreAuth`/菜单 SQL | `api/business/hcs.js`;管理端主数据页 | 无 | | F2 状态与推送 | 无(端点已有) | 两列表页:状态列/筛选 + 推送合规按钮 | F1(hcs.js) | | F3 对账与附件 | `/hcs/risk`、`/hcs/attachment/upload`、`/hcs/attachment/download` | 对账弹窗 + 合规附件下载 + 手动转传 + 附件行 `hcsFdId` | F2 | -| F4 特批 | 合同特批字段组 SQL;`POST /hcs/contract/spec-apply` + `POST /hcs/callback/spec-result`(B103);合同推送链路加 need 挂起判断 | 发起特批弹窗 + 特批状态标签 + 按钮联动 | C103-8/B103 报文(§7-U1,可先按预估模式实现联调替换) | +| F4 特批 | 合同特批字段组 SQL;`POST /hcs/contract/spec-apply` + `POST /hcs/contractLegal/result`(合规结果推送接收,2026-10-12 替代 B103);合同推送链路加 need 挂起判断 | 发起特批弹窗 + 特批状态标签 + 按钮联动 | C103-8 报文(§7-U1,可先按预估模式实现联调替换);结果推送报文已定(requestId/status/reason) | | F5 即时推送(2026-10-10 增补,纯后端) | `HcsImmediatePushSupport` + 4 处审批入口触发(§6.3)+ 开关配置 | 无 | 无(复用既有 Support,扫描兜底保留) | --- @@ -305,6 +305,6 @@ public void pushContractAfterCommit(Long id) // 合同 C103 | # | 事项 | 影响 | 当前处理 | |---|---|---|---| -| U1 | **C103-8 / B103 报文 v4 未提供**(业务闭环已在集成流程梳理中明确) | 特批发起与结果回传的报文字段 | 按 C106-3 模式预估实现 + 回调端点先落库留痕;联调拿到报文后替换(代码已留 TODO) | +| U1 | ~~C103-8 / B103 报文 v4 未提供~~ → **C103-8 报文仍待联调;结果回传已决(2026-10-12)**:B103 不建设,合规经 `contractLegal/result`/`paymentLegal/result` 推送结果(报文已定) | C103-8 发起报文字段 | 发起仍按 C106-3 模式预估(代码留 TODO);结果接收已按定稿报文实现(`HcsLegalResultDTO`) | | U2 | **C103-5 返回流是否带文件名**(v4 仅写"文件流") | 下载文件命名 | 后端以附件元数据/`fdId` 兜底命名,联调校准 | | U3 | 合规状态列/菜单权限是否需要按租户差异化 | 菜单 SQL | 先按统一菜单落地 | diff --git a/doc/docs/hcs合同/2026-10-11-hcs合同推送流程梳理.md b/doc/docs/hcs合同/2026-10-11-hcs合同推送流程梳理.md index c7cc11db..59c361d1 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 履约规则。 +> 对接接口:C101-1 风险校验、C103-2 附件上传、C103-3 合同判重、C103-1 合同发起、C103-11 合同更新、C103-8 特批、C103-9 履约规则;特批结果接收 `/hcs/contractLegal/result`(合规推送,替代未建设的 B103,见 §9.4)。 > "必填" 标注来源:代码注释中标注的 v4 接口文档要求(HCS 侧),以及 TMS 推送前强校验(缺失直接失败)。 --- @@ -155,7 +155,7 @@ | `hcs_spec_status` / `hcs_spec_time` / `hcs_spec_msg` | 特批状态(none/need/processing/approved/rejected)及留痕 | | `hcs_spec_fd_id` | 特批流程ID(C103-8 返回) | | `hcs_spec_files_json` | 特批申请材料JSON(含 C103-2 合规附件ID) | -| `current_node` | 挂起展示节点:自动特批后置"特批审核",B103 通过恢复"审批通过",驳回置"已驳回" | +| `current_node` | 挂起展示节点:自动特批后置"特批审核",合规推送特批通过恢复"审批通过",驳回置"已驳回" | 风险校验明细另写 `blade_hcs_check_log`(甲方/乙方各一条,含 traceId)。 @@ -201,11 +201,20 @@ TMS 审批通过(approved / change_approved) - 特批已通过(approved,单次有效)的合同推送/变更不重复发起特批; - C103-8 发起失败保持 need 仅留痕,人工经 `/hcs/contract/spec-apply`(详情页"发起特批"按钮)重发。 -### 9.4 特批结果联动(B103 回传 / 人工确认等效) +### 9.4 特批结果联动(合规推送 contractLegal/result / 人工确认等效) + +**结果接收机制(2026-10-12 变更)**:原计划的 B103 推送合规方未建设,改为合规系统审批完成后经 iPaaS 网关调用 TMS 接收回传结果: + +| 接口 | 定位方式 | 处理 | +| --- | --- | --- | +| `POST /hcs/contractLegal/result`(公开端点,网关注册映射 `/gwzh/HTHG/contractLegal/result`) | `requestId` = TMS 合同ID | 合同特批结果联动 | +| `POST /hcs/paymentLegal/result`(公开端点,网关注册映射 `/gwzh/HTHG/paymentLegal/result`) | `requestId` = TMS 付款申请ID | 付款特批回写 `hcs_spec_status`(不联动付款审批状态) | + +报文两接口共用(`HcsLegalResultDTO`):`{sourceSystem, requestId, status, reason}`;`status=APPROVED`(通过)/ `REJECTED`(驳回,reason 为驳回原因如"特批说明材料不完整,请补充"),大小写不敏感识别,其他值仅留痕不落状态。报文原文(含 reason)全量留痕 `blade_hcs_check_log`;未定位到单据或状态未识别时仅留痕返回,不报错。 | 特批结果 | 合同联动 | | --- | --- | | approved | `currentNode` 恢复"审批通过"(C103-1 已起草,hcs_sync_status 保持 synced,无需再推送) | -| rejected | `approvalStatus=rejected` + `currentNode="已驳回"`,走重新编辑 → 提交 → 审批 → 重新特批闭环(重新推送时 C103-11 更新后再次自动特批) | +| rejected | `approvalStatus=rejected` + `currentNode="已驳回"`,走重新编辑 → 提交 → 审批 → 重新特批闭环(重新推送时 C103-11 更新后再次自动特批),reason 随原文见 `hcs_spec_msg` | -> 缺口:v4 无特批结果主动查询接口(§9-U1),结果依赖 B103 回调(`POST /hcs/callback/spec-result`)或页面人工确认(`POST /hcs/contract/spec/confirm`),合规方提供查询能力后可增轮询兜底。 +> 等效兜底:页面人工确认(`POST /hcs/contract/spec/confirm`,合同)与(`POST /hcs/spec-pay/confirm`,付款)与合规推送等效,二者均以先到为准。原推测性接收端点 `POST /hcs/callback/spec-result`(B103 候选键解析)已删除。 diff --git a/doc/docs/hcs合同/2026-10-12-合同特批与结算付款特批流程梳理.md b/doc/docs/hcs合同/2026-10-12-合同特批与结算付款特批流程梳理.md new file mode 100644 index 00000000..9f2f67c5 --- /dev/null +++ b/doc/docs/hcs合同/2026-10-12-合同特批与结算付款特批流程梳理.md @@ -0,0 +1,272 @@ +# 合同特批与付款(结算付款)特批流程梳理 + +> 梳理日期:2026-10-12 +> 涉及模块:`blade-service/blade-transport`(业务编排/状态留痕)、`blade-third-party-api/blade-hcs-api`(Feign 客户端 + DTO + 配置) +> 关联设计文档:`doc/docs/hcs合同/2026-10-11-hcs合同推送流程梳理.md`(§九)、`2026-09-27-桂物合同合规系统HCS接入技术设计.md`(§5.4/§5.5) +> 关联提交:`8e6e263`(外部客商高风险黑名单管控与合同自动特批) +> +> **2026-10-12 变更**:原计划的 B103 推送合规方未建设,特批结果改为合规审批完成后经 iPaaS 主动推送 TMS:合同 `POST /hcs/contractLegal/result`、付款 `POST /hcs/paymentLegal/result`(报文 `{sourceSystem, requestId, status=APPROVED/REJECTED, reason}`);原推测性回调端点 `/hcs/callback/spec-result` 及 `HcsFieldConstant.SPEC_CB_*` 候选键解析已删除。见 §2.5/§4.4/§五。 + +--- + +## 一、总览:特批的业务含义 + +本文所述"特批"**不是 TMS 本地审批流**(本地审批走 `approvalStatus`/`currentNode`),而是**向集团合规系统 HCS 发起的特殊审批流程**:TMS 侧仅负责发起、留痕、挂起展示并接收结果,审批动作本身在 HCS 内完成。 + +### 1.1 触发条件(仅两类,与金额阈值、超权限无关) + +| 触发线 | HCS 接口 | 判定条件 | 触发的特批 | 作用对象 | +| --- | --- | --- | --- | --- | +| 外部客商高风险/黑名单 | C101-1 风险查询 | `fdRiskLevel=2`(高风险)或 `fdBlackStatus=yes`(黑名单) | 合同特批(C103-8 发起 / contractLegal/result 结果推送) | `ContractManage`(合同) | +| 合同额度超额 | C106-1 额度校验 | `fdIsCredit=false`(超额) | 结算付款特批(C106-3 发起 / C106-4 更新) | `PaymentApplication`(付款申请) | + +补充规则: + +- **内部组织客商不查**:`CustomerArchive.customerKind=internal` 默认无风险(`HcsSyncConstant.CUSTOMER_KIND_INTERNAL`)。 +- **甲/乙任一方命中即整单管控**(`HcsSyncConstant.java:151-176`)。 +- **付款链路中黑名单不是特批而是直接阻断**:`risk.block-blacklist=true`(默认)时提交付款申请直接抛异常,不走特批。 + +### 1.2 与普通审批的关系 + +特批挂在 TMS 审批**之后**(合同须先审批通过并成功推送 HCS 起草,拿到 `hcs_fd_id` 后才能发起特批)。特批期间 TMS 用 `hcs_spec_status ∈ {need, processing}` + `currentNode="特批审核"` 挂起展示,推送门禁跳过;特批通过即放行,驳回则联动本地审批驳回(仅合同链路)。 + +### 1.3 特批状态机(两条链路共用 `HcsSyncConstant.SPEC_STATUS_*`) + +``` +none(默认) ──触发──▶ need(挂起"特批审核")──发起成功──▶ processing(HCS 流程进行中)──结果──▶ approved / rejected + └─发起失败──▶ 回落 need(仅留痕,可人工重发) +``` + +- 合同特批 `approved` **单次有效**:再次推送时若已 approved 不重复发起。 +- 付款特批 `approved/rejected` **不联动付款审批状态**(无驳回联动),仅人工确认。 + +--- + +## 二、合同特批(C103-8 发起 / contractLegal/result 结果推送) + +### 2.1 触发条件 + +外部客商高风险(风险等级=2)或黑名单,甲方或乙方任一方命中。风险判定:`HcsContractSyncSupport#checkRelativeRisk`(`HcsContractSyncSupport.java:167-183`,`risky` 判定在 :178)。 + +### 2.2 阶段 A:提交校验(特批说明附件必传) + +入口 `ContractManageController`(`@RequestMapping("/contract-manage")`): + +| 接口 | Service 方法 | 校验调用 | +| --- | --- | --- | +| `POST /contract-manage/submit` | `ContractManageServiceImpl#submit`(:146) | :161 | +| `POST /contract-manage/to-temporary` | `#toTemporary`(:178) | :185 | +| `POST /contract-manage/submit-formal` | `#submitFormal`(:198) | :205 | + +三处均调用 `validateSpecExplanationOnSubmit`(:1048-1061): + +1. `isRiskyCustomer`(:1066-1071)→ `HcsCreditCheckSupport#queryCustomerRiskByName`(:240)→ `queryCustomerRisk`(:182-231)**实时调 C101-1**(`hcsClient.getRelativeRisk`);内部组织客商直接返回不命中;名称反查不到客商编号不阻断(:242-248)。 +2. 命中且 `attachmentsJson` 中无 `fileType=特批说明`(`attachmentType=spec_explanation`)附件 → 抛出:"合同相对方存在高风险/黑名单客商,必须上传「特批说明」类型附件后再提交审批"。 + +> 已知缺口:`submitChange`(:303)未调用该校验;`submit()` 中"变更驳回重提交"分支(:150-155)转入 `submitChange`,会绕过附件强校验——推送后自动特批链路仍会兜底挂起,但附件缺失会导致特批发起失败。 + +### 2.3 阶段 B:审批通过 → 推送 → 自动特批 + +审批通过:`POST /contract-manage/approve` → `ContractManageServiceImpl#approve`(:217-245):置 `hcsSyncStatus=unsynced`(:237,推送零埋点 ADR-0001)→ `hcsImmediatePushSupport.pushContractAfterCommit(id)`(:243)。 + +合同推送共 3 个入口,收敛到 `HcsContractSyncSupport#pushContract`(:113-158): + +| 入口 | 位置 | 说明 | +| --- | --- | --- | +| 即时推送 | `HcsImmediatePushSupport#pushContractAfterCommit`(:114) | afterCommit 异步(2 线程 daemon 池),开关 `push.immediate-enabled` 默认 false;`pushContractNow`(:178)对特批挂起中(need/processing)短路跳过(:185-188) | +| 定时扫描 | `HcsPushTask#pushHcsContract`(:155,cron 默认 `0 1/5 * * * ?`) | `pushUnsyncedContracts`(:254-278):`approvalStatus ∈ {approved, change_approved}` 且 `hcs_sync_status ∈ {unsynced, failed}` 且重试未超限 | +| 手动重推 | `HcsSyncController POST /hcs/sync/contract/{id}`(:110)→ `repushContract`(:509-530) | 特批挂起中不可推(:517-519) | + +`pushContract` 内部步骤(与本文相关的 ⑤): + +``` +⓪ 特批挂起门禁(need/processing 直接返回,:118-121) +① 风险校验仅留痕(:124-126,回写 hcs_risk_level / hcs_black_status / hcs_risk_time) +②③④ 附件转传 C103-2 / 判重 / C103-1 起草或 C103-11 更新,markSynced 回填 hcs_fd_id(:535) +⑤ risky 时 autoApplySpecIfNeeded(:190-212)——自动特批链路 +``` + +`autoApplySpecIfNeeded`(:190-212): + +1. 特批已通过(`hcs_spec_status=approved`,单次有效)→ 跳过(:191-195); +2. 置 `hcsSpecStatus=need` + `currentNode="特批审核"`(`SPEC_REVIEW_NODE`,:196-201)——**先挂起后特批**; +3. `transferSpecExplanationAttachments`(:218-242)筛选「特批说明」附件转传 C103-2(合规附件 ID 存入 `hcs_spec_files_json`); +4. 调 `hcsContractSpecSyncSupport.applySpec(...)`(:207)发起 C103-8;失败保持 `need` 仅留痕(:208-211),可人工经 `POST /hcs/contract/spec-apply` 重发。 + +> 设计要点(`HcsContractSyncSupport.java:56-58` 注释):C103-8 必须携带已起草合同的 `hcs_fd_id`,因此顺序是 **先 C103-1 起草、后 C103-8 特批**(8e6e263 调整)。 + +### 2.4 阶段 C:发起特批 C103-8 + +`HcsContractSpecSyncSupport#applySpec`(`HcsContractSpecSyncSupport.java:92-130`): + +- 前置:`requireAppliableContract`(:196-208,须审批通过 + 特批状态 need/rejected)、附件非空(:94-96)、`requireContractFdId`(:213-218,须已有 `hcs_fd_id`); +- 组装 `HcsSpecContractSaveDTO`:`fdDocSubject="合同特批-{合同编号}"`、`fdReason=合同名称`、附件 `fdEntityKey=fd_spc_approval_attach`(:97-111); +- `hcsClient.addSpecContract`(`IHcsClient.java:281`,`SPEC_CONTRACT_ADD_URL`)响应双层嵌套 `data.data.fdId` → 回填 `hcs_spec_fd_id`(:117),`markSpec` 置 `processing`(:118); +- 留痕 `blade_hcs_check_log`(biz_type=`contract`,check_type=`spec`,:335-350);失败回 `need`(:125)。 + +### 2.5 阶段 D:结果联动(两条等效路径) + +| 路径 | 接口 | 实现 | +| --- | --- | --- | +| 合规推送 | `POST /hcs/contractLegal/result`(`HcsSyncController`,`@PreAuth(PERMIT_ALL)`,网关注册 `/gwzh/HTHG/contractLegal/result`) | `handleLegalResult`:`requestId`=合同ID(selectById)定位 → `status=APPROVED/REJECTED` 大小写不敏感识别(其他值仅留痕)→ 原文(含 reason)留痕,报文模型 `HcsLegalResultDTO` | +| 人工确认 | `POST /hcs/contract/spec/confirm`(:251-257) | `confirmSpecResult`(:139-157,仅 processing 可确认) | + +联动 `syncContractOnSpecResult`(:312-320): + +- `approved` → `currentNode="审批通过"`(C103-1 已起草,无需再推送,流程放行); +- `rejected` → `approvalStatus=rejected` + `currentNode="已驳回"`,走"重新编辑 → 提交 → 审批 → 重新特批"闭环。 + +`markSpec`(:325-330)回写 `hcs_spec_status`/`hcs_spec_time`/`hcs_spec_msg`,回调原文留痕。 + +### 2.6 TMS 侧留痕字段(`blade_contract_manage`,`ContractManage.java:45`) + +| 字段 | 位置 | 含义 | +| --- | --- | --- | +| `hcs_fd_id` | :213 | HCS 合同 ID(C103-1 起草回填) | +| `hcs_risk_level` / `hcs_black_status` / `hcs_risk_time` | :233/:236/:239 | C101-1 风险留痕 | +| `hcs_spec_fd_id` | :242 | HCS 特批流程 ID(C103-8 回填) | +| `hcs_spec_status` | :246 | `none/need/processing/approved/rejected` | +| `hcs_spec_time` / `hcs_spec_msg` | :249/:253 | 特批时间/信息 | +| `hcs_spec_files_json` | :256 | 特批材料(含 C103-2 合规附件 ID) | +| `current_node` | — | 挂起展示:`特批审核` / `审批通过` / `已驳回` | + +--- + +## 三、付款特批(付款申请提交触发侧) + +### 3.1 入口与触发 + +`PaymentApplicationController`(`/payment-application`)`POST /submit` → `PaymentApplicationServiceImpl#submit`(`PaymentApplicationServiceImpl.java:316-335`),事务内 :329 调 `HcsCreditCheckSupport#checkOnSubmit(entity)`(`HcsCreditCheckSupport.java:89-99`),依次执行两项校验: + +**① C101-1 收款方风险校验**(开关 `risk.check-on-payment` 默认 true,:91) + +- `checkRelativeRisk`(:104-131):按收款方 `payeeName` 反查 `CustomerArchive` 客商编号 → C101-1 实时查询; +- **黑名单且 `risk.block-blacklist=true`(默认 true)→ 直接阻断**:抛"收款方客商黑名单,禁止提交付款申请"(:127-129)——付款链路黑名单不走特批; +- 反查不到客商编号记 skip 留痕、不阻断(:106-110)。 + +**② C106-1 合同额度校验**(开关 `credit.check-enabled` 默认 false,**一期未对接**,:95-97) + +- `checkCredit`(:136-172):要求合同已推送(有 `hcs_fd_id`,:138-145)→ `hcsClient.contractCreditCheck`(:151); +- `fdIsCredit=true`(额度内)→ `hcs_credit_status=pass`(:160); +- **超额不拦截提交** → `hcs_credit_status=over` + `hcs_credit_msg` + **`hcs_spec_status=need`**(:167-169)——这是付款特批的唯一自动触发点。 + +### 3.2 后续流转 + +- 审批通过:`#approve`(:353-362)置 `hcs_sync_status=unsynced`(:359,零埋点 ADR-0001); +- **付款链没有即时推送**(`HcsImmediatePushSupport` 仅覆盖 project/contract),完全依赖定时扫描/手动端点(见 §四)。 + +### 3.3 TMS 侧留痕字段(`blade_payment_application`,`PaymentApplication.java:41`) + +| 字段 | 位置 | 含义 | +| --- | --- | --- | +| `hcs_fd_id` / `hcs_sync_status` / `hcs_retry_count` | :125/:127/:129 | HCS 同步主状态 | +| `hcs_credit_status` | :135 | `pass`(额度内)/ `over`(超额) | +| `hcs_credit_msg` / `hcs_credit_time` | :137/:139 | 额度校验信息 | +| `hcs_spec_fd_id` / `hcs_spec_status` | :141/:142 | 特批流程 ID / `none/need/pushing/processing/approved/rejected` | +| `hcs_perf_fd_id` | :145 | 履约记录(C108,默认关,不在本文范围) | + +### 3.4 与合同特批的关联 + +- 付款特批报文中的合同取 `ContractManage.hcs_fd_id` 传值(`requireContractFdId`,`HcsSpecPaySyncSupport.java:210-215`),额度校验也是按合同维度(C106-1 `fdContractId`); +- 二者共用 `HcsSyncConstant.SPEC_STATUS_*` 状态机与 `blade_hcs_check_log` 留痕表(biz_type=`payment`,check_type=`risk`/`credit`/`spec`)。 + +--- + +## 四、结算付款特批(C106-3 发起 / C106-4 更新) + +### 4.1 概念澄清 + +代码库中**不存在独立的"结算单付款"特批实体**。"结算付款特批"是**付款申请(PaymentApplication)的 HCS 特批流程在 HCS 侧的表单名称**——单据主题固定 `结算付款特批-{paymentNo}`(`HcsSpecPaySyncSupport.java:129/158`)。即: + +- §三(付款特批)= **触发侧**:提交时 C106-1 超额置 `need`; +- 本节(结算付款特批)= **推送侧**:审批通过后发起 C106-3 / 更新 C106-4。 + +佐证:`PaymentApplication.paymentType` 含 `settlement_payment`(`TransportBusiConstant.PAYMENT_TYPE_SETTLEMENT`,:35),BFI 申请事由即称"结算付款申请"(`PaymentApplicationServiceImpl.java:1207-1213`);`FormalSettlementPayment`(正式结算付款记录,`blade_formal_settlement_payment`)**没有任何 hcs/特批字段**,仅在付款完成后联动生成,不参与特批。 + +### 4.2 推送链路 + +| 入口 | 位置 | 说明 | +| --- | --- | --- | +| 定时扫描 | `HcsPushTask#pushHcsPayment`(:163,cron 默认 `0 2/5 * * * ?`,开关 `push.payment.sync-enabled` 默认 false) | `pushUnsyncedPayments`(:285-309):`approvalStatus=approved` 且 `hcs_sync_status ∈ {unsynced, failed}` 且重试未超限 → `HcsPaymentSyncSupport#pushPayment` | +| 手动重推 | `POST /hcs/sync/payment/{id}`(`HcsSyncController.java:111`)→ `repushPayment`(:95-113);批量 `POST /hcs/sync/payment`(:129) | — | + +`HcsPaymentSyncSupport#pushPayment`(`HcsPaymentSyncSupport.java:70-87`): + +1. **① 结算付款特批**:`hcs_spec_status=need` 且未发起时(:72-74)调 `HcsSpecPaySyncSupport#pushSpecPay`; +2. ② 履约记录 C108(默认关); +3. 最后统一 `markSynced`(:142)/ `markFailed`(:154)回写整体同步状态。 + +> 当前 `credit.check-enabled=false`(C106-1 未对接),`need` 无自动触发源,"仅历史数据/人工场景可达"(`HcsPaymentSyncSupport.java:72` 注释)。 + +### 4.3 C106-3/4 实现(`HcsSpecPaySyncSupport`) + +`pushSpecPay`(:86-108): + +- `hcs_spec_fd_id` 为空 → **C106-3 发起**:`hcsClient.addSpecApplyPay`(:92,`IHcsClient.java:259`)双层嵌套 `data.data.fdId` → 回填 `hcs_spec_fd_id` + 状态 `processing`(:94-96); +- 非空 → **C106-4 更新**:`updateSpecApplyPay`(:102,`IHcsClient.java:268`,顶层 `fdId` 定位,内层 `success` 判断)。 + +报文组装 `buildSpecPayParam`(:113-166):`HcsSpecPaySaveDTO` → `HcsSpecPayFormDataDTO` → `HcsSpecPayPropsDTO`,关键字段: + +| HCS 字段 | 取值 | +| --- | --- | +| `fdDocSubject` | `结算付款特批-{paymentNo}`(:129/:158) | +| `fdContractName` | 合同 `hcs_fd_id`(:123) | +| `fdDocNo` / `fdId` | `paymentNo`(:127/:131) | +| `fdPayAmount` | `appliedAmount` 申请金额(:133) | +| `fdTotalAmount` | `settlementAmount` 结算金额(:135) | +| `fdPayer` / `fdPayee` | 付款方/收款方(:137-138) | +| 收款账户/账号/开户行 | :140-142 | +| `fdSettleCurrency` | 默认"人民币"(:144) | +| `fdPaymentPurpose`/`fdPaymentNature`/`fdPaymentType` | 来自 `thirdParty.hcs.spec-pay.*` 配置(:146-148) | +| `fdReason` / `fdSupplementNote` | `remark`(:150-151) | +| `fdSpcApprovalAttach` | `fd_spc_approval_attach`(:155) | + +操作人 = 付款申请创建人登录名(`resolveLoginName`,:220-229)。 + +附件 `buildMechanisms`(:171-193):`attachmentsJson` 经 `HcsAttachmentSupport#transferAttachments`(C103-2)转传;**发起时带 `fdBindType=ADD`、更新时不带**(:181-189)。 + +### 4.4 结果确认 + +特批结果由合规系统审批完成后主动推送(2026-10-12 起,替代原计划的 B103,§9-U1 已闭环): + +- `POST /hcs/paymentLegal/result`(`HcsSyncController`,`@PreAuth(PERMIT_ALL)`,网关注册 `/gwzh/HTHG/paymentLegal/result`)→ `HcsPaymentSyncSupport#handleLegalResult`:`requestId`=付款申请ID 定位,`status=APPROVED/REJECTED` 回写 `hcs_spec_status`,不联动付款审批状态; +- 等效兜底:页面人工确认 `POST /hcs/spec-pay/confirm`(仅 `processing` 可确认,置 `approved/rejected`); +- **付款特批结果不联动付款审批状态**(与合同特批的 `syncContractOnSpecResult` 不同,无驳回联动)。 + +--- + +## 五、推送时机与结果接收机制汇总 + +| 机制 | 合同特批(C103-8/contractLegal/result) | 付款/结算付款特批(C106-3/4/paymentLegal/result) | +| --- | --- | --- | +| 定时扫描 | `HcsPushTask#pushHcsContract`(默认 `0 1/5 * * * ?`) | `HcsPushTask#pushHcsPayment`(默认 `0 2/5 * * * ?`);Redis 任务锁 TTL 240s(:92)、分钟位错峰(:75-77) | +| 即时推送 | `HcsImmediatePushSupport#pushContractAfterCommit`(afterCommit 异步,开关默认 false,单条锁 TTL 120s) | 无 | +| 结果推送接收 | `POST /hcs/contractLegal/result`(PERMIT_ALL,requestId=合同ID,原文留痕+联动审批状态) | `POST /hcs/paymentLegal/result`(PERMIT_ALL,requestId=付款申请ID,回写特批状态) | +| 人工确认 | `POST /hcs/contract/spec/confirm` | `POST /hcs/spec-pay/confirm` | +| 手动发起/重推 | `POST /hcs/contract/spec-apply`(:226)、`POST /hcs/sync/contract/{id}`(:110) | `POST /hcs/sync/payment/{id}`(:111)、`POST /hcs/sync/payment`(:129) | + +--- + +## 六、依赖配置项(`thirdParty.hcs.*`,`HcsProperties.java`) + +| 配置 | 默认 | 说明 | +| --- | --- | --- | +| `contract.require-risk-check` | true | 提交时特批说明附件强校验 | +| `risk.check-on-contract` | — | 合同链路 C101-1 查询开关 | +| `risk.check-on-payment` | true | 付款提交 C101-1 校验开关 | +| `risk.block-blacklist` | true | 付款链路黑名单阻断(合同链路已不用于阻断) | +| `credit.check-enabled` | **false** | C106-1 额度校验,一期未对接(付款特批自动触发源关闭) | +| `contract.special-contract-enabled` | false | C103-1 报文特批流程字段 `fdSepcailContract`(固定 false,D15) | +| `push.immediate-enabled` | false | 审批通过后即时推送 | +| `push.contract.sync-enabled` / `push.contract.cron` | — / `0 1/5 * * * ?` | 合同定时扫描 | +| `push.payment.sync-enabled` / `push.payment.cron` | — / `0 2/5 * * * ?` | 付款定时扫描 | +| `spec-pay.payment-purpose/nature/type` | — | C106 报文付款用途/性质/类型 | + +--- + +## 七、留痕与常量速查 + +- **留痕表**:`blade_hcs_check_log`(`HcsContractCheckLog.java:44`):`biz_type=contract/payment`、`check_type=risk/credit/spec`、`result`、`msg`(≤500)、`trace_id`。 +- **关键常量**(`HcsSyncConstant`):`SPEC_STATUS_NONE/NEED/PROCESSING/APPROVED/REJECTED`(:119-149)、`RISK_LEVEL_HIGH="2"`(:156)、`ATTACHMENT_TYPE_SPEC_EXPLANATION="特批说明"`(:171)、`SPEC_REVIEW_NODE="特批审核"`(:176)。 +- **合规推送结果状态**(`HcsSyncConstant`):`LEGAL_RESULT_APPROVED="APPROVED"` / `LEGAL_RESULT_REJECTED="REJECTED"`(原 B103 回调候选键常量 `HcsFieldConstant.SPEC_CB_*` 已随旧回调端点删除)。 +- **特批附件挂载键**:`fd_spc_approval_attach`(合同 C103-8 与付款 C106-3/4 共用)。