!8 付款特批+履约计划履约记录(付款+开票+收票+收款)+金蝶编码取A901-1供应商接口返回的number

Merge pull request !8 from mindless/feature/20261027-hcs-bif-all
This commit is contained in:
2026-11-04 08:33:15 +00:00
committed by Gitee
87 changed files with 4166 additions and 368 deletions
@@ -0,0 +1,268 @@
# C108 履约记录四场景推送改造流程梳理(收款/付款/开票/收票)
> 日期:2026-10-28
> 范围:`tms-api` blade-transport HCS 推送链路;合同系统(HCS)接口 C108-1 履约记录新建 / C108-2 履约记录更新
> 关联文档:《2026-10-27-履约计划与履约记录逻辑与流程梳理》(改造前基线)
---
## 1. 需求口径
C108-1(履约记录新建)、C108-2(履约记录更新)两个接口需在收款、付款、开票、收票四个场景使用:
| # | 场景 | 对应 TMS 数据 | 推送时机 | 履约日期(fd_plan_date) | 履约类型(fd_paln_type) |
|---|------|--------------|----------|------------------------|------------------------|
| 1 | 履约收款记录 | 收款认领记录(收款流水 × 认领分摊) | 金蝶认领推送(A301-3)成功后 | **交易日期**(收款流水 `transaction_time`) | 收款 |
| 2 | 履约付款记录 | 付款申请(含实际付款金额) | **金蝶实际付款后**(付款结果回写推进) | 申请日期(计划日期口径,维持原样) | 付款 |
| 3 | 履约开票记录 | 开票申请的金蝶回写发票(每张发票一条) | **金蝶开票完成后**(A303-5 发票落库后) | **发票完成开票日期**(`invoice_date`) | 开票 |
| 4 | 履约收票记录 | 收票单的每条结算信息(分摊行,每条一条) | 收票单推送合规(C109)成功后 | **发票日期**(收票单 `invoice_date`) | 收票 |
> `fd_paln_type` 按四场景分别传中文值:**付款 / 收款 / 开票 / 收票**(常量 `HcsSyncConstant.PERF_TYPE_*`);C103-9 履约计划行的履约类型仍传 `payment`/`collection`,两者互不影响。
本次确认的业务口径调整:**履约付款记录由「审批通过即新建」改为「金蝶实际付款后才新建」**。
---
## 2. 总览:改造前后对照
| 场景 | 改造前 | 改造后 |
|------|--------|--------|
| 收款 | 已实现(C108-1),履约日期=最近认领日期 | 履约日期改为交易日期;组装逻辑收敛到通用组件 |
| 付款 | 审批通过即 C108-1 新建,特批通过后补推履约计划与履约记录,实际付款后 C108-2 更新 | **特批通过后不推任何履约数据**;未实际付款不推送;首次实际付款 C108-1 新建;分期付款推进 C108-2 更新 |
| 开票 | 无(仅 C111 开票登记) | 新增:金蝶回写发票逐张推 C108-1,发票粒度幂等+重试 |
| 收票 | 无(仅 C109 收票单) | 新增:每条结算分摊行推 C108-1,分摊行粒度幂等+重试,且限 C109 已推送 |
---
## 3. 通用机制
### 3.1 接口与字段
- C108-1:`IHcsClient.perfRecordAdd`,返回 `fdId`(履约记录ID,**必须持久化**,C108-2 更新必传)
- C108-2:`IHcsClient.perfRecordUpdate`,`formData.fdId` 必填,响应无 data,`success=true` 即成功
- `fd_plan_id`(履约计划id)接口必填:取合同**已同步的履约计划行合规阶段ID**(`blade_contract_exe_stage.hcs_stage_fd_id`);无已同步计划行时抛出重试,合同链路首推 C103-9 后下轮自愈
- `fd_paln_type` 为接口文档原文拼写(plan 笔误),必须沿用;取值 `payment` / `collection`
- 机制数据(附件)C108-1 必填:新三场景(收款/开票/收票)无附件传空列表;付款场景保留附件转传逻辑
### 3.2 开关
统一复用 `thirdParty.hcs.perf-record.sync-enabled`(默认关,灰度打开),无新增配置:
- 收款:门禁 C108-1(C103-9/C107-1 仍由 `exe-stage.sync-enabled` 门禁)
- 付款:门禁 C108-1/C108-2
- 开票/收票:门禁各自扫描任务,且随宿主任务(invoice-application / invoice-receipt)的 `sync-enabled` 一起生效
### 3.3 幂等与重试模式
- **付款**:单据粒度,`blade_payment_application.hcs_perf_fd_id` + `hcs_sync_status`(unsynced/synced/failed)+ `hcs_retry_count`,随 HcsPushTask 付款任务扫描重试
- **开票**:发票粒度,`blade_invoice_application_invoice.hcs_perf_fd_id`(非空即已推,扫描跳过)+ `hcs_perf_retry_count` / `hcs_perf_sync_msg`,失败下轮自动补偿,超上限人工
- **收票**:分摊行粒度,`blade_invoice_receipt_settlement.hcs_perf_fd_id` + 同上两列;扫描范围限定所属收票单 C109 已推送(`hcs_sync_status=synced`)
- **收款**:认领链事件驱动(金蝶认领推送成功后内联),fdId 暂不落库(shortcut:认领链无 C108-2 场景,重推会重复,需作废联动时先落库)
### 3.4 通用组件
新增 `HcsPerfRecordAddSupport`(transport/support/hcs):收敛收款/开票/收票三场景的 C108-1 组装与推送(申请金额=实际金额、fd_plan_id 校验、标题、溯源字段),入参:合同、履约计划行、申请编号、金额、履约日期、履约类型、金蝶单据号、业务ID、标题。
付款场景因含 C108-2 推进与附件转传,保留原 `HcsPerfRecordSyncSupport`。
---
## 4. 各场景流程明细
### 4.1 履约收款记录(对应认领记录)
```
认领操作 → 收款流水推送金蝶(A301-3)成功
→ HcsClaimSyncSupport.pushClaimToHcs(flowId)
① C103-9 认领金额累加收款履约计划行并重推
② C107-1 认领记录(按「认领主单 × 合同」分组,金额为分摊到该合同的金额)
③ C108-1 履约流水(按合同一条) ← 本次改造点
```
- 履约日期:**收款流水交易日期** `blade_kingdee_receipt_flow.transaction_time`(原为最近认领日期,空时兜底当天)
- 申请编号:收款通知单号,兜底明细流水号
- 申请金额 = 实际金额 = 该合同累计认领金额
- fd_jd_doc_no:A301-3 返回的金蝶收款单号;fd_business_id:收款流水ID
- 标题:`收款履约-{通知单号}`
- 前置门禁:合同已推送合规(hcs_fd_id 非空)、存在已同步收款计划行,不满足仅记日志跳过
### 4.2 履约付款记录(对应付款记录,金蝶实际付款了再推)
```
付款申请审批通过
→ 如需特批:发起 C106-3 挂起,特批通过后仅联动审批恢复 + 补推金蝶
★改:特批通过后不推履约计划与履约记录(履约数据统一在各业务环节推送)
→ 审批通过即时推送链不产生履约付款记录(paidAmount 为空/0 跳过,
提示"金蝶未实际付款,待付款后推送履约记录",整体状态照常置 synced)
金蝶实际付款 → 定时任务 A103-2 付款结果回写(applyPayApplyResult)
→ paidAmount 首次 >0 或金额变化 → hcs_sync_status 置 unsynced ★改(原仅在有 fdId 时置)
→ HcsPushTask 付款任务下轮扫描 → pushPayment
C103-9 履约计划重推(付款审批累加金额行,exe-stage 开关门禁)
无 hcs_perf_fd_id → C108-1 新建(申请金额 + 实际金额)→ fdId 回填 hcs_perf_fd_id
有 hcs_perf_fd_id → C108-2 更新(分期付款推进实际金额)
```
- 触发数据源:A103-2 分录 `e_paidamt` 汇总(分录缺失且已付款时兜底申请全额)
- 履约日期:申请日期(fd_plan_date 计划日期口径不变);C108-2 仅在金额推进时触发,`paying` 状态每轮回写金额不变不再重复推送
- 标题:`付款履约-{付款申请单号}`;fd_jd_doc_no:金蝶付款申请单号
### 4.3 履约开票记录(对应开票申请,金蝶开票完成后推送)
```
开票申请审批通过 → 推金蝶(A303-1)→ 推合规 C111 开票登记(票据日期空)
金蝶开票完成 → 定时任务 A303-5 开票结果回写(executeInvoiceResultSync)
→ 发票逐张落库 blade_invoice_application_invoice
→ 申请单置 kingdeeStatus=invoiced + hcs_sync_status=unsynced(触发 C111-3 回填票据日期)
HcsPushTask 开票任务(每5分钟):
① pushUnsyncedInvoiceApplications:C111 开票登记推送/回填
② HcsInvoicePerfSyncSupport.pushUnsyncedInvoicePerfRecords ★新增
扫描 hcs_perf_fd_id IS NULL 且重试未超限的发票
→ 批量装配:申请单(须审批通过)→ 应收结算关联 → 正式结算单合同 → 收款履约计划行
→ 每张发票一条 C108-1:金额=发票价税合计,履约日期=发票完成开票日期
→ 成功回填 hcs_perf_fd_id;失败 retry+1 记 hcs_perf_sync_msg 下轮补偿
```
- 申请编号:发票号;fd_jd_doc_no:金蝶开票申请单编号(serialNo);fd_business_id:发票记录ID
- 标题:`开票履约-{发票号}`
- 合同回溯不到(无应收结算关联/合同)→ 记失败原因,下轮重试(同 C111 §9-U10 口径)
### 4.4 履约收票记录(对应收票单每条结算信息)
```
收票登记审批通过
→ 推金蝶收票单(A303-2 + A302-6)
→ HcsPushTask 收票任务(每5分钟):
① pushUnsyncedInvoiceReceipts:C109 收票单推送合规
② HcsReceiptPerfSyncSupport.pushUnsyncedReceiptPerfRecords ★新增
扫描 hcs_perf_fd_id IS NULL 且重试未超限的分摊行,
且所属收票单 hcs_sync_status=synced(C109 已推送)+ 审批通过
→ 每条结算信息一条 C108-1:金额=分摊收票金额(兜底结算金额),
履约日期=收票单发票日期,履约类型 payment,关联合同付款履约计划行
→ 成功回填 hcs_perf_fd_id;失败 retry+1 记 hcs_perf_sync_msg 下轮补偿
```
- 申请编号:`{发票号}-{结算单号}`(同一发票分摊多结算单时逐条可区分);标题:`收票履约-{发票号}-{结算单号}`
- fd_jd_doc_no:金蝶收票单号(`kingdee_received_invoice_no`);fd_business_id:分摊行ID
- 合同回溯:分摊行 → 正式结算单 → contractId
---
## 5. 定时任务编排(改造后)
| 任务 | cron(默认) | 内容 |
|------|-------------|------|
| payment | `0 2/5 * * * ?` | 付款特批 C106 + 履约计划 C103-9 + **履约付款记录 C108-1/2(金蝶实际付款门禁)** |
| invoice-application | `0 3/5 * * * ?` | C111 开票登记 + **履约开票记录 C108-1(发票粒度)** |
| invoice-receipt | `0 4/5 * * * ?` | C109 收票单 + **履约收票记录 C108-1(分摊行粒度)** |
| (收款无独立任务) | 事件驱动 | 金蝶认领推送(A301-3)成功后内联:C103-9 → C107-1 → C108-1 |
---
## 6. 数据库变更
`doc/sql/transport/blade_invoice_application_invoice_perf_20261028.sql`、`blade_invoice_receipt_settlement_perf_20261028.sql`:
- `blade_invoice_application_invoice` 加 `hcs_perf_fd_id varchar(64)` / `hcs_perf_retry_count int` / `hcs_perf_sync_msg varchar(512)`
- `blade_invoice_receipt_settlement` 加同三列
---
## 7. 关键代码位置
| 文件 | 说明 |
|------|------|
| `support/hcs/HcsPerfRecordAddSupport.java` | ★新增 通用 C108-1 组件(收款/开票/收票共用) |
| `support/hcs/HcsInvoicePerfSyncSupport.java` | ★新增 履约开票记录扫描推送 |
| `support/hcs/HcsReceiptPerfSyncSupport.java` | ★新增 履约收票记录扫描推送 |
| `support/hcs/HcsClaimSyncSupport.java` | 改:履约日期→交易日期;组装改调通用组件 |
| `support/hcs/HcsPaymentSyncSupport.java` | 改:C108 环节增加「金蝶实际付款」门禁 |
| `service/impl/PaymentApplicationServiceImpl.java` | 改:实际付款推进置 unsynced(不再要求已有 fdId;金额不变不重复触发) |
| `task/HcsPushTask.java` | 改:开票/收票任务追加履约记录推送;组合方法改 public 供手动批量入口复用 |
| `controller/HcsSyncController.java` | 改:`POST /hcs/sync/invoice-application|invoice-receipt` 批量入口改走组合方法(手动触发也推履约记录) |
| `pojo/entity/InvoiceApplicationInvoice.java`、`InvoiceReceiptSettlement.java` | 改:加 3 个 hcs_perf_* 字段 |
---
## 8. 验证指引
### 8.1 前置准备
1. **执行 SQL**:`doc/sql/transport/blade_invoice_application_invoice_perf_20261028.sql`、`blade_invoice_receipt_settlement_perf_20261028.sql`(两表各加 3 列)。
2. **编译**:`mvn clean compile -DskipTests -pl blade-service/blade-transport -am`(已验证通过)。
3. **Nacos 开关**(`third-party-api.yaml` / 环境配置):
- `thirdParty.hcs.perf-record.sync-enabled: true`(履约记录总开关,四场景共用,默认关)
- 宿主任务开关:`thirdParty.hcs.push.payment.sync-enabled`、`thirdParty.hcs.push.invoice-application.sync-enabled`、`thirdParty.hcs.push.invoice-receipt.sync-enabled`(定时任务与手动批量共用)
- 收款链另需 `thirdParty.hcs.exe-stage.sync-enabled: true`(门禁 C103-9/C107-1)
- 环境项照旧:`thirdParty.hcs.base-url/authorization/key-auth`、`perf-record.xform-id`
4. **基础数据**:合同已推送合规(`blade_contract_manage.hcs_fd_id` 非空)且存在已同步履约计划行(`blade_contract_exe_stage.hcs_stage_fd_id` 非空,收款场景需收款行、付款/收票需付款行、开票需收款行)——`fd_plan_id` 必填来源,无则推送记失败等待合同链路首推后自愈。
### 8.2 手动触发入口(联调不等定时任务)
| 动作 | 接口 |
|------|------|
| 认领推送金蝶(收款链触发点) | `POST /receipt-flow/push-kingdee` |
| 付款结果回写(A103-2/A103-4) | `POST /payment-application/sync-kingdee-result` |
| 开票结果回写(A303-5 发票落库) | `POST /invoice-application/sync-kingdee-invoice-result` |
| 收票单推送金蝶(A303-2+A302-6) | `POST /invoice-receipt/push-kingdee` |
| HCS 批量扫描一轮(含履约记录) | `POST /hcs/sync/payment`、`/hcs/sync/invoice-application`、`/hcs/sync/invoice-receipt` |
| HCS 单条重推(付款) | `POST /hcs/sync/payment/{付款申请ID}` |
> 注意:开票/收票的手动批量与定时任务走同一组合方法(C111/C109 + 履约记录一起推);单条重推仅覆盖 C111/C109 主单据,发票/分摊行粒度的履约重推走批量扫描(fdId 为空的行自动补偿)。
### 8.3 分场景验证步骤
**场景 1|履约收款记录**
1. 页面对收款流水做认领(分摊到关联合同的正式结算单),推送金蝶认领:`POST /receipt-flow/push-kingdee`。
2. TMS 日志:`HCS认领记录推送成功` → `HCS履约流水新建成功`(含 perfFdId)。
3. HCS 侧核对履约记录:标题 `收款履约-{通知单号}`、申请/实际金额=该合同累计认领金额、**fd_plan_date=收款流水交易日期**(改造点,不再是最早/最近认领日期)、fd_plan_id=收款计划行阶段ID。
4. 边界:交易时间为空的流水 → fd_plan_date 兜底当天;认领作废不触发推送。
**场景 2|履约付款记录(金蝶实际付款了再推)**
1. 付款申请审批通过并推金蝶(`POST /payment-application/sync-kingdee`);此时**不应**产生履约付款记录——日志出现 `金蝶未实际付款,待付款后推送履约记录`,HCS 侧无记录。
2. 特批场景(高风险/黑名单收款方或额度超额):提交后发起 C106-3 挂起;特批通过(回调 `paymentLegal/result` 或人工确认 `POST /hcs/spec-pay/confirm`)后,核对**无任何履约计划重推与履约记录推送动作**(仅审批恢复 + 金蝶补推),HCS 侧仍无履约付款记录。
3. 在金蝶完成实际付款后,手动回写:`POST /payment-application/sync-kingdee-result`。
4. 数据库:`SELECT paid_amount, hcs_sync_status FROM blade_payment_application WHERE id=?` → paid_amount>0 且 hcs_sync_status=unsynced。
5. 手动扫描:`POST /hcs/sync/payment` → 日志 `HCS履约记录新建成功`(C108-1)→ 数据库 `hcs_perf_fd_id` 回填。
6. 分期付款(金蝶再次付款)→ 再触发回写 → 金额变化置 unsynced → 再扫描 → 日志 `HCS履约记录更新成功`(C108-2);HCS 侧 fd_fact_amount 与最新 paid_amount 一致。
7. 反向验证:`paying` 状态下连续两轮回写但金额不变 → 不置 unsynced、不重复推送。
**场景 3|履约开票记录**
1. 开票申请审批通过 → 推金蝶 → 金蝶完成开票后手动回写:`POST /invoice-application/sync-kingdee-invoice-result` → `blade_invoice_application_invoice` 落库发票。
2. 手动扫描:`POST /hcs/sync/invoice-application` → 汇总含 `履约开票记录:扫描 X 张,成功 X 张`。
3. 数据库:`SELECT invoice_no, invoice_date, hcs_perf_fd_id, hcs_perf_sync_msg FROM blade_invoice_application_invoice WHERE invoice_application_id=?` → 每张发票 fdId 回填、msg 清空。
4. HCS 侧核对:每张发票一条履约记录、标题 `开票履约-{发票号}`、**fd_plan_date=发票完成开票日期**、金额=发票价税合计、fd_plan_id=收款计划行阶段ID。
5. 失败重试:构造失败(如临时断开 HCS / 删掉合同 hcs_fd_id)→ fdId 保持空、`hcs_perf_retry_count` 每轮 +1、`hcs_perf_sync_msg` 记录原因;恢复后下轮自动补推成功。
**场景 4|履约收票记录**
1. 收票登记(分摊到结算单)审批通过 → 推金蝶:`POST /invoice-receipt/push-kingdee`。
2. 手动扫描:`POST /hcs/sync/invoice-receipt` → 先 `C109 收票单推送成功`,再 `履约收票记录:扫描 X 条,成功 X 条`。
3. 数据库:`SELECT formal_settlement_no, allocated_invoice_amount, hcs_perf_fd_id, hcs_perf_sync_msg FROM blade_invoice_receipt_settlement WHERE invoice_receipt_id=?` → 每条分摊行 fdId 回填。
4. HCS 侧核对:每条结算信息一条履约记录、申请编号 `-{发票号}-{结算单号}`、**fd_plan_date=收票单发票日期**、金额=分摊收票金额、fd_plan_id=付款计划行阶段ID、履约类型 payment。
5. 依赖顺序验证:C109 未推送成功时先扫描 → 分摊行 `hcs_perf_sync_msg` 记"收票单尚未推送合规";C109 成功后下轮自动补推,无需人工干预。
### 8.4 通用检查点
| 检查项 | 方法 | 预期 |
|--------|------|------|
| 幂等 | 同条件连续触发两轮 `/hcs/sync/{bizType}` | 第二轮履约记录扫描 0 条(fdId 非空跳过),HCS 无重复记录 |
| 失败重试上限 | 持续失败场景观察 | `hcs_perf_retry_count` 达 `thirdParty.hcs.push.max-retry`(默认 5)后不再扫描,人工处理后重置计数 |
| 履约日期口径 | HCS 侧逐条核对 fd_plan_date | 收款=交易日期 / 开票=发票开票日期 / 收票=发票日期 / 付款=申请日期 |
| 溯源字段 fd_business_id | HCS 侧核对 | 付款=付款申请ID、收款=流水ID、开票=发票记录ID、收票=分摊行ID |
| 开关关闭回归 | `perf-record.sync-enabled=false` 后触发各链路 | 金蝶/合规主流程(A301-3、C111、C109)不受影响,仅履约记录跳过 |
| 日志 | 检索 `HCS履约` | 推送开始/成功/失败成对出现,失败带响应 msg 与重试计数 |
> 服务端核对路径:HCS 管理端按 `fd_doc_subject`(收款履约-/付款履约-/开票履约-/收票履约-前缀)检索履约记录列表。
---
## 9. 联调注意事项与风险
1. **fd_paln_type 口径(已确认)**:履约记录类型按四场景传中文——付款 / 收款 / 开票 / 收票;款项性质仍取关联履约计划行(progress),如合规侧字典要求编码(如 4141 样例)联调时调整常量即可。
2. **C108-1 无服务端判重键**:新三场景极端情况下「推送超时但远端已成功」的重试可能在合同系统产生重复记录(与既有 C107-1 同风险);开票/收票有本地 fdId 幂等只能防"确认成功后"的重复,不能防"未知结果"的重试。
3. **收票履约依赖 C109 先推**:收票单未推送合规(或推送失败)时分摊行记失败原因等待,C109 成功后下轮自动补偿。
4. **存量数据**:改造前已按「审批通过即新建」推送过履约付款记录的单据(已有 `hcs_perf_fd_id`),后续金额推进仍走 C108-2,行为兼容;开票/收票新场景上线后只会处理新落库数据(`hcs_perf_fd_id` 为空的历史发票会被补推,如需排除请手工回填标记)。
5. 测试由业务侧执行;开关 `thirdParty.hcs.perf-record.sync-enabled` 默认关闭,灰度打开后观察 HcsPushTask 日志(前缀 `HCS履约`)。
@@ -0,0 +1,103 @@
# 客商黑名单与风险等级业务说明(业务侧)
> 更新日期:2026-10-30 | 适用系统:运输 TMS | 读者:业务/运营人员
>
> 关联文档:《客商黑名单与风险等级运维手册(运维侧)》(同目录)
## 1. 这是什么
TMS 从**两个外部系统**获取客商风险数据,每日自动更新到客商档案,用于客商档案的展示、筛选,以及合同、付款环节的风险管控:
| 数据 | 来源系统 | 说明 |
|---|---|---|
| **客商风险等级** | 合同合规系统(HCS) | 低风险 / 中风险 / 高风险,另含"黑名单"标识 |
| **金蝶黑名单** | 金蝶(星瀚)· 国资委黑名单 | 命中后记录**失信类别**(禁止交易类 / 风险警示类)与**列入事由** |
## 2. 名词解释
| 名词 | 含义 |
|---|---|
| 黑名单 | 客商被列入外部(国资委)黑名单,**以金蝶黑名单查询(A801-5)命中为准**,命中记录含失信类别与列入事由。金蝶分 **A 类(禁止交易类,不允许交易)** 和 **B 类(风险警示类,需关注)** |
| 失信类别 | 黑名单的分类名称(如"禁止交易类"),来自金蝶黑名单记录 |
| 列入事由 | 被列入黑名单的具体原因(如"涉贪污受贿裁判相关提及方(3年以上及其他)"),来自金蝶黑名单记录 |
| 风险等级 | 合同合规系统对客商的风险评级:0=低风险、1=中风险、2=高风险 |
| 内部组织客商 | 集团内我方签约主体(客商类型=内部组织),**不查询风险,默认无风险** |
## 3. 总体流程
```mermaid
flowchart TD
A[每日凌晨自动刷新<br/>02:30] --> B[取合同期限内生效合同的<br/>甲乙方客商]
B --> C{内部组织客商?}
C -->|是| D[默认无风险, 跳过]
C -->|否| E[查合同合规系统风险等级]
C -->|否| F[查金蝶黑名单]
E --> G[结果写入客商档案<br/>供列表展示与筛选]
F --> G
```
- 刷新范围:**合同期限内**(合同起止日期或临时期限覆盖当天)且**审核通过、未终止**的合同,其甲乙方关联客商。
- 数据**每日更新一次**;当天新增的客商在表单里有实时提示(见 4.1)。
## 4. 各业务环节说明
### 4.1 新增 / 编辑客商(表单实时提示)
- 录入**统一社会信用代码**满 18 位后,系统自动查金蝶客商档案,回填客商名称、法人等工商信息。
- **客商名称**回填或填写后失焦时,系统实时查询该客商的风险;若为高风险/黑名单客商,名称下方显示红色提示,悬浮可见明细,格式:
> 【客商名称】:被列入外部黑名单(失信类别:xx);列入事由 xx;风险等级:高风险
### 4.2 提交准入审批(金蝶黑名单硬校验)
提交客商准入审批时,系统按客商**发票信息中的纳税人识别号**实时查询金蝶黑名单:
| 命中情况 | 结果 |
|---|---|
| **A 类(禁止交易类)** | ❌ **禁止提交**,提示失信类别与列入事由 |
| **B 类(风险警示类)** | ⚠️ 默认放行并记录告警(是否拦截由系统配置决定) |
| 查询异常 | ❌ 暂缓提交(防止漏拦),稍后重试 |
> 因此:维护客商**发票信息(税号)是黑名单校验的前提**,未维护税号时提审不会做黑名单校验。
### 4.3 客商档案列表(展示 / 筛选 / 悬浮)
**客商风险列**显示规则:
| 客商情况 | 显示 | 颜色 |
|---|---|---|
| 金蝶黑名单命中 + 风险等级(组合展示,等级在前) | 高风险、黑名单 / 中风险、黑名单 / 低风险、黑名单 | 红 |
| 金蝶黑名单命中(无等级数据) | 黑名单 | 红 |
| 仅高风险 | 高风险 | 红 |
| 中风险 | 中风险 | 黄 |
| 低风险 | 低风险 | 绿 |
| 内部组织客商 | 无风险(默认,不查询) | 绿 |
| 尚未查询到数据 | - | — |
> "黑名单"仅指**金蝶黑名单命中**;合同合规系统返回的黑名单状态字段不用于列表展示(仅在付款提交强制校验中使用)。
- 红色标签(黑名单/高风险)**鼠标悬浮**可查看明细:失信类别、列入事由、风险等级。
- 搜索栏新增**客商风险**下拉筛选:黑名单 / 高风险 / 中风险 / 低风险。
- 数据为每日凌晨刷新结果,当天有变动的以次日刷新为准。
### 4.4 合同推送(合同合规系统)
合同推送到合规系统前,甲乙双方客商各做一次风险校验:**高风险/黑名单客商的合同不能直接签约**,系统自动发起合同特批流程,特批通过后方可继续。
### 4.5 付款申请
提交付款申请时,若收款方为外部客商且属**高风险/黑名单**:
- 系统弹出风险提示;
- **必须上传「特批附件」**类型附件,否则无法提交审批;
- 审批通过后自动发起付款特批,特批完成前禁止推送金蝶。
## 5. 常见问题
| 问题 | 说明 |
|---|---|
| 为什么客商风险列显示"-"? | 该客商不在任何合同期限内生效合同的关联范围内,尚未被每日刷新任务查询过;或系统刚上线数据尚未生成 |
| 为什么内部组织客商显示"无风险"? | 内部组织为我方主体,按集团规定不查询风险,默认无风险 |
| 新客商当天会出现在风险筛选里吗? | 表单实时提示即时生效;列表落库数据次日刷新后生效 |
| 提交审批被黑名单拦截怎么办? | 客商属 A 类禁止交易,不可线上提交,走线下处置流程 |
| 黑名单数据多久更新? | 每日凌晨 02:30 自动刷新(合同期限内关联客商) |
@@ -0,0 +1,137 @@
# 客商黑名单与风险等级运维手册(运维侧)
> 更新日期:2026-10-30 | 适用系统:运输 TMS(blade-transport) | 读者:运维/实施人员
>
> 关联文档:《客商黑名单与风险等级业务说明(业务侧)》(同目录)
## 1. 链路总览
```
┌──────────────┐ C101-1 客商风险等级 ┌────────────────┐
│ 合同合规系统 │ ◄────────────────────── │ │
│ (HCS) │ A801-5 金蝶黑名单 │ TMS │
└──────────────┘ ◄────────────────────── │ blade-transport│
└──────┬─────────┘
每日 02:30 CustomerRiskRefreshTask │
┌──────▼─────────┐
│ blade_customer_archive
│ hcs_risk_level / kingdee_black_status
│ hcs_risk_time
│ kingdee_black_category / kingdee_black_reason
└────────────────┘
```
**两条数据线**:
| 线 | 接口 | 查询键 | 落库字段 |
|---|---|---|---|
| 合同合规风险(C101-1) | `getRelativeRisk` | 客商编号(fdNumber) | `hcs_risk_level`、`kingdee_black_status`、`hcs_risk_time` |
| 金蝶黑名单(A801-5) | `queryBlacklist` | 税号/统一社会信用代码(number) | `kingdee_black_category`、`kingdee_black_reason` |
**调用场景**(C101-1):
| 场景 | 入口 | 行为 |
|---|---|---|
| 每日定时刷新 | `CustomerRiskRefreshTask` → `HcsCreditCheckSupport.refreshCustomerRiskForActiveContracts()` | 批量落库 |
| 表单实时提示 | `GET /hcs/sync/risk/by-name`(名称反查编号) | 实时查 C101-1 + A801-5 组装 riskTip |
| 列表单查/批量 | `GET /hcs/sync/risk`、`GET /hcs/sync/risk/batch` | 实时查(展示用) |
| 合同推送校验 | `HcsContractSyncSupport.checkRelativeRisk` | 甲乙双方各查一次,高风险转特批 |
| 付款提交校验 | `HcsCreditCheckSupport.checkRelativeRisk` | 高风险/黑名单须特批附件 |
**调用场景**(A801-5):
| 场景 | 入口 | 行为 |
|---|---|---|
| 每日定时刷新 | 同上(200 税号/批) | 落失信类别/列入事由 |
| 提审黑名单校验 | `CustomerArchiveServiceImpl.validateBlacklist` | 按客商发票信息税号查询;**A 类硬拦截,B 类默认放行告警,查询异常阻断提审** |
## 2. 定时任务
`CustomerRiskRefreshTask`(每天 02:30,错开金蝶客商同步 02:00):
1. 取合同期限内生效合同(`approval_status IN (approved, change_approved)`、`current_node != '已终止'`、正式或临时期限覆盖当天)的甲乙方名称——1 次 SQL;
2. 按名称 `IN` 反查客商档案——1 次 SQL;内部组织客商跳过(默认无风险);
3. 外部客商按 **200/批**:每批 A801-5 一次批量查询 + C101-1 逐个远程查询(接口仅支持单编号);
4. 批内成功结果立即 `Db.updateBatchById` 落库 + `Db.saveBatch` 留痕,**批间互不影响,单批失败不中断其余批次**。
## 3. 配置项(Nacos)
| 配置键 | 环境变量 | 默认 | 说明 |
|---|---|---|---|
| `third-party.hcs.risk.refresh-enabled` | `HCS_RISK_REFRESH_ENABLED` | false | 每日刷新总开关(**上线需置 true**) |
| `third-party.hcs.risk.refresh-cron` | `HCS_RISK_REFRESH_CRON` | `0 30 2 * * ?` | 刷新调度 |
| `third-party.hcs.risk.check-on-contract` | `HCS_RISK_CHECK_ON_CONTRACT` | true | 合同推送前风险校验 |
| `third-party.hcs.risk.check-on-payment` | `HCS_RISK_CHECK_ON_PAYMENT` | true | 付款提交前风险校验 |
| `thirdparty.bfi.blacklist.blockRiskWarning` | `BFI_BLACKLIST_BLOCK_RISK_WARNING` | false | 金蝶黑名单 **B 类(风险警示)提审是否拦截**(A 类恒拦截) |
配置模板:`doc/nacos/third-party-api.yaml`(hcs.risk 节点)。
## 4. 数据库
### 4.1 表结构(blade_customer_archive 新增列)
| 字段 | 类型 | 说明 |
|---|---|---|
| `hcs_risk_level` | varchar(8) | C101-1 风险等级:0=低/1=中/2=高风险 |
| `kingdee_black_status` | varchar(8) | C101-1 黑名单状态:yes/no/handing(数据归金蝶口径,故用 kingdee_ 前缀) |
| `hcs_risk_time` | datetime | 风险最近查询时间 |
| `kingdee_black_category` | varchar(200) | 金蝶黑名单失信类别(awrp_combofield_title 兜底 awrp_combofield) |
| `kingdee_black_reason` | varchar(1000) | 金蝶黑名单列入事由(awrp_textareafield) |
索引:`idx_hcs_risk_level`、`idx_kingdee_black_status`。
### 4.2 脚本(幂等可重复执行)
`doc/sql/transport/lqj/temp/`:
| 脚本 | 内容 |
|---|---|
| `02_blade_customer_archive_hcs_risk_20261030.sql` | 加 5 列 + 2 索引(information_schema 判断,已存在跳过) |
| `03_blade_customer_risk_dict_20261030.sql` | 业务字典 `customer_risk`(列表筛选下拉)与 `risk_level`(等级翻译) |
> 若早期版本已执行过含 `hcs_black_category/reason` 的脚本,需手动删除残留列(现名已改 `kingdee_black_*`)。
### 4.3 字典
| code | dictKey → dictValue | 用途 |
|---|---|---|
| `customer_risk` | blacklist/high/middle/low → 黑名单/高风险/中风险/低风险 | 客商列表搜索栏筛选下拉 |
| `risk_level` | 0/1/2 → 低风险/中风险/高风险 | 风险等级名称翻译(明细文案) |
字典缺失时前端筛选走兜底选项、后端明细少拼等级段,不报错。
## 5. 明细组装口径(后台统一)
唯一出口:`HcsCreditCheckSupport.buildRiskDetail(customerName, blackStatusYes, riskLevel, blackCategory, blackReason)`,
格式:`【客商名称】:被列入外部黑名单(失信类别:xx);{列入事由};风险等级:xx`
- 黑名单段:**仅金蝶命中**(类别/事由任一非空);C101-1 的 `hcs_black_status`(fdBlackStatus)不参与展示,仅付款提交强制校验使用;
- 等级段:`risk_level` 字典翻译(`DictBizCache` 未命中兜底 `DictCache`);
- 列表(`hcs_risk_detail`,列表查询时组装不落库)与表单实时提示(`riskTip`)同口径。
列表显示规则(前端 `customerRowRiskName`):高风险+黑名单 → "高风险、黑名单"(红);高风险、黑名单单项各显示(红);中风险(黄);低风险(绿);内部组织 → "无风险"(绿);无数据 → "-"。
## 6. 日志与排查
| 排查点 | 位置/关键字 |
|---|---|
| 刷新汇总 | 应用日志:`定时刷新客商风险:生效合同 X 份,覆盖客商 Y 个,刷新 Z 个…` |
| 单客商刷新失败 | `定时刷新客商风险失败:customerCode=…`(error 级,含堆栈) |
| 黑名单批量查询失败 | `定时刷新客商风险批量查询金蝶黑名单失败:size=…`(该批黑名单段缺失,下轮重刷) |
| 留痕写入失败 | `定时刷新客商风险留痕批量写入失败:size=…` |
| 全量留痕 | 表 `blade_hcs_check_log`(`biz_type=contract`,`check_type=risk`,`result=pass/fail/skip`,含 `trace_id`、`msg`) |
| 提审黑名单拦截 | 提审报错文案含"国资委黑名单中(失信类别:…,列入事由:…)" |
## 7. 常见操作
| 操作 | 方法 |
|---|---|
| 开启/关闭每日刷新 | Nacos 改 `refresh-enabled`(`@RefreshScope`,改后自动生效,无需重启) |
| 立即手动刷新一次 | 临时把 `refresh-cron` 改为近时刻(如 `0 5 14 * * ?`),执行后改回;或本地调用 `refreshCustomerRiskForActiveContracts()` |
| 补字典 | 执行 `03_blade_customer_risk_dict_20261030.sql`(幂等) |
| 某客商风险不更新 | 核对:客商名称是否与合同甲乙方**完全一致**(按名称匹配);客商是否内部组织(跳过);合同是否期限内且审核通过 |
| C101-1 不可用 | 刷新任务该客商记失败跳过,不影响其他客商;列表显示上轮数据 |
| A801-5 不可用 | 该批黑名单字段缺失(等级仍更新);提审黑名单校验会阻断提交(防止漏拦),恢复后重试 |
---
**注意**:黑名单/风险数据仅作展示与流程管控,强制安全校验在提审(A801-5 硬拦)、合同推送、付款提交链路的服务端事务内,前端展示不作为安全边界。
@@ -0,0 +1,201 @@
# 金蝶单据锁定与解锁说明(业务版)
> 业务域:正式结算单、开票申请、付款申请在「同步金蝶」成功后的单据锁定、金蝶侧解锁/删单通知、锁定失败自动补偿
> 核心规则:**单据推送金蝶成功后,本系统会请金蝶"锁单";锁定期间本系统对应单据被冻结,不能作废或改动。金蝶侧解锁或删单后,会通知本系统,本系统据此解除锁定或自动还原单据。**
> 最后更新:2026-10-30
---
## 一、为什么要锁单
一张单在 TMS 和金蝶各存一份。如果 TMS 推完单后继续改、继续作废,金蝶那边还是老单,就会出现"两套账"。
锁单就是把两边"绑住":
1. 推送成功后,本系统立即请求金蝶把这张单锁住(金蝶侧不允许随意改动);
2. 同时本系统把这边的单冻结(不能作废、不能改);
3. 金蝶那边解锁或删单后,会主动通知本系统,本系统再解除冻结或把单据还原。
锁定与否**不影响已推送成功的结果**:金蝶单一旦生成,不会因为锁单没成功而重复生成。
---
## 二、适用范围(总览)
| 业务单据 | 什么时候推送 | 金蝶侧单据 | 对应关系 |
| --- | --- | --- | --- |
| 正式结算单(应付) | 审批通过后系统自动推送,也可页面点「同步金蝶」 | 财务应付单 | 一张结算单 → 一张金蝶单 |
| 正式结算单(应收) | 同上 | 财务应收单 | 一张结算单 → 一张金蝶单 |
| 开票申请单 | 审批通过后系统自动推送,也可页面点「同步金蝶」 | 开票单 | 一张申请单 → **按发票张次 N 张金蝶单,逐张锁定** |
| 付款申请单 | 审批通过后系统自动推送(正式结算付款、预付款均适用),也可页面点「同步金蝶」 | 付款申请单 | 一张付款申请 → 一张金蝶单 |
| 收票单 | — | — | **暂未纳入锁定范围**(接口已预留) |
> 开票申请按"张"锁:一张申请里有几张发票,就有几条锁定记录,各张单独锁、单独补偿,互不影响。但只要其中任意一张被金蝶删除,整张开票申请会被作废(见场景三)。
---
## 三、页面上的"金蝶锁状态"怎么读
列表和详情页的「金蝶锁状态」列会显示以下标签,悬停可看原因或操作人:
| 标签 | 含义 | 单据能不能操作 | 业务该做什么 |
| --- | --- | --- | --- |
| **金蝶锁定中**(红) | 金蝶已锁单,单据被冻结 | 不能作废、不能改动(开票申请/付款申请点作废会提示"该单据已被金蝶锁定,不可修改";结算单本身"已同步金蝶"就不可编辑/作废) | 确实要改,先去金蝶侧解锁,等状态变为"金蝶锁单"后再处理 |
| **锁定失败·补偿中**(橙) | 金蝶单已生成,但"锁单"这一步没成功,系统正在自动重试 | 不建议作废或重建 | **不要作废单据**,等待自动补偿;着急可在页面点「同步金蝶」立即补锁 |
| **锁定失败·已达上限**(红) | 自动补偿已重试满 5 次仍未成功 | 同上 | 点「同步金蝶」立即补锁(会重新开始补偿);仍失败请把金蝶单号和失败原因给技术排查 |
| **金蝶删单**(红) | 金蝶侧把这张单删除了 | 结算单/开票申请已自动作废;付款申请转为"生成失败" | 结算单/开票申请:重新走业务流程;付款申请:核实后重新推送 |
| **金蝶锁单**(橙) | 金蝶侧解锁了,但单据还在 | 锁已解除,按单据自身状态规则操作 | 注意两边不再自动联动,改动/作废前先确认金蝶侧如何处理 |
| **结算调整重推**(橙) | 结算调整生成新单后,原单的旧锁自动解除 | 原单只做标记,不删不改 | 无需处理,以调整后的新单为准 |
| 空白 | 没有锁记录(从未推送,或锁定早已解除且无留痕) | 按单据自身状态规则操作 | — |
---
## 四、主流程(业务视角)
```
单据审批通过
└─ 系统自动推送金蝶(失败不影响审批结果)
├─ 推送失败 → 金蝶状态记"生成失败",可重推,不产生金蝶单
└─ 推送成功 → 回填金蝶单号 → 请求金蝶锁单
├─ 锁定成功 → 单据冻结(页面:金蝶锁定中)
└─ 锁定失败 → 系统每5分钟自动重锁,最多5次
(页面:锁定失败·补偿中 / 已达上限)
金蝶侧后续动作:
├─ 解锁(单据还在) → 通知本系统 → 解除锁定(页面:金蝶锁单)
└─ 删单 → 通知本系统 → 结算单/开票申请自动作废并还原
付款申请转"生成失败",等人工重推
```
---
## 五、场景一:推送成功后锁定
**触发方式**
1. 审批通过后系统自动推送(不需要人工点);
2. 页面手动点「同步金蝶」(补推、重推、补锁都走这里)。
**系统做了什么**
1. 推送成功即回填金蝶单号,随后逐张请求金蝶锁单;
2. 每张金蝶单对应一条锁定记录,先登记"待锁"再调金蝶,保证漏不掉;
3. 单张锁失败不影响其他张,也不影响主单的"已同步"状态。
**重复操作会怎样**
- 已经推送成功、已有金蝶单号的,再点「同步金蝶」不会重复生成金蝶单;
- 已锁定成功的单据不会重复锁。
**锁定期间的业务影响**
- 开票申请、付款申请:作废入口被拦截;
- 正式结算单:本身"已同步金蝶"就不能编辑、调整、作废,锁定期同样被拦截。
---
## 六、场景二:金蝶解锁(单据还在)
1. 金蝶侧对单据执行解锁后,通知本系统;
2. 本系统把锁定记录置为"已解锁",页面显示橙色「金蝶锁单」标签,悬停显示**谁在什么时间解锁**;
3. 本系统单据的业务状态**不会因此改变**(结算单仍是"已同步",开票申请/付款申请仍保持原审批状态);
4. 重复收到同一条解锁通知不会重复处理,也不会报错。
> 注意:解锁只解除"金蝶锁单"这一层限制。正式结算单即使解锁,仍受"已同步金蝶不可直接作废"的约束;要作废/调整需走结算调整,或让金蝶侧删单由系统自动作废。
---
## 七、场景三:金蝶删单(三种单据处理不同)
金蝶侧删除单据后,系统按单据类型分别处理:
| 业务单据 | 本系统处理 | 单据状态 | 后续 |
| --- | --- | --- | --- |
| 正式结算单 | 自动作废,并还原到推送前的同步信息:清空金蝶单号、金蝶内码、同步时间,同步状态改回"未同步" | 已作废(终态),当前节点"已作废" | 变更流水记录"金蝶删单回调自动废除",操作人显示金蝶侧操作人;需重新推单请新单重走流程 |
| 开票申请 | 自动作废,清空金蝶单号、同步时间,同步状态改回"未同步",并刷新关联结算单的开票状态 | 已作废(终态) | 操作流水记"金蝶删单回调作废",操作人为金蝶侧操作人;需重新开票请重新发起申请 |
| 付款申请 | **不作废源单**:金蝶状态由"已生成/付款中"改为"生成失败",清空金蝶单号、内码(原值留日志) | 审批状态不变 | **不自动重推**,人工核实后重新推送;页面显示红色「金蝶删单」标签,以便与普通推送失败区分 |
补充说明:
- 开票申请有多张金蝶单时,任意一张被删,**整张开票申请作废**;
- 付款申请只有"已生成/付款中"状态会转为"生成失败",已完成付款等终态不受影响;
- 结算单作废时会同步释放项目预付核销占用,避免残留;
- 重复的删单通知不会重复作废、重复还原。
---
## 八、场景四:锁定失败与自动补偿
**什么情况会锁定失败**:推送成功后,请求金蝶锁单时接口报错或超时。
**系统怎么处理**
1. 该张单据保留"锁定失败"记录并记录原因,页面显示橙色「锁定失败·补偿中」;
2. 定时任务自动重锁,默认每 5 分钟一轮,最多自动重试 5 次;
3. 5 次仍未成功,页面转为红色「锁定失败·已达上限」,不再自动重试。
**业务注意事项**
- **锁定失败不影响已推送成功的结果**,单据仍是"已同步金蝶",不会重复生成金蝶单;
- 补偿期间建议**先不要作废或重建单据**,避免本系统与金蝶不一致;
- 已达上限时,在页面点「同步金蝶」会立即补锁,并重新开始补偿计数;
- 仍失败时,请提供单据号、金蝶单号、页面上的失败原因给技术排查。
> 自动补偿是否开启由各环境配置决定(默认开启锁定、默认关闭定时补偿),如发现"一直没人补锁",请联系技术确认环境配置。
---
## 九、场景五:结算调整重推(本系统主动解锁)
已推送金蝶的正式结算单需要调整时,走结算调整:系统生成一张新的结算单并推送金蝶,**原单的旧锁自动解除**,页面显示橙色「结算调整重推」标签。
- 原单只加"已调整"标记,不删除、不改业务字段;
- 后续收付款、开票以新单为准;
- 这是本系统主动解锁,不是金蝶回调,操作人显示发起调整的人。
---
## 十、常见问题
**1. 单据显示"金蝶锁定中",我要改内容/作废怎么办?**
先到金蝶侧解锁,等本系统状态变成「金蝶锁单」后再处理。正式结算单还要注意"已同步金蝶"本身就不能直接作废,需要走结算调整或由金蝶删单。
**2. 金蝶那边已经解锁了,为什么本系统还不能作废?**
解锁只解除"金蝶锁单",不改变单据的业务状态。结算单仍受"已同步不可作废"限制;开票申请/付款申请解锁后恢复可作废,但作废不会反向同步金蝶,请确认金蝶侧单据的处理方式。
**3. 显示"金蝶删单"是什么意思?**
金蝶侧把单据删了。结算单、开票申请已自动作废,需要重新走流程;付款申请没有作废,但变成了"生成失败",核实后重新推送即可。
**4. 显示"锁定失败"要不要人工处理?**
先等系统自动补偿(每 5 分钟一次,最多 5 次)。已达上限时点「同步金蝶」立即补锁;补偿期间不要作废或重建单据。
**5. 金蝶重复发解锁/删单通知,会不会把单据作废两次?**
不会。系统按"当前是否仍锁定/是否已作废"判断,重复通知自动跳过。
**6. 开票申请有多张发票,其中一张锁失败怎么办?**
各张独立锁定、独立补偿,其他张照常冻结。页面会提示哪一张失败;该张补偿成功前,整张申请仍按"锁定失败"提示。
**7. 已推送的单据能不能直接在 TMS 作废?**
不能。开票申请、付款申请在锁定中被拦截;正式结算单已同步即不可作废。要么金蝶侧删单由系统自动作废,要么走结算调整生成新单。
---
## 十一、留痕在哪里查
| 想查什么 | 在哪看 |
| --- | --- |
| 单据当前锁状态、失败原因、重试次数、解锁操作人与时间 | 列表/详情「金蝶锁状态」列,悬停查看提示 |
| 结算单被金蝶删单自动作废的过程 | 结算单变更流水(内容含"金蝶删单回调自动废除") |
| 开票申请被金蝶删单自动作废的过程 | 开票申请操作流水(动作"金蝶删单回调作废") |
| 付款申请解锁原因 | 付款申请金蝶失败原因("金蝶侧单据已删除解锁……等待重新推送") |
| 每张金蝶单的完整锁定/解锁明细 | 技术侧锁定记录表 `blade_kingdee_bill_lock`(一张金蝶单一行) |
---
## 十二、口径边界(给管理员/技术)
1. 锁定总开关关闭时:推送后不锁单,金蝶的解锁/删单通知只应答、不处理;
2. 补偿定时任务需按环境开启,默认每 5 分钟一轮,重试上限 5 次;
3. 金蝶回调为无登录态公开接口,需保持网关白名单配置有效(异常时金蝶会重试);
4. 锁单与解锁均为逐张调用,单张成败互不影响;解锁回调整批处理,任一张还原失败则整批回滚、由金蝶重试闭环;
5. 后续新增单据(如收票单)接入锁定时,锁定状态、解锁标识与本文口径保持一致即可复用。
+5
View File
@@ -159,6 +159,11 @@ thirdParty:
# 数据来源系统编码(推送金蝶公共参数:客商、付款申请等统一使用),默认 WLTMS(运输TMS)
srcSys: ${BFI_SRC_SYS:WLTMS}
# 金蝶黑名单查询(A801-5 客商提审拦截):禁止交易类(A)始终拦截;
# 风险警示类(B)默认放行告警,开启后一并拦截
blacklist:
blockRiskWarning: ${BFI_BLACKLIST_BLOCK_RISK_WARNING:false}
# 应付/应收/收票单分录物料映射(A102-2/A302-2/A303-2 共用,未配置使用代码默认值):
# 运输类按项目业务模式映射——国内运输按运单运输方式映射、国际运输映射国际货代服务;
# 装卸大类及手动添加的非运费杂费映射装卸物料
+4
View File
@@ -124,6 +124,10 @@ thirdParty:
language: ${BFI_LANGUAGE:zh_CN}
# 数据来源系统编码(推送金蝶公共参数:客商、付款申请等统一使用),默认 WLTMS(运输TMS)
srcSys: ${BFI_SRC_SYS:WLTMS}
# 金蝶黑名单查询(A801-5 客商提审拦截):禁止交易类(A)始终拦截;
# 风险警示类(B)默认放行告警,开启后一并拦截
blacklist:
blockRiskWarning: ${BFI_BLACKLIST_BLOCK_RISK_WARNING:false}
# 付款申请推送配置(A103-3 付款申请保存)
payApply:
# 单据类型编码:ap_payapply_BT_S 采购付款申请、ap_payapply_oth_BT_S 其他付款申请
+10
View File
@@ -246,6 +246,9 @@ blade:
- /hcs/projectLegal/result
- /blade-transport/hcs/contractKingdee/result
- /hcs/contractKingdee/result
# HCS 合规附件下载(C103-5 代理):前端附件面板凭合规附件ID 查看/下载,fdId 32位随机不可枚举,免登免授权
- /blade-transport/hcs/attachment/download/**
- /hcs/attachment/download/**
#授权认证配置
auth:
- method: ALL
@@ -298,6 +301,13 @@ blade:
- method: POST
pattern: /hcs/contractKingdee/result
expression: "permitAll()"
# HCS 合规附件下载(C103-5 代理):前端附件面板凭合规附件ID 查看/下载,fdId 32位随机不可枚举,免登免授权
- method: GET
pattern: /blade-transport/hcs/attachment/download/**
expression: "permitAll()"
- method: GET
pattern: /hcs/attachment/download/**
expression: "permitAll()"
#基础认证配置
basic:
- method: ALL
+8
View File
@@ -61,6 +61,10 @@ thirdParty:
# 数据来源系统编码(推送金蝶公共参数:客商、付款申请等统一使用),默认 WLTMS(运输TMS)
srcSys: ${BFI_SRC_SYS:WLTMS}
# 金蝶黑名单查询(A801-5 客商提审拦截):禁止交易类(A)始终拦截;
# 风险警示类(B)默认放行告警,开启后一并拦截
blacklist:
blockRiskWarning: ${BFI_BLACKLIST_BLOCK_RISK_WARNING:false}
# 应付/应收/收票单分录物料映射(A102-2/A302-2/A303-2 共用,未配置使用代码默认值):
# 运输类按项目业务模式映射——国内运输按运单运输方式映射、国际运输映射国际货代服务;
# 装卸大类及手动添加的非运费杂费映射装卸物料
@@ -245,6 +249,10 @@ thirdParty:
risk:
check-on-contract: ${HCS_RISK_CHECK_ON_CONTRACT:true}
check-on-payment: ${HCS_RISK_CHECK_ON_PAYMENT:true}
# 客商风险每日定时刷新开关(刷新合同期限内生效合同关联客商并落库,支撑列表展示与筛选,默认关)
refresh-enabled: ${HCS_RISK_REFRESH_ENABLED:false}
# 客商风险刷新调度 cron,默认每天 02:30(错开金蝶客商同步 02:00)
refresh-cron: ${HCS_RISK_REFRESH_CRON:0 30 2 * * ?}
# 黑名单是否阻断(合同置 failed / 付款提交拦截)
# block-blacklist: ${HCS_RISK_BLOCK_BLACKLIST:true}
# 额度校验(C106-1,一期暂不对接)
+8 -1
View File
@@ -46,6 +46,11 @@ CREATE TABLE `blade_customer_archive` (
`kingdee_status` varchar(20) NOT NULL DEFAULT 'none' COMMENT '金蝶协同状态:none未推送/exist金蝶已有/synced已推送/failed推送失败',
`kingdee_fail_reason` varchar(500) NULL DEFAULT NULL COMMENT '金蝶推送失败原因',
`kingdee_sync_time` datetime NULL DEFAULT NULL COMMENT '金蝶推送时间',
`hcs_risk_level` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '合规客商风险等级(C101-1,0=低风险/1=中风险/2=高风险)',
`kingdee_black_status` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '合规客商黑名单状态(C101-1,yes=是/no=否/handing=处理中)',
`hcs_risk_time` datetime DEFAULT NULL COMMENT '客商风险最近查询时间(C101-1)',
`kingdee_black_category` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '金蝶黑名单失信类别(A801-5 awrp_combofield_title,缺失兜底 awrp_combofield)',
`kingdee_black_reason` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '金蝶黑名单列入事由(A801-5 awrp_textareafield)',
`create_user` bigint NULL DEFAULT NULL COMMENT '创建人',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
@@ -58,7 +63,9 @@ CREATE TABLE `blade_customer_archive` (
UNIQUE KEY `uk_customer_archive_credit_code` (`tenant_id`, `unified_credit_code`, `is_deleted`) USING BTREE,
KEY `idx_customer_archive_access` (`tenant_id`, `access_type`, `approval_status`) USING BTREE,
KEY `idx_customer_archive_name` (`tenant_id`, `full_name`, `short_name`) USING BTREE,
KEY `idx_kingdee_status` (`kingdee_status`) USING BTREE
KEY `idx_kingdee_status` (`kingdee_status`) USING BTREE,
KEY `idx_hcs_risk_level` (`hcs_risk_level`) USING BTREE,
KEY `idx_kingdee_black_status` (`kingdee_black_status`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '客商档案';
-- ----------------------------
@@ -0,0 +1,5 @@
-- 开票申请金蝶发票结果表新增履约开票记录推送字段(C108-1:金蝶开票完成后每张发票推送一条履约开票记录)
ALTER TABLE `blade_invoice_application_invoice`
ADD COLUMN `hcs_perf_fd_id` varchar(64) DEFAULT NULL COMMENT '履约开票记录ID(C108-1返回,非空即已推送)' AFTER `raw_json`,
ADD COLUMN `hcs_perf_retry_count` int DEFAULT NULL COMMENT '履约开票记录推送失败重试次数' AFTER `hcs_perf_fd_id`,
ADD COLUMN `hcs_perf_sync_msg` varchar(512) DEFAULT NULL COMMENT '履约开票记录最近推送失败原因' AFTER `hcs_perf_retry_count`;
@@ -0,0 +1,5 @@
-- 收票登记结算单分摊表新增履约收票记录推送字段(C108-1:收票单每条结算信息推送一条履约收票记录)
ALTER TABLE `blade_invoice_receipt_settlement`
ADD COLUMN `hcs_perf_fd_id` varchar(64) DEFAULT NULL COMMENT '履约收票记录ID(C108-1返回,非空即已推送)' AFTER `allocated_invoice_amount`,
ADD COLUMN `hcs_perf_retry_count` int DEFAULT NULL COMMENT '履约收票记录推送失败重试次数' AFTER `hcs_perf_fd_id`,
ADD COLUMN `hcs_perf_sync_msg` varchar(512) DEFAULT NULL COMMENT '履约收票记录最近推送失败原因' AFTER `hcs_perf_retry_count`;
@@ -0,0 +1,17 @@
-- 付款管理:金蝶推送失败原因留档展示
-- 新增 kingdee_fail_reason:markKingdeeSyncFailed 落"生成失败"时同步落失败原因,
-- 列表"金蝶单据状态"列悬浮提示展示;重推成功转 synced 后残留原因不再回显
-- 以下结构升级支持重复执行
SET @ddl_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `blade_payment_application` ADD COLUMN `kingdee_fail_reason` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''金蝶推送失败原因'' AFTER `kingdee_status`',
'SELECT 1')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'blade_payment_application'
AND COLUMN_NAME = 'kingdee_fail_reason'
);
PREPARE ddl_stmt FROM @ddl_sql;
EXECUTE ddl_stmt;
DEALLOCATE PREPARE ddl_stmt;
@@ -0,0 +1,11 @@
-- 付款特批结果回传附件(paymentLegal/result 回调 fileUrl=合规附件ID):
-- blade_payment_application 追加合规特批结果附件ID 字段,供 C103-5 下载与金蝶附件联带上传。
-- 通过 information_schema 判断字段是否存在,可重复执行。
SET @db_name = DATABASE();
SET @sql = IF(
EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = @db_name AND table_name = 'blade_payment_application' AND column_name = 'hcs_spec_attach_fd_id'),
'SELECT 1',
'ALTER TABLE blade_payment_application ADD COLUMN hcs_spec_attach_fd_id varchar(128) DEFAULT NULL COMMENT ''合规付款特批结果附件ID(paymentLegal/result 回调 fileUrl,C103-5 下载入参)'''
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
@@ -0,0 +1,87 @@
-- 客商档案:合规客商风险(C101-1)落库字段
-- 用途:每日定时刷新合同期限内生效合同关联客商的风险等级/黑名单状态并落库,支持列表按客商风险筛选
-- 口径:内部组织客商默认无风险不落值;筛选值映射 blacklist=黑名单/high=高风险/middle=中风险/low=低风险
-- 幂等可重复执行:逐列/逐索引查 information_schema,已存在则跳过
-- ① 列 hcs_risk_level
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND COLUMN_NAME = 'hcs_risk_level') = 0,
'ALTER TABLE `blade_customer_archive` ADD COLUMN `hcs_risk_level` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''合规客商风险等级(C101-1,0=低风险/1=中风险/2=高风险)'' AFTER `kingdee_sync_time`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ② 列 kingdee_black_status(C101-1 黑名单状态;此前误用 hcs_ 前缀,存在旧列时 CHANGE 改名迁移数据)
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND COLUMN_NAME = 'kingdee_black_status') = 0,
(SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND COLUMN_NAME = 'hcs_black_status') > 0,
'ALTER TABLE `blade_customer_archive` CHANGE COLUMN `hcs_black_status` `kingdee_black_status` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''合规客商黑名单状态(C101-1,yes=是/no=否/handing=处理中)''',
'ALTER TABLE `blade_customer_archive` ADD COLUMN `kingdee_black_status` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''合规客商黑名单状态(C101-1,yes=是/no=否/handing=处理中)'' AFTER `hcs_risk_level`')),
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ③ 列 hcs_risk_time
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND COLUMN_NAME = 'hcs_risk_time') = 0,
'ALTER TABLE `blade_customer_archive` ADD COLUMN `hcs_risk_time` datetime DEFAULT NULL COMMENT ''客商风险最近查询时间(C101-1)'' AFTER `kingdee_black_status`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ④ 索引 idx_hcs_risk_level
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND INDEX_NAME = 'idx_hcs_risk_level') = 0,
'ALTER TABLE `blade_customer_archive` ADD INDEX idx_hcs_risk_level (hcs_risk_level)',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ⑤ 索引 idx_kingdee_black_status
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND INDEX_NAME = 'idx_kingdee_black_status') = 0,
'ALTER TABLE `blade_customer_archive` ADD INDEX idx_kingdee_black_status (kingdee_black_status)',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ⑥ 旧索引清理:② CHANGE 改名后旧索引 idx_hcs_black_status 会自动跟随新列残留,若存在则删除(由 idx_kingdee_black_status 取代)
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND INDEX_NAME = 'idx_hcs_black_status') > 0,
'ALTER TABLE `blade_customer_archive` DROP INDEX idx_hcs_black_status',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ⑥ 列 hcs_black_category / hcs_black_reason(A801-5 金蝶黑名单原始字段:失信类别、列入事由,明细文案由后台组装)
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND COLUMN_NAME = 'kingdee_black_category') = 0,
'ALTER TABLE `blade_customer_archive` ADD COLUMN `kingdee_black_category` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''金蝶黑名单失信类别(A801-5 awrp_combofield_title,缺失兜底 awrp_combofield)'' AFTER `hcs_risk_time`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_customer_archive' AND COLUMN_NAME = 'kingdee_black_reason') = 0,
'ALTER TABLE `blade_customer_archive` ADD COLUMN `kingdee_black_reason` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''金蝶黑名单列入事由(A801-5 awrp_textareafield)'' AFTER `kingdee_black_category`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
@@ -0,0 +1,43 @@
-- 开票申请 / 正式结算单 / 结算调整单:金蝶推送失败原因留档展示
-- markKingdeeSyncFailed 落"同步失败"时同步落失败原因,列表"金蝶单据状态"列悬浮提示展示;
-- 重推成功转 synced 后残留原因不再回显。付款管理 blade_payment_application 已单独处理(20261028)
-- 以下结构升级支持重复执行(三张表逐一判断)
SET @ddl_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `blade_invoice_application` ADD COLUMN `kingdee_fail_reason` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''金蝶推送失败原因'' AFTER `kingdee_status`',
'SELECT 1')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'blade_invoice_application'
AND COLUMN_NAME = 'kingdee_fail_reason'
);
PREPARE ddl_stmt FROM @ddl_sql;
EXECUTE ddl_stmt;
DEALLOCATE PREPARE ddl_stmt;
SET @ddl_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `blade_formal_settlement` ADD COLUMN `kingdee_fail_reason` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''金蝶推送失败原因'' AFTER `kingdee_sync_status`',
'SELECT 1')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'blade_formal_settlement'
AND COLUMN_NAME = 'kingdee_fail_reason'
);
PREPARE ddl_stmt FROM @ddl_sql;
EXECUTE ddl_stmt;
DEALLOCATE PREPARE ddl_stmt;
SET @ddl_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `blade_settlement_adjustment` ADD COLUMN `kingdee_fail_reason` varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''金蝶推送失败原因'' AFTER `kingdee_sync_status`',
'SELECT 1')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'blade_settlement_adjustment'
AND COLUMN_NAME = 'kingdee_fail_reason'
);
PREPARE ddl_stmt FROM @ddl_sql;
EXECUTE ddl_stmt;
DEALLOCATE PREPARE ddl_stmt;
@@ -0,0 +1,89 @@
-- 客商风险筛选字典 customer_risk(客商档案列表搜索栏「客商风险」下拉)。
-- dict_key=筛选值(与后端列表筛选入参一致:blacklist/high/middle/low),dict_value=展示名称。
-- 字典缺失时前端保留固定兜底选项,落库后各环境与前端兜底保持一致;id 由 UUID_SHORT() 动态生成,不写死,幂等可重复执行。
-- ① 字典父项
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000', 0, 'customer_risk', '-1', '客商风险', 1, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'customer_risk' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0
);
-- ② 子项:黑名单
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000',
(SELECT id FROM blade_dict_biz WHERE code = 'customer_risk' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0 LIMIT 1),
'customer_risk', 'blacklist', '黑名单', 1, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'customer_risk' AND dict_key = 'blacklist' AND tenant_id = '000000' AND is_deleted = 0
);
-- ③ 子项:高风险
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000',
(SELECT id FROM blade_dict_biz WHERE code = 'customer_risk' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0 LIMIT 1),
'customer_risk', 'high', '高风险', 2, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'customer_risk' AND dict_key = 'high' AND tenant_id = '000000' AND is_deleted = 0
);
-- ④ 子项:中风险
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000',
(SELECT id FROM blade_dict_biz WHERE code = 'customer_risk' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0 LIMIT 1),
'customer_risk', 'middle', '中风险', 3, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'customer_risk' AND dict_key = 'middle' AND tenant_id = '000000' AND is_deleted = 0
);
-- ⑤ 子项:低风险
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000',
(SELECT id FROM blade_dict_biz WHERE code = 'customer_risk' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0 LIMIT 1),
'customer_risk', 'low', '低风险', 4, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'customer_risk' AND dict_key = 'low' AND tenant_id = '000000' AND is_deleted = 0
);
-- ⑥ 客商风险等级字典 risk_level(C101-1 风险等级翻译,dictKey=等级 0/1/2):父项
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000', 0, 'risk_level', '-1', '客商风险等级', 1, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'risk_level' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0
);
-- ⑦ 子项:低风险(0)
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000',
(SELECT id FROM blade_dict_biz WHERE code = 'risk_level' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0 LIMIT 1),
'risk_level', '0', '低风险', 1, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'risk_level' AND dict_key = '0' AND tenant_id = '000000' AND is_deleted = 0
);
-- ⑧ 子项:中风险(1)
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000',
(SELECT id FROM blade_dict_biz WHERE code = 'risk_level' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0 LIMIT 1),
'risk_level', '1', '中风险', 2, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'risk_level' AND dict_key = '1' AND tenant_id = '000000' AND is_deleted = 0
);
-- ⑨ 子项:高风险(2)
INSERT INTO blade_dict_biz (id, tenant_id, parent_id, code, dict_key, dict_value, sort, remark, is_sealed, status, is_deleted)
SELECT UUID_SHORT(), '000000',
(SELECT id FROM blade_dict_biz WHERE code = 'risk_level' AND dict_key = '-1' AND tenant_id = '000000' AND is_deleted = 0 LIMIT 1),
'risk_level', '2', '高风险', 3, NULL, 0, 1, 0
WHERE NOT EXISTS (
SELECT 1 FROM blade_dict_biz
WHERE code = 'risk_level' AND dict_key = '2' AND tenant_id = '000000' AND is_deleted = 0
);
@@ -0,0 +1,32 @@
-- 合同表黑名单状态列改 kingdee_ 前缀(黑名单数据归金蝶口径,与客商档案表字段命名统一):
-- blade_contract_manage.hcs_black_status -> kingdee_black_status
-- blade_contract_change.hcs_black_status -> kingdee_black_status
-- 幂等可重复执行:新列不存在时,旧列存在则 CHANGE 改名迁移数据,否则新增;旧索引自动跟随列名,无需处理。
-- ① blade_contract_manage
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_manage' AND COLUMN_NAME = 'kingdee_black_status') = 0,
(SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_manage' AND COLUMN_NAME = 'hcs_black_status') > 0,
'ALTER TABLE `blade_contract_manage` CHANGE COLUMN `hcs_black_status` `kingdee_black_status` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''合规客商黑名单状态(C101-1,任一方黑名单记是)''',
'ALTER TABLE `blade_contract_manage` ADD COLUMN `kingdee_black_status` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''合规客商黑名单状态(C101-1,任一方黑名单记是)'' AFTER `hcs_risk_level`')),
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ② blade_contract_change
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_change' AND COLUMN_NAME = 'kingdee_black_status') = 0,
(SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_change' AND COLUMN_NAME = 'hcs_black_status') > 0,
'ALTER TABLE `blade_contract_change` CHANGE COLUMN `hcs_black_status` `kingdee_black_status` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''合规客商黑名单状态(展示用)''',
'ALTER TABLE `blade_contract_change` ADD COLUMN `kingdee_black_status` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''合规客商黑名单状态(展示用)'' AFTER `hcs_risk_level`')),
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
@@ -0,0 +1,54 @@
-- 合同表移除客商风险留痕列(风险展示改为列表/详情实时关联客商档案组装,不再落库):
-- blade_contract_manage DROP hcs_risk_level / kingdee_black_status / hcs_risk_time
-- blade_contract_change DROP hcs_risk_level / kingdee_black_status
-- 幂等可重复执行:列存在才 DROP。
-- ① blade_contract_manage.hcs_risk_level
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_manage' AND COLUMN_NAME = 'hcs_risk_level') > 0,
'ALTER TABLE `blade_contract_manage` DROP COLUMN `hcs_risk_level`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ② blade_contract_manage.kingdee_black_status
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_manage' AND COLUMN_NAME = 'kingdee_black_status') > 0,
'ALTER TABLE `blade_contract_manage` DROP COLUMN `kingdee_black_status`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ③ blade_contract_manage.hcs_risk_time
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_manage' AND COLUMN_NAME = 'hcs_risk_time') > 0,
'ALTER TABLE `blade_contract_manage` DROP COLUMN `hcs_risk_time`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ④ blade_contract_change.hcs_risk_level
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_change' AND COLUMN_NAME = 'hcs_risk_level') > 0,
'ALTER TABLE `blade_contract_change` DROP COLUMN `hcs_risk_level`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ⑤ blade_contract_change.kingdee_black_status
SET @ddl = (SELECT IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'blade_contract_change' AND COLUMN_NAME = 'kingdee_black_status') > 0,
'ALTER TABLE `blade_contract_change` DROP COLUMN `kingdee_black_status`',
'SELECT 1'));
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
@@ -0,0 +1,16 @@
-- 客商档案:新增供应商编码字段
-- 新增 supplier_code:金蝶A901-1供应商查询返回number,新增/同步客商时落库,金蝶单据推送直接复用,不再实时查接口
-- 以下结构升级支持重复执行
SET @ddl_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `blade_customer_archive` ADD COLUMN `supplier_code` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''供应商编码(金蝶A901-1供应商查询返回number)'' AFTER `customer_code`',
'SELECT 1')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'blade_customer_archive'
AND COLUMN_NAME = 'supplier_code'
);
PREPARE ddl_stmt FROM @ddl_sql;
EXECUTE ddl_stmt;
DEALLOCATE PREPARE ddl_stmt;