docs: 金蝶票池选票回切镜像读终态口径文档,09-22实时版加退役声明

This commit is contained in:
刘泉佳
2026-10-05 17:54:03 +08:00
parent d3f549bf42
commit eb1edd3bbe
2 changed files with 88 additions and 0 deletions
@@ -5,6 +5,8 @@
> 关联文档:`2026-09-20-收票管理同步金蝶全票池发票(A801-1查询+批量同步+定时绑定关联)业务流程.md`(同步链已整体退役,仅存推送/回写侧仍有效的键与端点见该文档退役声明)、`2026-09-22-收票单推送金蝶全链路业务流程(A303-2保存-A302-6指定应付-A801-3预检回写).md`(图05 推送链路,镜像字段 invoice_type_code/items_json 由其取数消费)
> 设计依据:`docs/superpowers/specs/2026-09-22-invoice-pool-remote-reversal-design.md`
> 最后更新:2026-09-23(选票可用过滤 + 有界循环补页游标分页 + 单据使用状态收敛为后端固定查未用;2026-09-22 本文原为「金蝶票池选票统一查镜像」,同日二次决策改回实时查询后整篇重写;文件名保留以免断链)
>
> **⚠️ 退役声明(2026-10-05)**:本文描述的**实时查询链路(游标分页、可用过滤拉取后执行、claimed/registered 纯展示装饰)已被第三次定稿回切为镜像读**,终态口径见 `2026-10-05-金蝶票池选票回切镜像读(本地真分页+票号回源+瘦身同步+认领闸门)业务流程.md`。**仍然有效的部分**:保存重查闸门 `persistMirrorFromRemote`(含 isUsablePoolRow 复核,原样保留)、镜像 `(tenant_id, invoice_no)` 唯一与存根写入语义、A801-2 附件下载镜像优先/回源链路。下文其余叙述作历史口径。
---
@@ -0,0 +1,86 @@
# 金蝶票池选票回切镜像读(本地真分页 + 票号回源 + 瘦身同步 + 认领闸门)业务流程
> 适用系统:TMS(BladeX 微服务平台,服务:blade-transport;前端:tms-erp-web)
> 对接系统:金蝶发票云旗舰版·票易通(piaozone)全票池 A801-1,经业财融合 BFI 网关(rim 契约)透传
> 关联文档:`2026-09-22-金蝶票池选票统一查镜像…业务流程.md`(2026-09-22 定稿镜像读版、同日改写为实时版,本文第三次定稿)、`2026-09-23-金蝶票池选票方案对比评估与优化建议(镜像读+回源+保存重查闸门).md`(本方案评估依据)、`2026-09-20-收票管理同步金蝶全票池发票…业务流程.md`(首版同步体系,绑定/补偿/白名单部分维持退役)
> 设计依据:2026-10-05 grilling 会话定稿(Q1 回源 / Q2 瘦身同步 / Q3 双闸门 / Q4 全恢复条件能力 / Q5 邻接功能不动不留开关 / Q6 新分支 / Q7 手动 bootstrap)
> 最后更新:2026-10-05
---
## 1. 背景与决策
实时透传方案(2026-09-22 二次决策)运行暴露:每次开弹窗/翻页/保存都是一次 BFI 网关远程链路(秒级)、无 total 游标翻页不可跳页、名称模糊与认领/登记过滤被删、金蝶抖动期间选票整体瘫痪。2026-09-23 评估文档结论成立:**该回切的是"查询架构",不该回切的是"同步体系负担"**,且保存重查闸门是两版方案中唯一资金安全级防线。
**定稿口径**:
- 收票登记新增、正式结算单认领两处选票回切**查本地镜像** `blade_kingdee_invoice_pool`:本地 MySQL 真分页(total/跳页)、名称模糊、票种、双税号、claimed/registered 三态过滤全部恢复;**仅出可用票**(原 `isUsablePoolRow` 口径本地化执行:`available_amount > 0` 且 `amount_use_status = '0'`)。
- **票号未命中回源**:票号精确查本地无结果(且无认领/登记过滤条件)时,窄查一次 A801-1(票号全等防御 + 可用复核)→ upsert 入镜像 → 本地重查返回。兜底增量窗口缝隙内的当日新票;名称模糊本地为空**不回源**(远程不支持名称条件,救不了)。
- **瘦身版定时同步**回归:只保留「增量窗口分页拉取 + 镜像全列批量 upsert」,**不恢复**绑定回填、漏绑补偿、双白名单、指纹比对(保存即写存根绑定,登记侧无定时绑定需求;全列覆盖消灭指纹清单漏字段静默不同步的坑)。
- **双闸门保留/补齐**:收票保存重查(`persistMirrorFromRemote`)原样保留;结算认领确认(`claimInvoices`)补齐服务端按票号逐张重查校验——窗口拉取口径 `invoiceStatus="0"`,被删除/红冲票不再出现在拉取结果,镜像可能陈旧,资金安全由闸门保证。
## 2. 接口契约(后端)
| 端点 | 说明 |
| --- | --- |
| `GET /invoice-receipt/invoice-pool`、`GET /formal-settlement/invoice-pool` | 镜像统一查询,收参 `KingdeeInvoicePoolQueryDTO`,返回 `R<IPage<KingdeeInvoicePoolVO>>`(records/total/size/current) |
| `POST /invoice-receipt/sync-invoice-pool` | 手动触发全票池同步(bootstrap/联调/补偿三用),返回执行摘要 |
- **已删除**:游标契约 `KingdeeInvoicePoolPageVO`(hasMore/nextCursor)与 DTO `cursor` 字段、实时链路 `PoolScanCursor`/`toPoolViewVO`/`decorateUseFlags`。
- `KingdeeInvoicePoolQueryDTO` 条件:`current/size`(size 钳位 1~100)、`invoiceNo`(模糊)、`invoiceDateStart/End`(服务端强校验 yyyy-MM-dd)、`salerName/buyerName`(名称模糊)、`invoiceType`(票易通编码,匹配镜像 `invoice_type_code`)、`salerTaxNo/buyerTaxNo`(精确)、`claimed/registered`(三态过滤)。
- **KingdeeInvoicePoolMapper.xml**:`selectInvoicePoolPage` 单条 SQL 承载全部口径——`usableFilter`(`available_amount > 0 AND amount_use_status = '0'`)+ claimed/registered EXISTS 子查询(剔除作废结算单/作废登记,手工带租户与逻辑删除条件)+ 动态条件,`ORDER BY source_updated_time DESC`。
- VO 展示列:`availableTaxAmount`(剩余可用金额,金蝶可用税额口径,仅展示)与 `availableInvoiceAmount/matchedAmount`(价税合计口径,认领金额校验依赖)并存。
## 3. 保存与认领闸门
```
收票保存/提交(不变):persistMirrorFromRemote 按票号重查 A801-1
→ 未命中/delete=1 中止;isUsablePoolRow 复核(金额可用 0/使用状态变更中止)→ 写存根 + 绑定
结算认领确认(新增):claimInvoices 校验后逐张 assertInvoicesClaimable
→ 窄查 A801-1 + 票号全等防御 + isUsablePoolRow 同口径复核,任一不通过 ServiceException 中止
```
闸门数据不回写镜像(认领侧只校验不落库);可用性陈旧窗口由闸门兜底,无资损路径。
## 4. 定时同步(瘦身版)
```
InvoiceReceiptKingdeeSyncTask(@Scheduled cron,thirdParty.bfi.invoiceReceipt.cron 默认每30分钟,syncEnabled 默认关闭)
→ IInvoiceReceiptService.syncKingdeeInvoicePool()(KingdeeSyncLockSupport.runSingleFlight 单飞,锁键按租户)
→ executePoolSync():滚动近 incrementDays 天(默认30)窗口按 updateTime 分页拉取(pageSize 500,最多 50 页保护)
出站口径 invoiceStatus="0",不推 expenseStatus(在用/已用票随 updateTime 进窗口刷新使用状态,本地过滤自然排除)
→ batchUpsertInvoicePool:同页号码一次批量查既有镜像 → fillInvoicePool 全列填充 → Db.saveBatch / Db.updateBatchById
(全列覆盖、无指纹比对;源侧空字段维持库中原值——MP 非空字段更新策略,与手动/回源路径同口径)
→ 失败中断本轮由任务层记日志,下轮幂等重试
```
- 手动端点与定时任务共用单飞锁;`blade.lock.enabled=false` 时降级无锁并 warn(与付款回写/客商同步同模式)。
- 删除/红冲盲区:拉取不到的票镜像保持旧值看似可用——展示层陈旧可接受(无 `source_synced_time` 新增列,复用 `source_updated_time` 排序),资金安全由第 3 节双闸门保证。
## 5. 数据库与配置
| 项 | 内容 |
| --- | --- |
| 镜像表新增列 | `available_amount` decimal(18,2)、`amount_use_status` varchar(8),幂等脚本 `doc/sql/transport/blade_kingdee_invoice_pool_available_20261005.sql`(可重跑) |
| 新增索引 | `blade_formal_settlement_invoice (tenant_id, invoice_no)`(认领过滤 EXISTS 走索引) |
| Nacos | `third-party-api.yaml` 新增 `thirdParty.bfi.invoiceReceipt.*`:`syncEnabled`(false)/`cron`(每30分钟)/`incrementDays`(30)/`lockLeaseSeconds`(1800) |
| 存量数据 | 存量存根行两列为 NULL,不参与选票(可用过滤排除),随增量窗口同步自然回填;回切当天手动跑一次 `POST /invoice-receipt/sync-invoice-pool` bootstrap 铺底 |
## 6. 前端统一组件(`src/components/kingdee-invoice-pool-dialog/main.vue`)
- 分页区回切 `el-pagination`(total/sizes/prev/pager/next/jumper,可跳页);游标机件(nextCursor/pageCache/上一页缓存回显)删除。
- 条件区恢复:开票单位/受票单位名称模糊 + 认领状态/登记状态三态下拉;保留:票号、日期区间(默认近一月)、双税号、发票类型(编码下拉 26/27)。
- 保留实时版增强:剩余可用金额列、认领/登记 tag、附件查看/下载(A801-2 代理)、`rowKey = id || invoiceNo`(回源响应理论上有 id,兜底不变)。
- 页脚提示"按名称检索范围为已同步票,未找到请改用发票号码或税号精确查找"。
- 接线不变:收票登记表单(单选)、结算单编辑器(多选、`handleInvoiceClaimConfirm` 归一 `attachmentJson`)。
## 7. 邻接功能(本次不动)
A801-2 附件下载(镜像优先/实时回源,镜像覆盖面恢复后受益)、A801-5 黑名单查询(实时全量)、收票推送链 A303-2/A302-6/A801-3(消费镜像 `invoice_type_code/items_json`,不受影响)、收票保存重查与存根写入语义。
## 8. 已知限制
- 名称模糊仅检索已同步票(组件页脚已声明);同步缝隙内新票靠票号回源兜底,纯浏览需等下一轮同步。
- 30 分钟全列重写为已知写放大(千~万行级,成本可接受;量级上来后升级为整行载荷规范化哈希,**不恢复**人工字段清单式指纹)。
- 首轮 bootstrap 前无条件浏览为空表(上线操作项,见第 5 节)。
- 后端验证:`mvn compile -DskipTests -pl blade-service/blade-transport -am` 通过;前端 `pnpm run build` 通过。