docs: 金蝶附件同步(A902)设计文档与接口文档
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
# 金蝶附件同步(A902)设计文档
|
||||
|
||||
- 日期:2026-09-24
|
||||
- 范围:后端同步链路联带 A902 附件上传(付款申请、正式结算应付/应收、收票登记、开票申请)+ 前端状态列/提示/超时调整
|
||||
- 背景:单据推送金蝶成功后,TMS 侧附件(attachmentsJson)不随单上行,金蝶单据缺影像。星瀚 A902「附件上传到指定单据」接口已具备(见《业财融合系统接口文档.xlsx》同名页签),此前未在 BFI 客户端实现
|
||||
- 前置:依赖 2026-09-24-kingdee-push-timeout-anticlick 已落地的 loading+守卫+try/finally 模式,本设计不新增前端状态机
|
||||
|
||||
## 一、目标
|
||||
|
||||
1. 五类单据推送金蝶成功后,后端联带逐个上传附件至金蝶对应单据附件面板(A902)
|
||||
2. 收票登记含发票文件:票池镜像附件 path → A801-2 下载 → A902 回传收票单
|
||||
3. 附件同步独立状态、失败可补传(重推自动补);前端列表列 + message 可见
|
||||
4. 客商档案预留 entityNumber 映射配置,二期接入(开票申请 entityNumber 已确认为 `sim_original_bill`,提入本期)
|
||||
|
||||
## 二、A902 / A801-2 契约
|
||||
|
||||
### A902 附件上传到指定单据
|
||||
|
||||
- `POST /ierp/kapi/v2/frame/attachment/uploadFile`,multipart/form-data
|
||||
- Header:`access_token`(复用现有 getToken/token 缓存)
|
||||
- Body:`file`(文件)+ `attachmentUploadFileArgs`(JSON):`{"entityNumber":"ap_payapply","billPkId":2386455983883835392,"controlKey":"attachmentpanel"}`
|
||||
- 返回:`{"data":{"path":"211e6ce5c9805c00"},"errorCode":"0","status":true}`,`data.path` 即金蝶侧文件路径
|
||||
|
||||
### A801-2 文件下载(收票发票文件用)
|
||||
|
||||
- `POST /ierp/kapi/v2/awrp/bosext/attachment/download`,body `path`(镜像 attachmentsJson 的 path)→ 返回文件流
|
||||
|
||||
### entityNumber / controlKey 映射
|
||||
|
||||
| 业务单据 | entityNumber | controlKey | 期次 |
|
||||
| --- | --- | --- | --- |
|
||||
| 付款申请单 | `ap_payapply` | `attachmentpanel` | 本期 |
|
||||
| 财务应付单(正式结算应付面板) | `ap_finapbill` | `attachmentpanel` | 本期 |
|
||||
| 财务应收单(正式结算应收面板) | `ar_finarbill` | `attachmentpanel` | 本期 |
|
||||
| 收票单 | `ap_invoice` | `attachmentpanel` | 本期 |
|
||||
| 开票申请单 | `sim_original_bill` | `attachmentpanel` | 本期 |
|
||||
| 客商(资质附件) | 待金蝶确认 | 待确认 | 二期 |
|
||||
|
||||
映射以常量/配置类维护(如 `KingdeeBfiConstant` 或独立 `KingdeeAttachmentEntityMapping`),二期补条目不改架构。
|
||||
|
||||
## 三、领域模型
|
||||
|
||||
### 实体
|
||||
|
||||
**业务附件(不动)**:各单据 `attachmentsJson` JSON 列,是「单据有哪些附件」的业务事实,随表单编辑、随审批快照。本设计不读写其结构(只读 url/name)。
|
||||
|
||||
**附件同步表 `blade_kingdee_attachment_sync`(新增)**:
|
||||
|
||||
| 字段 | 说明 |
|
||||
| --- | --- |
|
||||
| id / tenant_id / 审计字段 | 标准结构 |
|
||||
| biz_type | `pay_application` / `formal_settlement_ap` / `formal_settlement_ar` / `invoice_receipt` / `invoice_application` |
|
||||
| biz_id | 单据 id |
|
||||
| attachment_key | 幂等键:用户附件=附件 url;发票文件=A801-2 的 path(path 变化视为新文件可重传) |
|
||||
| attachment_name | 附件名(展示/排查用) |
|
||||
| kingdee_path | A902 返回的 data.path |
|
||||
| sync_status | 1 成功 / 0 失败 |
|
||||
| fail_reason | 失败原因(超限/下载失败/金蝶报错) |
|
||||
| sync_time | 上传时间 |
|
||||
|
||||
- 唯一键 `uk_(biz_type, biz_id, attachment_key)`;同步前按 `(biz_type, biz_id)` 载入成功集合,命中即跳过(幂等)
|
||||
- 同步流水:现有同步流水新增 action=`attachment_upload`
|
||||
|
||||
**单据表加列**:`kingdee_bill_id`(星瀚单据内码,取自保存响应 `BfiBillSaveResultItemVO.id`)。付款申请已有该列;正式结算按应付/应收现有 kingdeeBillNo 的存储位置对应加 id 列;收票登记加收票单 id 列;开票申请加开票申请单 id 列。
|
||||
|
||||
### 附件同步状态机(单附件行级)
|
||||
|
||||
```
|
||||
(无记录) ──上传成功──> 成功(终态,幂等跳过)
|
||||
└────上传失败──> 失败(记 fail_reason;重推时重新尝试,成功则覆盖为成功)
|
||||
```
|
||||
|
||||
列表聚合展示态(运行时聚合,非存储字段):`无附件` / `已上传` / `部分未传` / `未上传`。
|
||||
|
||||
### 不变式
|
||||
|
||||
1. 附件上传必须晚于主单推送成功、拿到并落库 billPkId 之后
|
||||
2. 附件失败永不回滚、不污染主单同步状态(逐附件独立 try/catch)
|
||||
3. 同 `(biz_type, biz_id, attachment_key)` 最多一条成功记录
|
||||
4. 不自动重试;重推主单时自动补传(主单被幂等预检跳过不影响附件补传分支)
|
||||
5. 单文件软限制 20MB(常量,待金蝶确认后调整);超限/下载失败记原因跳过,不阻塞同单其余附件,更不阻塞同批其他单据
|
||||
|
||||
## 四、后端设计
|
||||
|
||||
### BFI 客户端(blade-bfi-api)
|
||||
|
||||
`IBfiClient` 新增两个方法,复用现有 token 配置(`BfiFeignClientConfig`):
|
||||
|
||||
- `uploadFile`:`produces = MULTIPART_FORM_DATA_VALUE`,`@RequestPart("file")` + `@RequestPart("attachmentUploadFileArgs")`(JSON 字符串),返回 `BfiOpenApiResultVO`(含 data.path)
|
||||
- `downloadFile`(A801-2):body 传 path,返回 `feign.Response`(流式读取,防大文件全量进内存)
|
||||
|
||||
### 附件同步支持类(blade-transport)
|
||||
|
||||
新增 `KingdeeAttachmentSyncSupport`(与 `KingdeeApBillSyncSupport` 等同包同风格),核心方法:
|
||||
|
||||
```
|
||||
syncAttachments(bizType, bizId, billPkId, List<KingdeeAttachmentItem>)
|
||||
```
|
||||
|
||||
流程:载入已成功集合 → 过滤已传 → 过滤超限(记 fail_reason)→ 逐个(读文件流 / A801-2 下载)→ A902 上传 → 落记录 + 流水。单附件 try/catch,异常记失败继续下一个。
|
||||
|
||||
### 各模块接入点(主单成功、billPkId 落库之后)
|
||||
|
||||
| 模块 | 接入点 | entityNumber | 附件来源 |
|
||||
| --- | --- | --- | --- |
|
||||
| 付款申请 | `pushBfiPayApplyPush` / `reconcileExistPayApply` 成功后 | ap_payapply | 单据 attachmentsJson |
|
||||
| 正式结算应付面板 | A102-2 保存成功后 | ap_finapbill | 结算单 attachmentsJson |
|
||||
| 正式结算应收面板 | A302-2 保存成功后 | ar_finarbill | 结算单 attachmentsJson |
|
||||
| 收票登记 | `pushKingdeeReceivedInvoice` A303-2 成功后 | ap_invoice | 登记附件 + 镜像发票文件(A801-2 下载,key=path) |
|
||||
| 开票申请 | A303-1 保存成功后(幂等预检命中时取 A303-4 查询响应 id 回填,与付款申请勾稽同模式) | sim_original_bill | 单据 attachmentsJson |
|
||||
|
||||
重推补传:现有同步入口无改动——主单被幂等预检判已存在时,仍进入附件补传分支(此时 billPkId 取本地 kingdee_bill_id;本地缺失则调对应查询接口回填,如付款申请勾稽已有此能力)。
|
||||
|
||||
### 列表状态聚合
|
||||
|
||||
各列表 VO 增加 `attachmentSyncStatus` 聚合字段:列表查询后按 biz_ids 一次 `GROUP BY biz_type, biz_id` 查同步表,与单据附件数量(解析 attachmentsJson 计数)对比得出聚合态,避免 N+1。
|
||||
|
||||
## 五、前端设计
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| 超时 | `paymentApplication.js` syncKingdee/syncKingdeeBatch、`invoiceApplication.js` syncKingdee、`formalSettlement.js` syncKingdee、`invoiceReceipt.js` pushKingdee 由 30s 放宽到 60s(附件联带增加耗时) |
|
||||
| 列表列 | payment-application.vue、invoice-application.vue、formal-settlement-table-panel.vue(prop 传入)、invoice-receipt.vue 增「附件同步」列:无附件/已上传/部分未传/未上传 |
|
||||
| message | 同步成功但存在附件未全部上传时,追加 warning 提示「N 单同步成功,其中 M 单附件未全部上传,可重推补传」 |
|
||||
| 交互 | loading/守卫/try-finally 模式完全复用,无新增状态;无新增按钮(重推即补传) |
|
||||
|
||||
## 六、不做的事
|
||||
|
||||
- 客商档案附件推送(二期,等金蝶确认 entityNumber/controlKey;本期仅预留映射配置)
|
||||
- 附件自动重试、定时补传任务
|
||||
- attachmentsJson 结构改造(去 JSON 化属独立重构,见 ADR-3)
|
||||
- OFD/PDF 发票文件在金蝶侧的可预览性验证
|
||||
|
||||
## 七、待确认(金蝶侧)
|
||||
|
||||
1. A902 单文件大小上限、允许格式(当前后端软限制 20MB 常量)
|
||||
2. 客商的 entityNumber/controlKey
|
||||
3. A902 调用频率限制(批量串行是否需间隔)
|
||||
4. OFD 数电票文件上传收票单附件面板是否可用(主文档 641 行注明「金蝶不支持直接推送数电票 OFD 附件」,需验证 A902 通道例外与否)
|
||||
|
||||
## 八、验证
|
||||
|
||||
1. 后端:`mvn clean compile -DskipTests -pl`(改动模块)
|
||||
2. 前端:`pnpm run typecheck`
|
||||
3. 手动(用户执行):
|
||||
- 含附件单据(付款申请/开票申请/正式结算/收票登记)单条/批量同步 → 金蝶对应单据附件面板可见文件
|
||||
- 同步成功但附件失败(断网/超限模拟)→ 主单状态正常、列表「附件同步」列示未传、重推自动补传
|
||||
- 重推已全部上传的单据 → A902 零调用(幂等跳过)
|
||||
- 收票登记:镜像发票文件经 A801-2 下载后出现在收票单附件面板
|
||||
|
||||
## 九、ADR 摘要(本次评审定案)
|
||||
|
||||
| # | 决策 | 备选与理由 |
|
||||
| --- | --- | --- |
|
||||
| ADR-1 | 后端联带自动传附件 | 前端两段式/独立按钮被否:状态机复杂、易漏传 |
|
||||
| ADR-2 | 附件独立状态+失败可补传,不自动重试 | 主单状态机不被污染;重推即补传零新增交互 |
|
||||
| ADR-3 | 幂等落独立同步表;**保留 attachmentsJson** | 附件业务事实(编辑/审批快照)与集成状态(幂等/path/原因)职责分离,url 幂等键是必要冗余而非数据冗余;推送期间单据锁定,无并发写 JSON 风险;去 JSON 化若要做属独立重构 |
|
||||
| ADR-4 | 本期 5 单据(开票申请 entityNumber 已确认 `sim_original_bill` 提入本期),客商预留配置 | entityNumber 是硬约束,猜错即传不上 |
|
||||
| ADR-5 | 同步接口超时 60s + 后端软限制跳过 | 大文件不拖死整批;不引入异步任务复杂度 |
|
||||
| ADR-6 | 收票含发票文件:A801-2 下载→A902 回传,key=path | path 变化(红冲重开)自动触发重传 |
|
||||
|
||||
## 术语表
|
||||
|
||||
| 术语 | 含义 |
|
||||
| --- | --- |
|
||||
| A902 | 星瀚「附件上传到指定单据」接口 |
|
||||
| A801-2 | 星瀚「文件下载」接口(票池发票影像) |
|
||||
| billPkId | 星瀚单据内码,保存响应 `BfiBillSaveResultItemVO.id`,A902 定位目标单据 |
|
||||
| entityNumber | 星瀚单据标识(如 ap_payapply) |
|
||||
| controlKey | 星瀚附件面板/附件字段标识,统一 attachmentpanel |
|
||||
| 附件同步聚合态 | 无附件/待上传/部分未传/已上传(列表展示用,运行时聚合) |
|
||||
Reference in New Issue
Block a user