: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 * * * ?` | 合同定时扫描 |