From 2afc18b8de2de67986019db2e274913dafa138d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Thu, 22 Oct 2026 16:25:10 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9EHcsPushTask=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E9=80=BB=E8=BE=91=E4=B8=8E=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E6=A2=B3=E7=90=86=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...6-10-22-HcsPushTask定时任务逻辑与流程梳理.md | 210 ++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 doc/docs/hcs合同/2026-10-22-HcsPushTask定时任务逻辑与流程梳理.md diff --git a/doc/docs/hcs合同/2026-10-22-HcsPushTask定时任务逻辑与流程梳理.md b/doc/docs/hcs合同/2026-10-22-HcsPushTask定时任务逻辑与流程梳理.md new file mode 100644 index 00000000..97e6ee15 --- /dev/null +++ b/doc/docs/hcs合同/2026-10-22-HcsPushTask定时任务逻辑与流程梳理.md @@ -0,0 +1,210 @@ +# HcsPushTask 定时任务逻辑与流程梳理 + +> 代码:`blade-service/blade-transport/src/main/java/org/springblade/transport/task/HcsPushTask.java` +> 定位:HCS(合同合规系统)合规推送的**兜底定时扫描**。审批代码零埋点——扫描只认「审批通过 + 待同步/失败未超限」的单据,与审批入口(/approve、MK 回调)无关;失败由下轮扫描自动补偿,超限仅人工重推(D7)。 + +--- + +## 1. 总体机制 + +| 机制 | 说明 | +| --- | --- | +| 调度 | 五类任务独立 `@Scheduled`,cron 走 Nacos `thirdParty.hcs.push.{bizType}.cron`,默认每 5 分钟、分钟位 0/1/2/3/4 错峰,避免同刻并发与 HCS 接口流量尖峰 | +| 开关 | 每任务独立开关 `thirdParty.hcs.push.{bizType}.sync-enabled`(默认关,灰度打开);未开启时本轮直接跳过 | +| 防重 | 按业务类型隔离的 Redis 分布式锁(`blade:third:hcs:push:task:lock:{bizType}`),setIfAbsent 抢锁 + 持有值比对释放,TTL 240s;多实例部署时同任务只有一台执行,任务间互不阻塞 | +| 批量 | `batch-size`(单轮扫描条数上限)、`max-retry`(重试上限)为全局配置 `thirdParty.hcs.push.*` | +| 复用 | 扫描与推送逻辑(pushUnsyncedXxx)同时供手动端点 HcsSyncController 复用(页面"推送合规/重推"按钮) | + +--- + +## 2. 五类任务总览 + +| bizType | 任务 | 默认 cron | 覆盖合规接口 | 推送 Support | +| --- | --- | --- | --- | --- | +| project | 项目立项 | `0 */5 * * * ?` | C102-1/2/3 | HcsProjectSyncSupport | +| contract | 合同(含特批兜底) | `0 1/5 * * * ?` | C101-1、C103-1/11/3/4/9、C103-2 附件 | HcsContractSyncSupport + HcsContractSpecSyncSupport | +| payment | 付款链(特批+履约) | `0 2/5 * * * ?` | C106-3/4、C108-1/2 | HcsPaymentSyncSupport(编排)→ HcsSpecPaySyncSupport / HcsPerfRecordSyncSupport | +| invoice-application | 开票登记 | `0 3/5 * * * ?` | C111-1/2/3、C103-2 附件 | HcsInvoiceRegSyncSupport | +| invoice-receipt | 收票单 | `0 4/5 * * * ?` | C109-1/2、C103-2 附件 | HcsReceiptBillSyncSupport | + +--- + +## 3. 统一扫描条件(状态口径) + +各任务扫描 SQL 口径一致(payment/invoice 两类只认 `approved`,不含变更通过): + +1. **审批状态**:`approvalStatus IN (approved, change_approved)`(合同/项目);付款、开票、收票仅 `approved`; +2. **同步状态**:`hcs_sync_status IN (unsynced, failed)`; +3. **重试门槛**:`hcs_retry_count IS NULL OR < max-retry`; +4. `limit batch-size` 控制单轮量。 + +逐条推送:成功由 Support 内 `markSynced` 回填(`hcs_fd_id` 合规ID、`synced`、清零重试、记 `hcs_sync_time/msg`);异常由任务统一 `markFailed`(`failed`、重试+1、失败原因截断 500 字落 `hcs_sync_msg`)。 + +### 同步状态机(hcs_sync_status) + +``` +unsynced(审批通过初始态) + │ 扫描推送成功 + ├──→ synced(终态,回填 hcs_fd_id) + │ 推送异常 + └──→ failed(重试+1) + │ 未超限:下轮扫描自动补偿 + ├──→ synced + └──→ 超限:停留 failed,仅人工重推(重推重置 unsynced + 清零计数) +``` + +--- + +## 4. 各任务流程与接口明细 + +### 4.1 项目立项(C102) + +**流程**(HcsProjectSyncSupport.pushProject): + +1. 无合规ID(首推)→ **C102-3 列表判重**(conditions=`fd_num=项目编号`),命中直接回填 fdId 置 synced,跳过新建; +2. 未命中 → **C102-1 新建**(模板编码取配置 `project.template-code`,操作 drafter_submit 直接提交,金额万元×10000 转元),回填 fdId; +3. 已有合规ID(变更单 change_approved)→ **C102-2 更新**(formData.fdId 必填)。 + +| 接口 | 用途 | +| --- | --- | +| C102-3 | 项目立项列表查询(判重) | +| C102-1 | 项目立项新建 | +| C102-2 | 项目立项更新 | + +**附带回调**(非本任务,同 Support):合规 `projectLegal/result` 推送(D902)→ 回填金蝶项目ID/编号(kingdeeId/kingdeeNumber),原文留痕 `blade_hcs_check_log`。 + +### 4.2 合同(C103)—— 最复杂链路 + +任务为组合动作:`pushUnsyncedContracts()` + `hcsContractSpecSyncSupport.syncProcessingSpecResults()`(特批结果查询兜底)。 + +**推送流程**(HcsContractSyncSupport.pushContract,按序): + +| 步骤 | 动作 | 接口 | +| --- | --- | --- | +| ⓪ 门禁 | 特批中(hcsSpecStatus=processing)的合同跳过推送,等待结果恢复;need 不拦截(重推时随报文自愈转特批) | — | +| ① 风险校验 | 开关 `contract.require-risk-check`;甲乙双方各查一次 C101-1(**不跳过内部组织客商**,仅名称反查不到编号记 skip;等级取甲方优先非空值、黑名单任一方为是),留痕 hcs_risk_* 字段与 check_log;**仅留痕不阻断**,高风险/黑名单触发后续自动特批。注:提交环节的阻断校验在合同/付款 submit 时已完成(见 §6 C101-1 全景),此步是推送链路的复核留痕 | **C101-1** 客商风险查询 | +| ② 附件转传 | 开关 `attachment.transfer-enabled`;合同主文件→eopCdraftSign、特批附件→eopCdraftSpecial、其它→eopCdraftOther;转传命中映射表(blade_hcs_attachment_sync)直接复用 | **C103-2** 附件上传 | +| ③ 判重 | conditions=`fdNumber=合同编号`,命中回填 fdId 置 synced | **C103-3** 合同列表查询 | +| ④ 起草/更新 | 首推 **C103-1 合同发起**(fdFieldJson 模板字段 + signer 相对方 + 顶层 attachment 挂载;高风险/黑名单或强制开关时报文带 `fdSepcailContract=true` 在合规侧走特批);变更单走 **C103-11 合同更新**(顶层 fdId 定位) | **C103-1** / **C103-11** | +| ⑤ 履约计划 | 开关 `exe-stage.sync-enabled`;C103-9 行级同步(add/update/delete 标记),仅依赖 hcs_fd_id、失败不受特批门禁阻塞 | **C103-9** 履约规则同步(exeplanAdd) | +| ⑥ 挂起特批 | 风险客商(且特批无终态)→ hcsSpecStatus=processing、currentNode="特批审核",等待结果 | — | + +**特批结果闭环**(HcsContractSpecSyncSupport,三条入口等效): + +1. 合规推送 `contractLegal/result`:success=true → 恢复"审批通过"(金蝶合同ID回填 kingdee_id,特批 approved);false → 联动合同审批驳回(rejected),走重新提交闭环; +2. **定时 C103-4 兜底**(本任务每轮执行):扫描特批中(processing 且已有 hcs_fd_id)的合同(limit 50),查合同详情 fdApprovalStatus——`approved` 联动通过、`approvalinvalid` 联动驳回、其余等待中跳过; +3. 人工确认(页面按钮,与推送等效)。 + +| 接口 | 用途 | +| --- | --- | +| C101-1 | 客商风险等级/黑名单查询(甲乙各一次) | +| C103-2 | 合同附件上传(multipart) | +| C103-3 | 合同列表查询(判重) | +| C103-1 | 合同发起(新建,返回 fdContractId 必须持久化) | +| C103-11 | 合同更新(变更单) | +| C103-9 | 履约规则/计划行级同步 | +| C103-4 | 合同详情查询(特批结果兜底,fdId 定位) | + +**附带回调**(非本任务):`contractKingdee/result` 推送(D903)→ 回填金蝶合同ID,仅留痕不联动审批。 + +### 4.3 付款链(C106-3 特批 + C108 履约) + +**流程**(HcsPaymentSyncSupport.pushPayment,编排组件): + +1. **① 结算付款特批**:仅当 `hcs_spec_status=need`(提交时高风险/黑名单须特批附件,或额度超额标记)时触发——未发起走 **C106-3 特批发起**(返回双层嵌套 data.data.fdId → hcs_spec_fd_id,状态置 processing),已发起走 **C106-4 特批更新**;发起后挂起 currentNode="特批审核"; +2. **② 履约记录**:开关 `perf-record.sync-enabled`(**一期默认关**,关闭时直接置 synced)——无记录ID走 **C108-1 新建**(回填 hcs_perf_fd_id),实际付款推进走 **C108-2 更新**。 + +特批结果入口(非扫描,同 Support):合规 `paymentLegal/result` 推送(requestId=付款申请ID,APPROVED/REJECTED)或人工确认——通过恢复"审批通过"放行,驳回联动付款审批驳回(returned)。 + +| 接口 | 用途 | +| --- | --- | +| C106-3 | 结算付款特批流程发起 | +| C106-4 | 结算付款特批流程更新 | +| C108-1 | 履约记录新建 | +| C108-2 | 履约记录更新 | + +### 4.4 开票登记(C111) + +**流程**(HcsInvoiceRegSyncSupport.pushInvoiceRegistration): + +1. 无合规ID → **C111-1 列表判重**(conditions=`fdNumber=申请单号`),命中回填; +2. 未命中 → **C111-2 新增**(合同编号经"开票申请→应收结算关联→正式结算单"链路回溯,回溯不到直接失败;币种按 RMB 取 `invoice.currency-id-mapping`;附件经 C103-2 转传);若金蝶已开票完成(kingdeeStatus=invoiced)则紧接着回填票据日期; +3. 已有合规ID(金蝶开票完成后回写置待同步)→ **C111-3 更新**(回填 fdBillDate/fdStatus=已开票)。 + +| 接口 | 用途 | +| --- | --- | +| C111-1 | 开票登记列表查询(判重) | +| C111-2 | 开票登记新增 | +| C111-3 | 开票登记更新(票据日期/状态回填) | +| C103-2 | 附件转传 | + +### 4.5 收票单(C109) + +**流程**(HcsReceiptBillSyncSupport.pushReceiptBill): + +1. 无合规ID → **C109-1 新建**(税率 TMS 整数÷100 转小数;合同主题/编号经"收票→结算关联→结算单合同"回溯,回溯不到取页面人工补录 hcs_contract_id/hcs_contract_no;附件挂 fdEntityKey=fd_attach;返回**双层嵌套** data.data.fdId)→ 立即持久化 hcs_fd_id → 任务层 markSynced; +2. 已有合规ID → **C109-2 更新**(顶层 fdId 必填,只传变更字段、不带文档状态)。 + +注:收票单是唯一在任务循环内显式调用 `markSynced` 的(Support 内只持久化 fdId),其余任务由 Support 内部回填。 + +| 接口 | 用途 | +| --- | --- | +| C109-1 | 收票单新建 | +| C109-2 | 收票单更新 | +| C103-2 | 附件转传 | + +--- + +## 5. 状态字段速查 + +| 字段 | 取值 | 含义 | +| --- | --- | --- | +| approvalStatus | draft/reviewing/withdrawn/**approved**/rejected/change_reviewing/change_approved/change_rejected/voided | TMS 审批状态;扫描只认 approved、change_approved(付款/开票/收票仅 approved) | +| hcs_sync_status | **unsynced / synced / failed** | 合规推送整体状态(任务补偿的依据) | +| hcs_retry_count | 整数 | 失败重试次数,≥ max-retry 停止自动补偿 | +| hcs_fd_id | — | 合规侧单据ID(项目/合同/开票登记),有值走更新链路 | +| hcs_spec_status | none/need/pushing/**processing**/approved/rejected | 特批状态;need 触发付款 C106-3,processing 挂起"特批审核"并阻塞合同重推 | +| hcs_spec_fd_id | — | 合规特批流程ID(付款 C106-3 返回) | +| hcs_perf_fd_id | — | 合规履约记录ID(C108-1 返回) | +| hcs_risk_level / hcs_black_status / hcs_risk_time | — | 合同客商风险校验留痕(C101-1 结果) | +| kingdee_id / kingdee_number | — | 金蝶同步结果回填(合规 result 回调) | + +--- + +## 6. C101-1 客商风险校验全景(最新口径) + +C101-1(`getRelativeRisk`,入参 fdNumber=客商编号,返回 fdRiskLevel 0=低/1=中/2=高、fdBlackStatus yes/no)在链路中共有 4 类调用场景。风险判定口径统一:**风险等级=2 或 黑名单=yes 即风险客商**;但「内部组织客商跳过查询」仅适用于场景 1/2/4(HcsCreditCheckSupport 统一入口),**场景 3(合同推送链路)未做内部组织跳过,甲乙双方均直接调 C101-1**,仅名称反查不到客商编号时记 skip。 + +| # | 场景 | 入口 | 开关 | 行为 | +| --- | --- | --- | --- | --- | +| 1 | **合同提交校验**(阻断) | ContractManageServiceImpl.validateSpecExplanationOnSubmit(新增/变更/重新提交等 4 处调用) | 无开关,始终执行 | 甲、乙方各自独立实时查(`isRiskyCustomer(partyA) \|\| isRiskyCustomer(partyB)`,queryCustomerRiskByName 名称反查编号,反查不到记 risky=false 不阻断);风险客商**必须已上传「特批附件」**,否则阻断提交(attachmentsJson 与 contractFileJson 均认可,历史已传兼容放行) | +| 2 | **付款提交校验**(提示+转特批) | PaymentApplicationServiceImpl 提交事务内 → HcsCreditCheckSupport.checkOnSubmit | `risk.check-on-payment` | 收款方反查档案:反查不到/内部组织 → skip 留痕不阻断;外部客商查询 C101-1,风险客商**必须上传「特批附件」**(attachmentType=special_approval,阻断提示),通过后置 `hcs_spec_status=need`、**清空旧 hcs_spec_fd_id**(特批单次有效,重新提交须重新发起 C106-3) | +| 3 | **合同推送留痕**(不阻断) | HcsPushTask 合同链路步骤① → HcsContractSyncSupport.checkRelativeRisk | `contract.require-risk-check` | **甲乙双方必各调一次 C101-1(此链路不跳过内部组织客商)**,仅名称反查不到编号时记 skip;结果留痕 hcs_risk_level(甲乙取甲方优先的非空值)/hcs_black_status(任一方黑名单即 yes)/hcs_risk_time 与 check_log;风险客商 → C103-1/C103-11 报文带 `fdSepcailContract=true` + 挂起"特批审核"(见 §4.2) | +| 4 | **页面展示查询** | HcsSyncController:`GET /hcs/risk?customerCode=`(单个)、`GET /hcs/risk/batch`(客商列表页批量,单个失败跳过)、`GET /hcs/risk/by-name`(按名称,合同前端校验用) | — | HcsCreditCheckSupport.queryCustomerRisk:内部客商直接 risky=false;外部客商查询后组装 CustomerRiskVO(fdBlackStatus/fdRiskLevel/riskLevelName/risky/riskTip);riskTip 为固定短文案(C101-1 不返回风险项明细):黑名单="被列入外部黑名单"、高风险="为高风险客商" | + +各场景均留痕 `blade_hcs_check_log`(check_type=risk,result=pass/fail/skip)。 + +### 6.1 风险客商管控闭环(合同/付款两条线) + +``` +提交时(阻断门禁):C101-1 查甲乙/收款方 → 风险客商须传「特批附件」方可提交 + │ +合同线:推送 C103-1/C103-11 报文 fdSepcailContract=true(合规侧走特批流程) + │ TMS 挂起"特批审核"(hcs_spec_status=processing) + └→ 结果:contractLegal/result 推送 或 C103-4 定时查询兜底 + approved → 恢复"审批通过";驳回 → 联动合同审批驳回 + +付款线:提交置 hcs_spec_status=need + │ 审批通过后扫描任务发起 C106-3(挂起"特批审核") + └→ 结果:paymentLegal/result 推送 或 人工确认 + APPROVED → 恢复放行;REJECTED → 联动付款审批驳回(returned) +``` + +--- + +## 7. 与本任务相关的其他链路(简述) + +- **即时推送**(HcsImmediatePushSupport):审批通过瞬间单条推送,Redis 单条锁(TTL 120s)防与扫描任务并发双推;失败落 failed 由本任务兜底。 +- **手动重推**(各 Support.repushXxx / HcsSyncController):重置 unsynced + 清零计数后立即推送;合同特批中(processing)禁止重推。 +- **主数据**(HcsMasterDataSupport):C103-6 模板 / C103-7 分类 / C103-12 币种列表,Redis 缓存,非本任务调度。 +- **额度校验 C106-1**:付款提交时同步调用(开关 `credit.check-enabled`,一期默认关);以 `fdIsCredit` 为准判定,通过置 hcs_credit_status=pass,超额**不拦截**提交、置 over 并标记 `hcs_spec_status=need` 转特批链路;校验依赖合同已推送合规(hcs_fd_id),未推送时按 `credit.require-contract-synced` 配置阻断或跳过。