:feat: 付款申请收款方高风险黑名单统一走特批(特批附件校验/特批审核挂起/结果联动审批状态/金蝶推送门禁)

This commit is contained in:
刘泉佳
2026-10-14 10:03:10 +08:00
parent d99488b999
commit 30028b9e27
9 changed files with 361 additions and 72 deletions
@@ -4,9 +4,11 @@
> 涉及模块:`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`(外部客商高风险黑名单管控与合同自动特批)
> 付款申请全链路(前端提交 → 风险/特批 → 同步金蝶 → 结果回写)专项梳理:`doc/docs/业务流程/2026-10-13-付款申请全链路业务流程(前端提交-客商风险特批-同步金蝶-结果回写).md`
>
> **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/§五。
> **2026-10-13 变更**:C103-8 独立特批发起接口合规未提供(联调 404),合同特批改为随 C103-1/C103-11 报文携带 `fdSepcailContract=true` 发起(高风险/黑名单判定后置入报文);TMS 挂起"特批审核"(processing)后新增**定时 C103-4 结果查询兜底**(随合同推送任务执行,`fdApprovalStatus=approved/approvalinvalid` 联动恢复/驳回);特批附件改随 C103-1 附件面板 `eopCdraftSpecial` 挂载;附件类型判定值与业务字典对齐为「特批附件」。**C103-8 全链路代码已删除**(`IHcsClient#addSpecContract`/`HcsSpecContractSaveDTO`/`applySpec`/`POST /hcs/contract/spec-apply`)。**contractLegal/result 报文已按合规方最新字段表修正**:`{contractType, contractCode, requestId, success, reason, kingdeeId, sourceSystem=WCCK}`(金蝶同步结果结构,非原假设的 status=APPROVED/REJECTED),按 `contractCode`=合同编号定位,`success=true` 联动放行(kingdeeId 留痕)/`false` 联动驳回走重新提交闭环;付款 `paymentLegal/result` 仍为旧结构,待合规方字段表后同步修正。
> **2026-10-13 付款链路变更**:按最新需求,付款链路黑名单**不再直接阻断**,与高风险统一走特批:提交时收款方为**外部客商**(`CustomerArchive.customerKind≠internal`)才查 C101-1,高风险(`fdRiskLevel=2`)/黑名单(`fdBlackStatus=yes`)→ 提示且**必须上传「特批附件」**(付款附件结构 `attachmentType=special_approval`,缺失抛异常)+ 标记 `hcs_spec_status=need`(不再依赖 C106-1 额度超额这一唯一触发源);审批通过后扫描任务发起 C106-3,TMS 挂起 `currentNode="特批审核"`;合规审批完成后**回调 `paymentLegal/result`** 通知结果,`APPROVED` 恢复"审批通过"放行、`REJECTED` 联动付款审批驳回(returned)走重新提交闭环,页面人工确认等效兜底;特批审核中(need/pushing/processing)**禁止推送金蝶**(`doSyncKingdee` 门禁);前端付款表单同步增加收款方 C101-1 风险查询提示与特批附件提交校验。`risk.block-blacklist` 配置及 Nacos 项已删除。见 §三/§4.4。
---
@@ -19,27 +21,29 @@
| 触发线 | HCS 接口 | 判定条件 | 触发的特批 | 作用对象 |
| --- | --- | --- | --- | --- |
| 外部客商高风险/黑名单 | C101-1 风险查询 | `fdRiskLevel=2`(高风险)或 `fdBlackStatus=yes`(黑名单) | 合同特批(C103-1/C103-11 报文 `fdSepcailContract=true` 发起 / contractLegal/result 结果回调 + C103-4 定时查询兜底) | `ContractManage`(合同) |
| 合同额度超额 | C106-1 额度校验 | `fdIsCredit=false`(超额) | 结算付款特批(C106-3 发起 / C106-4 更新) | `PaymentApplication`(付款申请) |
| 收款方外部客商高风险/黑名单 | C101-1 风险查询 | 同上判定(仅收款方,`customerKind=internal` 内部客商不查) | 结算付款特批(提交校验特批附件 + 标记 need → C106-3 发起 / C106-4 更新 / paymentLegal/result 回调联动付款审批状态) | `PaymentApplication`(付款申请) |
| 合同额度超额 | C106-1 额度校验 | `fdIsCredit=false`(超额) | 结算付款特批(同上链路) | `PaymentApplication`(付款申请) |
补充规则:
- **内部组织客商不查**:`CustomerArchive.customerKind=internal` 默认无风险(`HcsSyncConstant.CUSTOMER_KIND_INTERNAL`)。
- **内部组织客商不查**:`CustomerArchive.customerKind=internal` 默认无风险(`HcsSyncConstant.CUSTOMER_KIND_INTERNAL`),合同链路(甲/乙方)与付款链路(收款方)口径一致。
- **甲/乙任一方命中即整单管控**(`HcsSyncConstant.java:151-176`)。
- **付款链路中黑名单不是特批而是直接阻断**:`risk.block-blacklist=true`(默认)时提交付款申请直接抛异常,不走特批。
- **付款链路高风险/黑名单不再阻断**(2026-10-13 起):提示且必须上传「特批附件」,标记 need 走 C106-3 特批;原 `risk.block-blacklist` 阻断配置已删除。
### 1.2 与普通审批的关系
特批与合同起草**同报文发起**(高风险/黑名单客商推送时 C103-1/C103-11 报文带 `fdSepcailContract=true`,合规侧随起草自动走特批流程;C103-8 独立发起接口合规未提供,相关代码已删除)。特批期间 TMS 用 `hcs_spec_status=processing` + `currentNode="特批审核"` 挂起展示,推送门禁与手动重推均拦截;特批通过即放行,驳回则联动本地审批驳回(仅合同链路)。
特批与合同起草**同报文发起**(高风险/黑名单客商推送时 C103-1/C103-11 报文带 `fdSepcailContract=true`,合规侧随起草自动走特批流程;C103-8 独立发起接口合规未提供,相关代码已删除)。特批期间 TMS 用 `hcs_spec_status=processing` + `currentNode="特批审核"` 挂起展示,推送门禁与手动重推均拦截;特批通过即放行,驳回则联动本地审批驳回(合同与付款链路均已联动)。付款链路另在特批审核中(need/pushing/processing)**禁止推送金蝶**,特批通过后放行。
### 1.3 特批状态机(两条链路共用 `HcsSyncConstant.SPEC_STATUS_*`)
```
none(默认) ──高风险/黑名单随 C103-1/C103-11 带 fdSepcailContract=true──▶ processing(挂起"特批审核")──结果回调/查询──▶ approved / rejected
none(默认) ──付款提交高风险/黑名单须特批附件 / 额度超额──▶ need ──审批通过后扫描 C106-3──▶ processing(挂起"特批审核")──paymentLegal/result 回调──▶ approved / rejected
need(存量遗留,2026-10-13 起不再产生;重推时自愈:报文带特批标记 → 挂起转 processing)
```
- 合同特批 `approved` **单次有效**:再次推送时若已 approved 不重复发起。
- 付款特批 `approved/rejected` **不联动付款审批状态**(无驳回联动),仅人工确认。
- 付款特批结果**联动付款审批状态**(2026-10-13 起):`approved` 恢复"审批通过"放行(金蝶推送门禁解除);`rejected` 联动付款审批驳回(`approvalStatus=returned` + `currentNode="已驳回"`),走"重新编辑→提交→审批→重新特批"闭环。
---
@@ -132,26 +136,33 @@ need(存量遗留,2026-10-13 起不再产生;重推时自愈:报文带
## 三、付款特批(付款申请提交触发侧)
### 3.1 入口与触发
### 3.1 入口与触发(2026-10-13 起两类触发源)
`PaymentApplicationController`(`/payment-application`)`POST /submit` → `PaymentApplicationServiceImpl#submit`(`PaymentApplicationServiceImpl.java:316-335`),事务内 :329 调 `HcsCreditCheckSupport#checkOnSubmit(entity)`(`HcsCreditCheckSupport.java:89-99`),依次执行两项校验:
`PaymentApplicationController`(`/payment-application`)`POST /submit` → `PaymentApplicationServiceImpl#submit`,事务内调 `HcsCreditCheckSupport#checkOnSubmit(entity)`(`HcsCreditCheckSupport.java:94-108`),依次执行两项校验:
**① C101-1 收款方风险校验**(开关 `risk.check-on-payment` 默认 true,:91)
**① C101-1 收款方风险校验**(开关 `risk.check-on-payment` 默认 true,:95-98)
- `checkRelativeRisk`(:104-131):按收款方 `payeeName` 反查 `CustomerArchive` 客商编号 → C101-1 实时查询;
- **黑名单且 `risk.block-blacklist=true`(默认 true)→ 直接阻断**:抛"收款方客商黑名单,禁止提交付款申请"(:127-129)——付款链路黑名单不走特批;
- 反查不到客商编号记 skip 留痕、不阻断(:106-110)。
- `checkRelativeRisk`(:110-148):按收款方 `payeeName` 反查 `CustomerArchive`:
- 反查不到客商档案 → skip 留痕、不阻断(:111-117);
- **内部组织客商(`customerKind=internal`)默认无风险,不调 C101-1**(:119-124);
- 外部客商按客商编号实时调 C101-1,高风险(`fdRiskLevel=2`)或黑名单(`fdBlackStatus=yes`)判定 risky(:136);
- **risky 时两步管控(不再直接阻断)**:
1. **特批附件必传**:`attachmentsJson` 中无 `attachmentType=special_approval`(前端付款表单「特批附件」类型,兼容 `fileType=特批附件` 旧结构)附件 → 抛"收款方[xxx]为高风险/黑名单客商,必须上传「特批附件」类型附件后再提交审批"(`hasSpecAttachment`,:295-313);
2. **标记待特批**:`hcs_spec_status=need` 并清空旧 `hcs_spec_fd_id`(特批单次有效,重新提交须重新发起 C106-3,:149-151)——审批通过后扫描任务发起 C106-3。
**② C106-1 合同额度校验**(开关 `credit.check-enabled` 默认 false,**一期未对接**,:95-97)
**② C106-1 合同额度校验**(开关 `credit.check-enabled` 默认 false,**一期未对接**,:100-103)
- `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)——这是付款特批的唯一自动触发点。
- `checkCredit`:要求合同已推送(有 `hcs_fd_id`)→ `hcsClient.contractCreditCheck`;
- `fdIsCredit=true`(额度内)→ `hcs_credit_status=pass`;
- **超额不拦截提交** → `hcs_credit_status=over` + `hcs_credit_msg` + **`hcs_spec_status=need`**。
### 3.2 后续流转
### 3.2 后续流转(审批通过 → 推送特批 → 挂起 → 回调联动)
- 审批通过:`#approve`(:353-362)置 `hcs_sync_status=unsynced`(:359,零埋点 ADR-0001);
- **付款链没有即时推送**(`HcsImmediatePushSupport` 仅覆盖 project/contract),完全依赖定时扫描/手动端点(见 §四)。
- 审批通过:`#approve` 置 `hcs_sync_status=unsynced`(零埋点 ADR-0001);
- **付款链没有即时推送**(`HcsImmediatePushSupport` 仅覆盖 project/contract),完全依赖定时扫描/手动端点(见 §四);
- 扫描任务对 `hcs_spec_status=need` 的已审批单发起 C106-3 → 成功后 `processing` + **挂起 `currentNode="特批审核"`**(`HcsSpecPaySyncSupport#pushSpecPay`);
- **特批审核中(need/pushing/processing)禁止推送金蝶**:`PaymentApplicationServiceImpl#doSyncKingdee` 门禁抛"收款方客商为高风险/黑名单,付款特批审核中…特批完成后方可推送金蝶";
- 合规审批完成后**回调 `paymentLegal/result`**(见 §4.4):`APPROVED` → 恢复"审批通过"放行(金蝶门禁解除);`REJECTED` → 联动付款审批驳回(`approvalStatus=returned` + `currentNode="已驳回"`),走"重新编辑→提交→审批→重新特批"闭环(提交时重新校验风险与特批附件)。
### 3.3 TMS 侧留痕字段(`blade_payment_application`,`PaymentApplication.java:41`)
@@ -161,6 +172,7 @@ need(存量遗留,2026-10-13 起不再产生;重推时自愈:报文带
| `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` |
| `current_node` | :111 | 特批挂起展示:`特批审核`(C106-3 发起后)/ `审批通过`(特批通过恢复)/ `已驳回`(特批驳回联动) |
| `hcs_perf_fd_id` | :145 | 履约记录(C108,默认关,不在本文范围) |
### 3.4 与合同特批的关联
@@ -188,13 +200,13 @@ need(存量遗留,2026-10-13 起不再产生;重推时自愈:报文带
| 定时扫描 | `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`):
`HcsPaymentSyncSupport#pushPayment`(`HcsPaymentSyncSupport.java:75-91`):
1. **① 结算付款特批**:`hcs_spec_status=need` 且未发起时(:72-74)调 `HcsSpecPaySyncSupport#pushSpecPay`;
1. **① 结算付款特批**:`hcs_spec_status=need` 且未发起时(:77-80)调 `HcsSpecPaySyncSupport#pushSpecPay`(C106-3 成功后 `processing` + 挂起 `currentNode="特批审核"`);
2. ② 履约记录 C108(默认关);
3. 最后统一 `markSynced`(:142)/ `markFailed`(:154)回写整体同步状态。
3. 最后统一 `markSynced` / `markFailed` 回写整体同步状态。
> 当前 `credit.check-enabled=false`(C106-1 未对接),`need` 无自动触发源,"仅历史数据/人工场景可达"(`HcsPaymentSyncSupport.java:72` 注释)。
> `need` 触发源(2026-10-13 起):提交时收款方外部客商高风险/黑名单(须特批附件)或 C106-1 额度超额(`credit.check-enabled=false` 未对接时仅前者可达)。
### 4.3 C106-3/4 实现(`HcsSpecPaySyncSupport`)
@@ -225,11 +237,11 @@ need(存量遗留,2026-10-13 起不再产生;重推时自愈:报文带
### 4.4 结果确认
特批结果由合规系统审批完成后主动推送(2026-10-12 起,替代原计划的 B103,§9-U1 已闭环):
特批结果由合规系统审批完成后**回调 `paymentLegal/result` 通知 TMS**,并联动付款审批状态(2026-10-13 起):
- `POST /hcs/paymentLegal/result`(`HcsSyncController`,blade.secure 放行,网关注册 `/gwzh/HTHG/paymentLegal/result`)→ `HcsPaymentSyncSupport#handleLegalResult`:先校验 `sourceSystem`(不符抛"来源系统标识错误"异常),`requestId`=付款申请ID 定位,`status=APPROVED/REJECTED` 回写 `hcs_spec_status`,不联动付款审批状态;
- 等效兜底:页面人工确认 `POST /hcs/spec-pay/confirm`(仅 `processing` 可确认,置 `approved/rejected`);
- **付款特批结果不联动付款审批状态**(与合同特批的 `syncContractOnSpecResult` 不同,无驳回联动)。
- `POST /hcs/paymentLegal/result`(`HcsSyncController`,blade.secure 放行,网关注册 `/gwzh/HTHG/paymentLegal/result`)→ `HcsPaymentSyncSupport#handleLegalResult`(:156-189):先校验 `sourceSystem`(不符抛"来源系统标识错误"异常),`requestId`=付款申请ID 定位,`status=APPROVED` → 特批通过 + 恢复 `currentNode="审批通过"` 放行(金蝶推送门禁解除);`status=REJECTED` → 特批驳回 + **联动付款审批驳回**(`approvalStatus=returned` + `currentNode="已驳回"`,`syncPaymentOnSpecResult` :191-202),走"重新编辑→提交→审批→重新特批"闭环;
- 等效兜底:页面人工确认 `POST /hcs/spec-pay/confirm`(仅 `processing` 可确认,与回调同样联动付款审批状态);
- 与合同特批(contractLegal/result + C103-4 定时查询兜底)不同,付款特批**仅回调通知**(合规未提供 C106 结果查询接口),无定时查询兜底,回调未达时靠人工确认。
---
@@ -239,7 +251,7 @@ need(存量遗留,2026-10-13 起不再产生;重推时自愈:报文带
| --- | --- | --- |
| 定时扫描 | `HcsPushTask#pushHcsContract`(默认 `0 1/5 * * * ?`,同轮附带特批结果查询兜底 `syncProcessingSpecResults`) | `HcsPushTask#pushHcsPayment`(默认 `0 2/5 * * * ?`);Redis 任务锁 TTL 240s、分钟位错峰 |
| 即时推送 | `HcsImmediatePushSupport#pushContractAfterCommit`(afterCommit 异步,开关默认 false,单条锁 TTL 120s) | 无 |
| 结果推送接收 | `POST /hcs/contractLegal/result`(blade.secure 放行,sourceSystem=WCCK,contractCode=合同编号定位,success 联动审批状态,原文留痕) | `POST /hcs/paymentLegal/result`(blade.secure 放行,requestId=付款申请ID,回写特批状态;报文仍为旧结构待合规方字段表确认) |
| 结果推送接收 | `POST /hcs/contractLegal/result`(blade.secure 放行,sourceSystem=WCCK,contractCode=合同编号定位,success 联动审批状态,原文留痕) | `POST /hcs/paymentLegal/result`(blade.secure 放行,requestId=付款申请ID,回写特批状态并**联动付款审批状态**:approved 恢复放行 / rejected 联动审批驳回;报文仍为旧结构待合规方字段表确认) |
| 人工确认 | `POST /hcs/contract/spec/confirm` | `POST /hcs/spec-pay/confirm` |
| 手动发起/重推 | `POST /hcs/sync/contract/{id}`(spec-apply 已随 C103-8 删除,2026-10-13) | `POST /hcs/sync/payment/{id}`、`POST /hcs/sync/payment` |
@@ -251,9 +263,8 @@ need(存量遗留,2026-10-13 起不再产生;重推时自愈:报文带
| --- | --- | --- |
| `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 额度校验,一期未对接(付款特批自动触发源关闭) |
| `risk.check-on-payment` | true | 付款提交 C101-1 校验开关(收款方外部客商高风险/黑名单须特批附件并标记待特批) |
| `credit.check-enabled` | **false** | C106-1 额度校验,一期未对接(付款特批第二触发源关闭,高风险/黑名单触发不受影响) |
| `contract.special-contract-enabled` | false | C103-1/C103-11 报文 `fdSepcailContract` 强制 true(默认关;高风险/黑名单判定自动带 true,本开关可强制全量走特批,联调验证用) |
| `push.immediate-enabled` | false | 审批通过后即时推送 |
| `push.contract.sync-enabled` / `push.contract.cron` | — / `0 1/5 * * * ?` | 合同定时扫描 |
@@ -0,0 +1,200 @@
# 付款申请全链路业务流程(前端提交 → 客商风险与特批 → 同步金蝶 → 结果回写)
> 梳理日期:2026-10-13
> 涉及模块:`tms-erp-web/src/views/payment/payment-application-form.vue`(前端表单)、`blade-service/blade-transport`(业务编排)、`blade-third-party-api/blade-hcs-api`(合规 Feign)、`blade-third-party-api/blade-bfi-api`(金蝶 BFI Feign)
> 关联文档:`doc/docs/hcs合同/2026-10-12-合同特批与结算付款特批流程梳理.md`(特批机制专项)、`doc/docs/TMS业财融合-集成流程图文字版与业务流程梳理.md`(图03)、`业务流程/2026-09-16-付款管理正式付款同步金蝶….md` 与 `业务流程/2026-09-17-付款管理金蝶付款结果定时回写….md`(金蝶链路专项)
> 2026-10-13 变更:付款链路黑名单不再直接阻断,与高风险统一走特批(提示 + 特批附件必传 + C106-3 特批 + 回调联动审批状态 + 金蝶推送门禁);前端付款表单新增风险客商提示条与特批附件提交校验。
---
## 一、全链路总览
```mermaid
flowchart TD
subgraph FE["前端 · 付款申请表单"]
f1["新建付款申请<br/>选付款类型(正式结算付款/预付款/项目预付)"]
f1 --> f2["选合同/结算单 → 联动收款账户<br/>客商档案反查收款方"]
f2 --> f3{"C101-1 客商风险查询<br/>(收款方外部客商才查)"}
f3 -->|"高风险/黑名单"| f4["风险客商提示条(常驻)<br/>要求上传「特批附件」"]
f3 -->|"低风险/中风险/内部客商"| f5["正常填写"]
f4 --> f6
f5 --> f6["保存草稿 / 提交"]
end
subgraph TMS["TMS 后端 · 提交与审批"]
f6 --> t1{"提交校验<br/>(submit 事务内)"}
t1 -->|"特批附件缺失"| t2["拦截:必须上传「特批附件」"]
t1 -->|"通过"| t3["reviewing 财务审核<br/>(高风险/黑名单置 hcs_spec_status=need)"]
t3 --> t4{"本地审批"}
t4 -->|"驳回"| t5["returned 已驳回 → 重新编辑"]
t4 -->|"通过"| t6["approved 审批通过<br/>hcs_sync_status=unsynced"]
end
subgraph HCS["合同合规系统(HCS)"]
t6 -->|"定时扫描发起 C106-3"| h1["结算付款特批单生成"]
h1 --> h2["TMS 挂起 currentNode=特批审核<br/>(need/pushing/processing 禁止推送金蝶)"]
h2 --> h3{"集团特批审批"}
h3 -->|"paymentLegal/result:APPROVED"| h4["恢复 审批通过 → 放行金蝶推送"]
h3 -->|"paymentLegal/result:REJECTED"| h5["联动付款审批驳回 returned<br/>重新编辑 → 提交 → 重新特批"]
end
subgraph JD["金蝶星瀚(经 iPaaS /gwzh/BFI)"]
h4 -->|"手动/批量同步"| j1{"付款类型路由"}
j1 -->|"正式结算付款"| j2["A102-4 预检财务应付单已生成<br/>→ A103-2 幂等预检 → A103-1 应付下推"]
j1 -->|"预付款"| j3["A103-3 预付款申请保存"]
j2 --> j4["kingdeeStatus=synced(锁单)"]
j3 --> j4
j4 --> j5["财务共享审批 → 付款处理 → 付款完成"]
j5 -->|"A103-2/A103-4 定时回写"| j6["更新付款结果/履约数据"]
end
```
三条主线:**合规管控线**(C101-1 风险 → 特批附件 → C106-3 特批 → paymentLegal/result 联动)、**本地审批线**(draft → reviewing → approved/returned)、**金蝶付款线**(A103-1/A103-3 → 锁单 → A103-2/A103-4 回写)。硬约束:**高风险/黑名单收款方特批不通过,付款申请不得推送金蝶**。
---
## 二、阶段一:前端表单与提交(`payment-application-form.vue`)
| 步骤 | 动作 | 实现要点 |
|---|---|---|
| 1 | 新建/编辑付款申请 | 付款类型路由引用单据:正式结算付款→正式结算单(可多张)、预付款→预结算单、项目预付→项目+合同 |
| 2 | 选合同联动 | `fillBillTypeFromContract`:带出票据类型/付款方(合同甲方)/收款账户候选(合同乙方客商) |
| 3 | **收款方风险查询** | `loadReceiptAccountOptions`:按合同乙方名称反查客商档案 → `GET /hcs/risk?customerCode=`(C101-1 实时查,后端对内部组织客商默认返回无风险)→ `payeeRisky/payeeRiskLevel/payeeBlackStatus/payeeRiskTip` 留档 |
| 4 | **风险客商提示条** | 高风险/黑名单时基本信息"备注"下方常驻展示(橙黄底红字,同合同新增页):`风险等级:高风险|黑名单:是。【名称】:…风险项…,按集团规定不可直接付款,提交前须上传「特批附件」类型附件,审批通过后将自动发起付款特批`;附件清单同步显示"未上传:特批附件" |
| 5 | 附件材料 | 材料清单:磅单/结算单(必传)、合同签章文件(首次合同付款/项目预付)、**特批附件**(收款方高风险/黑名单或客商等级 D/E/F 时必传,`attachmentType=special_approval`)、其他 |
| 6 | 保存草稿 | `POST /payment-application`(save)→ draft,可反复编辑 |
| 7 | 提交 | `submitForm`:静默保存 → **特批附件缺失校验**(高风险/黑名单阻断,提示与后端同口径)→ `POST /payment-application/submit` → 发起 MK 审批流 |
> 风险查询失败不阻断前端填写,提交时后端强校验兜底。
---
## 三、阶段二:后端提交校验(`PaymentApplicationServiceImpl#submit`,事务内)
```
前置校验:状态(draft/returned)→ 申请金额>0 → 尾款/项目预付合同/选票/额度校验
↓
HcsCreditCheckSupport#checkOnSubmit(risk.check-on-payment 默认 true)
↓
① C101-1 收款方风险校验(checkRelativeRisk):
- 反查不到客商档案 → skip 留痕不阻断
- 内部组织客商(customerKind=internal)→ 默认无风险,不调 C101-1
- 外部客商 → C101-1 实时查询,risky = 风险等级2(高风险)或 fdBlackStatus=yes(黑名单)
- risky → 「特批附件必传」校验(attachmentsJson 含 attachmentType=special_approval,缺失抛异常)
→ hcs_spec_status=need + 清空旧 hcs_spec_fd_id(特批单次有效,重新提交重新发起)
② C106-1 额度校验(credit.check-enabled 默认 false,一期未对接):
- 合同已推送(有 hcs_fd_id)→ 额度内 pass / 超额不拦截 → hcs_credit_status=over + need
↓
全部通过:approvalStatus=reviewing,currentNode="财务审核",留痕 blade_hcs_check_log(biz_type=payment,check_type=risk/credit)
```
---
## 四、阶段三:本地审批
| 动作 | 状态流转 | 附加动作 |
|---|---|---|
| 审批通过 `approve` | reviewing → **approved**,currentNode="审批通过" | `hcs_sync_status=unsynced`(零埋点 ADR-0001,扫描任务据此接管后续推送) |
| 审批驳回 `returnBill` | reviewing → **returned**,currentNode="已驳回" | — |
| 作废 `voidBill` | approved → **voided**,currentNode="已作废" | 票据付款释放票据占用 |
---
## 五、阶段四:HCS 付款特批推送(`HcsPushTask#pushHcsPayment`)
- **定时扫描**:cron 默认 `0 2/5 * * * ?`,开关 `push.payment.sync-enabled` **默认 false**(灰度开启);条件 `approvalStatus=approved` 且 `hcs_sync_status ∈ {unsynced, failed}` 且重试 < `push.max-retry`(默认 5);Redis 任务锁 TTL 240s 防多实例重扫。
- **推送编排**(`HcsPaymentSyncSupport#pushPayment`):
1. **① 结算付款特批**(`hcs_spec_status=need` 时,`HcsSpecPaySyncSupport#pushSpecPay`):
- `hcs_spec_fd_id` 为空 → **C106-3 发起**:报文主题 `结算付款特批-{paymentNo}`,合同传 `blade_contract_manage.hcs_fd_id`,金额/收付款方/账户随单,附件经 C103-2 转传挂 `fd_spc_approval_attach`(发起带 `fdBindType=ADD`)→ 返回双层 `data.data.fdId` 回填 `hcs_spec_fd_id` → 状态 **processing** + **挂起 `currentNode="特批审核"`**;
- 非空 → **C106-4 更新**(单据变更场景,附件不带 fdBindType)。
2. ② C108 履约记录(默认关)。
3. `markSynced`/`markFailed` 回写整体同步状态。
- **手动重推**:`POST /hcs/sync/payment/{id}`(重置 unsynced 立即推)、`POST /hcs/sync/payment`(批量扫一轮)。
- **金蝶推送门禁**(`doSyncKingdee`):`hcs_spec_status ∈ {need, pushing, processing}` 抛"收款方客商为高风险/黑名单,付款特批审核中(特批审核),特批完成后方可推送金蝶"。
---
## 六、阶段五:特批结果联动(`HcsPaymentSyncSupport`)
| 路径 | 机制 | 结果联动 |
|---|---|---|
| **合规回调(主)** | 合规审批完成后回调 `POST /hcs/paymentLegal/result`(网关 `/gwzh/HTHG/paymentLegal/result`,blade.secure 放行)→ `handleLegalResult`:`sourceSystem` 须为 `third-party.hcs.src-system`(默认 WLTMS,不符抛"来源系统标识错误"),`requestId`=付款申请ID 定位,`status=APPROVED/REJECTED` | 见下 |
| **人工确认(兜底)** | `POST /hcs/spec-pay/confirm`(仅 processing 可确认,与回调等效) | 见下 |
| 特批结果 | `hcs_spec_status` | 付款审批联动 | 后续 |
|---|---|---|---|
| APPROVED | approved | currentNode="审批通过"(审批状态保持 approved) | 金蝶推送门禁解除,可同步金蝶 |
| REJECTED | rejected | **approvalStatus=returned + currentNode="已驳回"** | 走"重新编辑 → 提交(重新校验风险与特批附件、重新置 need)→ 审批 → 重新发起 C106-3"闭环 |
> 付款特批无 C106 结果查询接口,不做定时查询兜底(合同链路才有 C103-4 兜底);回调未达时靠页面人工确认。
---
## 七、阶段六:同步金蝶(`syncKingdee` → `doSyncKingdee`,单据级事务经自代理)
**前置**:`approvalStatus=approved` + 特批门禁通过 + `kingdeeStatus` 非终态(synced/paying/paid/closed 直接幂等返回)。
| 付款类型 | 链路 |
|---|---|
| **正式结算付款**(settlement_payment,应付类) | ① `requirePayableSettlement` 校验结算类型 → ② 逐张正式结算单 **A102-4** 预检财务应付单已在金蝶生成(缺则拦截"请先在正式付款单页面同步金蝶")→ ③ **A103-2** 幂等预检(上次下推成功但本地回滚的场景直接回填)→ ④ **A103-1 付款申请保存(应付下推)** |
| **预付款 / 项目预付** | 上次失败先 **A103-2** 勾稽恢复 → **A103-3 付款申请保存(预付款)**,不绑应付单 |
- **成功**:`kingdeeBillId` 回填 + `kingdeeStatus=synced`(业务单据锁定,ERP 不可改);付款申请单编号与付款状态由定时回写任务经 A103-2/A103-4 回填。
- **失败**:事务回滚后独立事务 `markKingdeeSyncFailed` → `kingdeeStatus=failed`,可重试同步。
- 批量:`syncKingdeeBatch`(全批共享档案缓存 + A102-4 批量预检,逐单单据级事务)。
---
## 八、阶段七:付款结果回写与履约联动
- **定时回写**(`PaymentKingdeeResultTask`,专项文档见 `业务流程/2026-09-17-….md`):**A103-2** 付款申请单查询 + **A103-4** 付款处理查询 → 回写 `kingdeeBillNo`/付款状态(paying/paid/closed)→ 付款完成联动正式结算付款记录(`blade_formal_settlement_payment`)与履约数据。
- **HCS 履约/附件**(默认关/独立周期):C108 履约记录推送(`perf-record.sync-enabled`)、C106-2 付款附件每日定时推送——不在本文展开,见特批专项文档 §四。
---
## 九、状态机速查
**付款审批状态 `approvalStatus`**:`draft` →(提交)`reviewing` →(通过)`approved` /(驳回)`returned` /(作废,仅 approved)`voided`;特批驳回联动 `approved → returned`。
**HCS 特批状态 `hcs_spec_status`**:`none` →(提交时高风险/黑名单或额度超额)`need` →(C106-3 发起成功)`processing`(挂起"特批审核")→(paymentLegal/result 回调/人工确认)`approved` / `rejected`。
**金蝶状态 `kingdeeStatus`**:空 →(同步成功)`synced` →(回写)`paying` → `paid` / `closed`;同步失败 `failed`(可重推)。
**当前节点 `currentNode`**:财务审核 → 审批通过 →(特批中)**特批审核** → 审批通过(放行)/ 已驳回(returned 闭环)。
---
## 十、配置项与接口速查
| 配置(`thirdParty.hcs.*`) | 默认 | 说明 |
|---|---|---|
| `risk.check-on-payment` | true | 提交时收款方 C101-1 校验开关 |
| `credit.check-enabled` | false | C106-1 额度校验(一期未对接,超额为特批第二触发源) |
| `push.payment.sync-enabled` / `push.payment.cron` | **false** / `0 2/5 * * * ?` | 付款特批+履约定时扫描(**未开启时高风险单审批通过后停在 need,且金蝶推送被门禁拦截**) |
| `push.max-retry` / `push.batch-size` | 5 / 50 | 重试上限 / 单轮批量 |
| `spec-pay.payment-purpose/nature/type`、`doc-status` | — | C106 报文字典值 |
| `src-system` | WLTMS | paymentLegal/result 回调来源校验值 |
| 接口 | 提供方 | 用途 |
|---|---|---|
| `GET /hcs/risk` | TMS 代理 C101-1 | 前端收款方风险查询(提示条) |
| C106-3 / C106-4 | 合同合规 | 结算付款特批发起 / 更新 |
| `POST /hcs/paymentLegal/result` | 合同合规 → TMS | 特批结果回调(APPROVED 放行 / REJECTED 联动审批驳回) |
| `POST /hcs/spec-pay/confirm` | TMS | 特批结果人工确认(兜底) |
| A102-4 / A103-2 | 金蝶 | 财务应付单预检 / 付款申请单幂等预检与结果回写 |
| A103-1 / A103-3 | 金蝶 | 应付下推付款申请 / 预付款申请保存 |
| B901 | ERP → 金蝶 | 锁单/解锁(已推金蝶单据 ERP 锁定) |
---
## 十一、异常与逆向
| 场景 | 处理 |
|---|---|
| C101-1 查询失败 | 提交抛"C101-1 客商风险查询失败"(不留风险缺口);前端查询失败仅跳过提示 |
| 收款方反查不到客商档案 | skip 留痕不阻断(§9-U6 口径) |
| 特批附件缺失 | 前端提交阻断 + 后端提交抛异常(双重校验) |
| C106-3 发起失败 | `hcs_sync_status=failed` + 重试计数,下轮扫描自动补偿,超限人工重推 |
| 特批驳回 | 付款审批联动驳回(returned),重新编辑提交后重新置 need、清空旧 `hcs_spec_fd_id`,重新发起特批 |
| 金蝶推送失败 | `kingdeeStatus=failed`,A103-2 幂等预检防重复推送;批量同步单条失败不影响整批 |
| 金蝶侧驳回/需修改 | 金蝶反审核+删除 → 解锁 → TMS 重推(已推单据 ERP 不可改,财务共享审批对 TMS 黑盒) |