From 6e685d3440dccb1ed238dbc4e44c3921470480c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Sun, 18 Oct 2026 15:23:12 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=96=B0=E5=A2=9E=E9=A2=84=E4=BB=98?= =?UTF-8?q?=E8=BD=AC=E6=AD=A3=E5=BC=8F=E7=BB=93=E7=AE=97=E5=8D=95=E4=B8=8E?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E9=A2=84=E4=BB=98=E6=93=8D=E4=BD=9C=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E8=AF=B4=E6=98=8E=EF=BC=88=E5=88=86=E5=9C=BA=E6=99=AF?= =?UTF-8?q?=C2=B7=E5=89=8D=E7=AB=AF=E5=90=8E=E7=AB=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...�结算单与项目预付操作流程说明(分场景·前端后端).md | 363 ++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 doc/docs/业务流程/2026-10-18-预付转正式结算单与项目预付操作流程说明(分场景·前端后端).md diff --git a/doc/docs/业务流程/2026-10-18-预付转正式结算单与项目预付操作流程说明(分场景·前端后端).md b/doc/docs/业务流程/2026-10-18-预付转正式结算单与项目预付操作流程说明(分场景·前端后端).md new file mode 100644 index 00000000..a61724d0 --- /dev/null +++ b/doc/docs/业务流程/2026-10-18-预付转正式结算单与项目预付操作流程说明(分场景·前端后端).md @@ -0,0 +1,363 @@ +# 预付转正式结算单与项目预付操作流程说明(分场景·前端后端) + +> 整理日期:2026-10-18 +> 定位:面向操作者与实施/联调人员的**分场景操作手册 + 逻辑说明**。讲清「谁在哪个页面点什么 → 后端发生什么 → 数据表/金蝶变成什么 → 怎么校验成功」。 +> 依据代码现状梳理(`tms-api` / `tms-erp-web`)。关联文档(同目录): +> - 《2026-10-18-预付完整流程梳理(进度预付-项目预付-正式结算单-付款-金蝶回写).md》——改造前现状 +> - 《2026-10-18-正式结算单预付整合设计(进度预付+项目预付核销·金额口径与记录流转).md》——v2 设计与决策 +> - 《2026-10-18-预付与正式结算单全链路逻辑梳理(进度预付-项目预付核销·前端到后端各环节).md》——改造后全链路 +> - 《2026-09-21-应收结算与开票申请同步金蝶全链路业务流程(A302-2保存-A302-4勾稽-A303-1新增-A303-4预检-A303-5回写).md》——开票链 +> - 《2026-09-29-预结算开票(预开票)金蝶推送方案.md》——预开票(**方案,尚未落地**) + +--- + +## 〇、先看全局:两条预付线 + 一条开票线 + +### 0.1 术语 + +| 术语 | 含义 | +|---|---| +| 预结算单(PreSettlement) | 结算前的费用单据,审批通过后作为预付/尾款结算的依据。有 **应付(payable)/应收(receivable)** 两种。 | +| 进度预付(progress_advance) | 挂在**预结算单**上的预付,属**应付**侧(我方付出去)。 | +| 项目预付(project_advance) | 挂在**项目 + 承运商合同**上的预付,不挂结算单,属**应付**侧。 | +| 核销 | 项目预付金在后续结算单上"抵扣",落 `SettlementProjectAdvanceWriteOff` 行。**仅金蝶已付款(paid)的项目预付可核销**。 | +| 容纳 / 纳入 | 预结算单转正式结算单时,其**预付台账快照**(进度预付)与**核销行**(项目预付)被正式结算单继承,计入正式单的"已付/已申请/剩余可付"。 | +| 尾款 | 正式结算单扣除已付(含预付、核销)后的剩余部分,走单独付款申请(settlement_payment)。 | +| 开票 | **应收**侧动作:正式结算单 → 开票申请 → 金蝶开票单。**应付**侧对应的是**收票**,两者共用 `formal_settlement.invoice_status` 字段,名称按结算方向区分。 | + +### 0.2 全景图 + +``` +【应付线 · 预付】 【应收线 · 开票】 + +预结算单(应付) approved 预结算单(应收) approved + │ │ + ├─ 预付申请(进度预付 progress_advance) └─ 尾款结算 + │ └ 审批 → A103-3 直推金蝶付款 → 回写 paid └→ 应收正式结算单 + │ └ 提前建档 PreSettlementAdvance ├ 审批 → 同步金蝶 A302-2 财务应收单 + │ └ 开票申请(选应收正式结算单) +项目预付(project_advance) ← 付款申请页「预付申请」 └ 审批 → A303-1 开票申请单 + ├ 选 项目 + 承运商合同(校验项目额度/客户额度) └ A303-5 回写发票 → 开票完成 + ├ 审批 → A103-3 → 金蝶付款 → 回写 paid + └ 后续在结算单上「项目预付核销」 + + ▼ 双线在「正式结算单」汇合 + 预结算单(应付) ──「尾款结算」──→ 应付正式结算单(容纳预付快照 + 核销行) + ├ 审批 → 同步金蝶 A102-2 财务应付单(全额 settlementAmount) + └「付款申请」→ 尾款付款 → A103-1 应付下推 +``` + +### 0.3 金蝶接口速查 + +| 接口 | 用途 | 触发方 | +|---|---|---| +| A103-3 | 预付款直接保存金蝶付款申请单(不绑应付单) | 付款申请(progress_advance / project_advance)同步金蝶 | +| A103-1 | 应付下推生成金蝶付款申请单 | 付款申请(settlement_payment)同步金蝶 | +| A103-2 / A103-4 | 付款申请单查询 / 付款处理查询 | 推送前幂等预检、定时回写(每 10 分钟) | +| A102-2 / A102-4 | 财务应付单保存 / 查询(防重预检) | 应付正式结算单「同步金蝶」 | +| A302-2 / A302-4 | 财务应收单保存 / 查询(勾稽) | 应收正式结算单「同步金蝶」 | +| A303-1 / A303-4 / A303-5 | 开票申请单保存 / 幂等预检 / 开票结果查询 | 开票申请「同步金蝶」与定时回写 | +| lockBusiData | 金蝶单据锁定 | 推送成功事务提交后 | +| A902 | 附件上传 | 主单推送成功后联带 | + +--- + +## 一、应付侧:预付转正式结算单(被"容纳") + +### 场景 A1:发起进度预付(挂预结算单) + +**前提**:预结算单 `approvalStatus=approved`、`settlementType=payable`、未转正式结算(`formalSettlementNo` 为空)。 + +**前端操作** +1. 菜单进「预结算单」列表 → 勾选 1 条或多条预结算单(**必须同一合同**)。 +2. 点工具栏「**预付申请**」。 + - 校验不通过时的提示:缺合同 ID / 多合同 / 非 payable / 非 approved / 已转正式。 +3. 跳转「付款申请」表单,页面类型已锁定为**进度预付**:结算单只读、结算金额与可付款金额自动带出。 +4. 填「申请付款金额」「付款方式」→「保存」→ 详情页「提交」→ 列表「通过」。 + +**后端动作** + +| 步骤 | 接口/方法 | 结果 | +|---|---|---| +| 可付金额 | `GET /payment-application/reference-amount` | `可付 = 预结算金额 − 累计已申请 − 项目预付核销额` | +| 保存 | `POST /payment-application/save` → `saveDraft` | 生成 `FKD+日期+序号` 单号;写 `PaymentApplicationSettlement` 关系表 | +| 提交 | `POST /payment-application/submit` | `draft/returned → reviewing` | +| 审批 | `POST /payment-application/approve` | `→ approved`,刷新预结算付款汇总,发布 `KingdeeBillApprovedEvent` | +| 自动推送 | `KingdeeApprovalSyncListener`(AFTER_COMMIT,开关 `thirdParty.bfi.autoSync.payment`) | A103-3 直推金蝶付款申请单;**提前建档** `PreSettlementAdvance`(`advanceNo = FKD 单号`);刷新预结算预付汇总并联动正式结算单 | + +> 说明:`PreSettlementController` 的 `/apply-advance`、`/update-advance-paid`、`/void-advance` 为**遗留接口**,前端已不再调用,台账改由付款申请流程联动维护。 + +**结果校验**:预结算单列表「申请预付金额 / 已预付金额」变化;付款申请 `kingdeeStatus` 从 `unsynced → synced`。 + +### 场景 A2:发起项目预付(挂项目 + 承运商合同) + +**前提**:项目已建、承运商合同已建;不超过项目额度与客户额度。 + +**前端操作** +1. 菜单进「付款申请」列表 → 点工具栏「**预付申请**」(注意:与 A1 的入口不同,本入口从付款申请页进)。 +2. 表单页类型为**项目预付**,填写: + - **所属项目**(必选,下拉) + - **合同名称**(必选,**仅承运商合同**,选项目后才可选) + - 申请付款金额、付款方式、付款方/收款方等 + - 不挂结算单,不展示发票信息与付款记录 +3. 「保存」→「提交」→「通过」。 + +**后端动作** + +| 步骤 | 接口/方法 | 结果 | +|---|---|---| +| 保存 | `saveDraft` → `validateQuota` | 项目额度、客户额度双重校验(见下) | +| 提交/审批 | `submit` / `approve` | 同上,审批后发事件推 A103-3 | +| 推送 | A103-3 | 金蝶生成付款申请单,`kingdeeStatus=synced` | +| 回写 | `PaymentKingdeeResultTask`(A103-2/A103-4,每 10 分钟) | `synced → paying → paid`;回填实付金额与付款记录 | + +**额度校验口径**(`PaymentApplicationServiceImpl.validateQuota`,悲观锁 `FOR UPDATE`) + +``` +项目额度 = (项目 fundLimit + Σ有效期内 approved 临时额度) × 10000 +客户额度 = 客商 maxCreditLimit × 10000 +申请付款金额 > 额度 → 分别报"申请付款金额不能超过项目额度 / 客户额度" +``` + +**结果校验**:付款申请列表 `kingdeeStatus=已付款(paid)`,金蝶单据号已回填。**只有 paid 才能进入后续核销**。 + +### 场景 A3:项目预付核销(在结算单上选单 + 录额) + +**前提**:存在 `approvalStatus=approved` 且 `kingdeeStatus=paid` 的项目预付,与结算单**同一合同**,且有剩余可核销余额。 + +**前端操作** +1. 打开**预结算单编辑器**(或后续的**正式结算单编辑器**)→「**项目预付核销**」分区 → 点「**选择**」。 +2. 弹窗「选择项目预付单」列出可核销单(同合同 + 已审批 + **已付款** + 有余额),已选行不可重复勾选。 +3. 勾选「确定」→ 默认按"可核销金额"预填「本次核销金额」,可手工改小。 +4. 「保存」(或保存草稿)。 + +**校验链(前端 → 后端一致)** + +| 层级 | 规则 | 提示 | +|---|---|---| +| 前端 | 金额 > 0 | 预付单 X 本次核销金额必须大于 0 | +| 前端 | 金额 ≤ 可核销金额 | 本次核销金额不能超过可核销金额 | +| 前端 | 核销合计 ≤ 结算单金额 | 项目预付核销合计不能超过结算单金额 | +| 后端 | 合同一致 | 项目预付单与结算单合同不一致 | +| 后端 | 仅项目预付 | 仅可核销项目预付单 | +| 后端 | approved | 仅可选择审核通过的项目预付单 | +| 后端 | **paid**(本次新增) | 预付单 X 尚未付款,项目预付须金蝶付款完成后方可核销 | +| 后端 | 同一预付单不重复 | 同一项目预付单不可重复核销 | +| 后端 | 有余额 / 合计 ≤ 结算金额 | 超出可核销金额 / 核销合计不能超过结算单金额 | + +**结果校验**:正式/预结算单「已付金额」立即包含核销额(核销行必对应已付款预付,计入实付口径),列表「申请付款金额(含预付)/已收已付合计(含预付)/剩余可付」同步变化。 + +### 场景 A4:预结算转正式结算单(容纳预付) + +**前提**:预结算单 `approved`、**同一项目**;此时其预付(进度预付台账、项目预付核销行)将被正式单继承。 + +**前端操作(两条路径)** +1. 「预结算单」列表勾选 → 工具栏「**尾款结算**」→ 跳「正式结算单」表单,来源预结算明细与费用项自动合并。 +2. 或在正式结算单表单里通过弹窗「追加来源预结算」。 + +**表单上的三处关键呈现(应付侧)** +- **结算合计(原金额)**:Σ 费用项 = `settlementAmount`,**始终全额,不扣预付/核销**(开票匹配上限、金蝶应付单金额基线)。 +- **汇总栏**「已付金额(含预付、核销)/ 剩余未付金额」: + - 编辑态实时算:`已付 = Σ来源预结算.advancePaidAmount + Σ核销行.writeOffAmount`; + - 只读态取落库值 `form.paidAmount`(已含尾款 + 进度预付 + 核销)。 +- **项目预付核销**:从预结算来源带入的核销行会**自动预填**,可增删改。 + +**后端动作(`FormalSettlementServiceImpl.saveDraft`,同一事务)** +1. 来源合并校验(同合同、同币种)→ 写 `FormalSettlementSource` 快照(含预付汇总 `advanceAppliedAmount / advancePaidAmount`)。 +2. `refreshSettlementAmount`:以费用项重算 `settlementAmount`,并刷一次汇总。 +3. **转移来源核销行**:`deleteBySettlementIds(PRE, 来源预结算ids)` —— 先释放来源占用,后续"不超可核销余额"校验才能通过预填金额。 +4. `replaceWriteOffs`:服务端复校验后落 **FORMAL** 核销行。 +5. `refreshPaymentSummary` 再刷一次(核销落库后必须再算,第 2 步覆盖不到核销行)。 + +> 原则:**同一笔预付的核销在链路上只存在一份** —— 预结算转正式 = 删源 PRE 行 + 落 FORMAL 行。 +> 轻量标记路径(`PreSettlementController /formal-settlement`):仅回写正式结算单号,无正式单实体,PRE 核销行原地保留,待真正建单时再转移。**前提:无在途预付申请**(存在 reviewing/approved 预付会拦截)。 + +**结果校验**:正式结算单「申请付款金额(含预付)」「已收已付合计(含预付)」「剩余可付」「收付款状态」四列直接反映预付与核销;同一预付在 PRE / FORMAL 侧无双份核销。 + +### 场景 A5:正式结算单同步金蝶(A102-2 财务应付单) + +**前端操作**:正式结算单列表 → **应付** tab → 勾选 1 条(按钮要求单选)→ 工具栏「**同步金蝶**」。 + +**后端动作**:`POST /formal-settlement/sync-kingdee` → 按结算方向路由: +- 应付 → **A102-2 财务应付单**(A102-4 幂等预检 / 反查,一张结算单一张应付单),金额 = **全额 settlementAmount**; +- 成功后回写 `kingdeeSyncStatus=synced` + 金蝶单据号/内码 → `lockBusiData` 锁单 → A902 附件上传。 + +**结果校验**:列表「金蝶同步状态」= 已同步、「金蝶锁定状态」= 已锁定 / 锁定中;附件未全部上传时页面追加提示"可重推补传"。 + +**审批时自动推送**:正式结算单「通过」后也会 AFTER_COMMIT 自动推;若推送失败,审批结果为 `false` + 具体原因以 warning 提示,审批本身不失败,走「同步金蝶」手动兜底或定时重推。 + +### 场景 A6:尾款付款(正式结算单之后) + +**前提**:正式结算单 `approved`、`payable`、同一合同、有剩余可付金额。 + +**前端操作**:正式结算单(应付)列表勾选 1 条或多条 → 工具栏「**付款申请**」→ 弹窗确认各单申请金额(默认 = 剩余可付,已扣核销)→「提交」。 + +**后端动作** +1. `saveDraft`:可挂多张同合同正式结算单,按可付金额比例分摊;`submit` 时 `validateNoTailPayment` 防重复尾款申请。 +2. **推送路由不同**:尾款走 **A103-1 应付下推**,前置对每张正式结算单做 A102-4 预检——**未在金蝶生成财务应付单则拦截**(提示先在正式结算单页同步金蝶);下推生成金蝶付款申请单,随后锁单 + 附件。 +3. 回写 `paid` → 生成 `FormalSettlementPayment(paymentType=final)` → `refreshPaymentSummary` 重算 `appliedPaymentAmount / paidAmount / remainingPayableAmount / paymentStatus`(unpaid → partial → paid)。 + +**金额口径(全系统唯一定义)** + +``` +settlementAmount = Σ 结算合计费用项(全额,不扣预付/核销) +appliedPaymentAmount = 尾款申请中(reviewing) + Σ来源预结算 advanceAppliedAmount + Σ核销行 +paidAmount = 尾款已付(approved 实付) + Σ来源预结算 advancePaidAmount + Σ核销行 +remainingPayableAmount = max(settlementAmount − paidAmount, 0) +paymentStatus = unpaid / partial / paid +``` + +--- + +## 二、应收侧:正式结算单推送开票 + +> 开票是**应收**方向:给客户开票 → 金蝶开票单。与应付侧的"收票"共用 `invoice_status` 字段,文案按方向区分(未开票 / 部分开票 / 已开票,未收票 / 部分收票 / 已收票)。 + +### 场景 B1:应收正式结算单同步金蝶(A302-2 财务应收单) + +**前端操作**:正式结算单列表切到「**应收**」tab → 勾选 1 条 → 工具栏「**同步金蝶**」。 + +**后端动作**:`POST /formal-settlement/sync-kingdee` → **A302-2 财务应收单**(防重键 `正式结算单号_结算明细单据号`)→ 回写单据号/内码 + `synced` → 锁单 + A902 附件。 +另有定时勾稽 `syncKingdeeArResult`(A302-4):对已同步/生成失败的应收结算单批量反查金蝶应收单并纠偏回填,可手动触发 `POST /formal-settlement/sync-kingdee-ar-result`。 + +**结果校验**:应收正式结算单 `kingdeeSyncStatus=已同步`,列表可见金蝶单据号。 + +> **开票前置**:正式结算开票要求**先有财务应收单**。开票申请推送时按 A302-4 逐结算单预检,未生成则拦截并提示"请先在正式结算单页面同步金蝶"。 + +### 场景 B2:开票申请创建与推送(A303-1 / A303-5) + +**前提**:存在 `approved`、未作废、**未收票/未开票(invoiceStatus=unreceived)** 的**应收**正式结算单。 + +**前端操作** +1. 菜单进「**开票申请**」列表 → 点「**新增**」。 +2. 「开票基本信息」区点「结算单」右侧「**选择**」→ 弹窗「选择应收正式结算单」(可按结算单号、项目、合同搜索)→ 勾选 → 「确定」。 + - 项目、开票单位(= 结算单收款方)自动带出;「**可开票金额**」= Σ 各结算单剩余可开票额;受票方开票信息按受票方客商档案带出。 +3. 填「发票类型」(电子专票时纳税人识别号/开户行/开户账号/注册地址必填)、受票方、邮箱、「开票内容」(发票张次与商品行)→ 系统自动算「本次开票金额」= 行合计。 +4. 「结算信息」表中填各结算单的**分摊开票金额**(≤ 该单剩余可开票金额)。 +5. 「开票明细」勾选明细 → 「保存」(草稿)→ 「提交」→ 列表「通过」。 + +**后端动作** + +| 步骤 | 接口/方法 | 规则 | +|---|---|---| +| 保存 | `POST /invoice-application/save` → `saveDraft` | ① 仅可选择**应收、审批通过、未作废、未收票**的正式结算单;② 结算单需兼容(同项目/开票方等);③ 分摊金额 ≤ 剩余可开票金额;④ 行合计 > 0;⑤ 受票方须有客商档案与有效开票信息;⑥ 电子专票四要素必填;⑦ 保存后刷新来源结算单开票状态,写变更记录 | +| 提交 | `/invoice-application/submit` | `draft/returned → reviewing`,写申请日期 | +| 审批 | `/invoice-application/approve` | `→ approved`,发布事件 → AFTER_COMMIT 推金蝶 | +| 推送 | `syncKingdee` → `doSyncKingdee` | ① **必须关联正式结算单**;② 逐结算单 A302-4 预检应收单已生成;③ A303-4 幂等预检(已生成的张次跳过并回填);④ 按发票张次拆分 `billno = 单号-张次` 逐张推 A303-1;⑤ 成功后锁单 + A902 附件 | +| 回写 | 定时 `syncKingdeeInvoiceResult`(A303-5,按 `serialNo=billno` 分批 ≤50)或手动 `POST /invoice-application/sync-kingdee-invoice-result` | 查到发票 → 落 `InvoiceApplicationInvoice` 发票记录并推进 `invoiced` 终态;同时刷新来源结算单 `invoice_status`(部分开票 → 已开票) | + +**结果校验**:开票申请 `kingdeeStatus=已同步 / 开票完成`,详情页可见发票结果(发票号、开票日期、价税合计、文件);来源正式结算单「发票状态」从未开票 → 部分开票 → 已开票。 + +**边界与限制(现状)** +- 已推送(`synced/invoiced`)**锁单不可改**;仅审批通过且未锁定时可「作废」。 +- 数电票已开出只能红冲(不走本系统作废)。 +- **预付/核销不影响开票**:开票按**全额 `settlementAmount`** 匹配,预付与核销只影响应付侧的已付/剩余可付。 + +### 场景 B3:预开票(预结算单直接开票)——**方案,尚未落地** + +按《2026-09-29-预结算开票(预开票)金蝶推送方案》,预结算(应收)可**只推 A303-1 开票申请单**、不校验应收单,新增 `invoice_source=pre` 与预结算关联表区分。 + +**当前代码状态**:`InvoiceApplicationServiceImpl.doSyncKingdee` 仍硬校验"必须关联正式结算单",创建入口也只允许选应收正式结算单 ⇒ **预开票目前推不出去**,需按上述方案改造后才能操作。本文不列为可执行场景。 + +--- + +## 三、状态机与字段口径 + +### 3.1 付款申请(PaymentApplication) + +| 字段 | 取值 | 说明 | +|---|---|---| +| `paymentType` | `progress_advance` / `project_advance` / `settlement_payment` | 进度预付 / 项目预付 / 尾款付款 | +| `approvalStatus` | `draft / reviewing / approved / returned / voided` | 提交后 reviewing;仅 approved 可作废 | +| `kingdeeStatus` | `unsynced / synced / paying / paid / closed / failed` | **paid 是项目预付可核销的前置** | +| `kingdeeLockStatus` | `locked / …` | 已锁定的单据禁止编辑/作废 | + +### 3.2 正式结算单(FormalSettlement) + +| 字段 | 取值 | +|---|---| +| `approvalStatus` | `draft / reviewing / approved / returned / voided` | +| `paymentStatus` | `unpaid / partial / paid` | +| `kingdeeSyncStatus` | `unsynced / synced / failed` | +| `invoiceStatus` | 应付=收票状态,应收=开票状态:`unreceived / partial / completed` | + +### 3.3 预付记录单据状态名(`src/utils/settlementStatus.js`,两个编辑器共用) + +| 值 | 名称 | +|---|---| +| `reviewing` | 审批中 | +| `approved` | 审批通过 | +| `paid` | 已付款 | +| `returned` | 已驳回 | +| `voided` | 已作废 | +| `draft` | 草稿 | + +### 3.4 正式结算单付款记录合并表(只读) + +一张表三类型,按「付款类型」列区分:**进度预付**(来源预结算 `PreSettlementAdvance` 台账)/ **项目预付核销**(核销行,金额=本次核销额)/ **结算尾款**。列名统一为「**申请/核销金额**」;创建时间统一取**底层付款申请创建时间**。 + +--- + +## 四、逆向与异常场景 + +| 场景 | 触发 | 系统行为 | +|---|---|---| +| 付款申请作废(仅 approved) | 付款申请列表「作废」(非金蝶锁定) | 金蝶锁单中禁止作废;汇票付款释放票据余额;**联动作废未付预付记录 + 删除其核销行并刷新受影响正式结算单汇总**(已付事实不回退) | +| 正式结算单作废 | 结算单列表「作废」 | 删本单 FORMAL 核销行,额度释放、详情无残留 | +| 金蝶删单回调(`voidByKingdee`) | 金蝶侧反审核删除 | 同上,删本单核销行 | +| 预结算单作废 | 预结算列表「作废」 | 存在关联预付申请需先作废预付;删 PRE 核销行 | +| 预付记录作废 | 预付台账 | 已付款的不能作废 | +| 金蝶反审核(解锁) | A103-2 连续两轮查不到已推单据 | 判定金蝶侧已删 → `unlockBill` 置 `failed`、清空金蝶单号/内码、**联动作废未付预付记录**(已付不回退);重推后重新建档。**此场景不删核销行**(预付申请仍 approved,核销继续计入),人工作废后才回落 | +| 推送失败 | A103-2/A102-2/A302-2/A303-1 报错 | 落 `failed` → `KingdeeAutoSyncRetryTask` 每 10 分钟自动重推;页面「同步金蝶」/「批量同步」手动兜底;审批接口把失败原因带回前端 warning,审批结果不受影响 | +| 结算调整(金额变更) | 「结算调整单」 | 调整落库前校验**核销合计 ≤ 新结算金额**,超出拒绝并提示先调减核销;落库后 `refreshPaymentSummary` 重算。调整重推:核销行**迁移到新单**(克隆 + 删原单行 + 批量刷新两单),原单作历史存档,收付口径以新单为准 | +| 全额核销 / 已结清 | `paymentStatus=paid` | `isSettlementCompleted` 拦截,不允许再发起结算调整(已确认"全额抵扣即结清") | + +--- + +## 五、接口与数据表索引 + +### 5.1 后端接口 + +| 模块 | 主要接口(`/blade-transport` 网关前缀) | +|---|---| +| 预结算单 | `GET /pre-settlement/list|detail`;`POST /pre-settlement/save|submit|approve|return|void`;`POST /pre-settlement/formal-settlement`(轻量标记转正式) | +| 付款申请 | `GET /payment-application/list|detail|reference-amount|project-advance-write-off-options`;`POST /payment-application/save|submit|approve|return|void|sync-kingdee|sync-kingdee-batch|sync-kingdee-result` | +| 正式结算单 | `GET /formal-settlement/list|detail|candidate-pre-settlements|contract-options`;`POST /formal-settlement/save|submit|approve|return|void|sync-kingdee|sync-kingdee-ar-result|retry-kingdee-bill-lock|apply-payment|apply-payments|claim-invoices` | +| 开票申请 | `GET /invoice-application/list|detail|settlement-candidates|settlement-details|receiver-information`;`POST /invoice-application/save|remove|submit|approve|return|void|sync-kingdee|sync-kingdee-invoice-result` | + +### 5.2 核心数据表 + +| 表/实体 | 作用 | +|---|---| +| `PreSettlement` | 预结算单;预付汇总 `advanceNo / advanceAppliedAmount / advancePaidAmount`、`formalSettlementNo` | +| `PreSettlementAdvance` | 预结算预付台账;`advanceNo`(=FKD 单号)、`billStatus`、`kingdeeAdvanceNo` | +| `PaymentApplication` | 付款申请(三种 paymentType) | +| `PaymentApplicationSettlement` | 付款申请 ↔ 结算单关系及分摊 | +| `PaymentApplicationRecord` | 付款记录(A103-4 回填,`voucherJson` 留档) | +| `FormalSettlement` | 正式结算单;`settlementAmount / appliedPaymentAmount / paidAmount / remainingPayableAmount / paymentStatus / kingdeeSyncStatus / invoiceStatus` | +| `FormalSettlementSource` | 来源预结算/明细快照,冗余预付汇总 | +| `FormalSettlementPayment` | 正式结算单尾款付款记录(`paymentType=final`) | +| `SettlementProjectAdvanceWriteOff` | 项目预付核销行(`settlementType`:PRE / FORMAL) | +| `InvoiceApplication` / `InvoiceApplicationSettlement` / `InvoiceApplicationSheet` / `InvoiceApplicationLine` / `InvoiceApplicationInvoice` | 开票申请主单 / 结算单关联与分摊 / 发票张次 / 商品行 / 金蝶回写发票 | + +### 5.3 前端页面 + +| 页面 | 路径 | +|---|---| +| 预结算单列表/表单 | `src/views/settlement/pre-settlement.vue`、`pre-settlement-form.vue`、`components/pre-settlement-editor.vue` | +| 正式结算单列表/表单 | `src/views/settlement/formal-settlement.vue`、`formal-settlement-form.vue`、`components/formal-settlement-editor.vue` | +| 项目预付核销组件 | `src/views/settlement/components/project-advance-write-off.vue` | +| 付款申请列表/表单 | `src/views/payment/payment-application.vue`、`payment-application-form.vue` | +| 开票申请列表/表单 | `src/views/payment/invoice-application.vue`、`invoice-application-form.vue` | +| 状态名公共工具 | `src/utils/settlementStatus.js`、`src/option/settlement/formalSettlementSearch.js` | + +--- + +## 六、已知口径与风险 + +1. **尾款默认可付额** = 结算金额 − 累计尾款申请 − 核销,**不扣进度预付已付部分**(既有口径)。进度预付占大头时默认额可能偏大,由审批环节把关。 +2. **正式结算单 `paidAmount` 现含核销**,下游消费该字段的报表/对账单口径随之变化(对账已确认接受)。 +3. **金蝶侧预付抵扣字段**(`y_billtype / y_billid / y_settleamt`)本期**不传**,金蝶报表与本系统"已付含核销"存在时间差(待业务确认后迭代)。 +4. **预开票未落地**:预结算直接开票需先按方案改造 `doSyncKingdee` 门禁与数据模型。 +5. 存量"approved 未 paid"的核销行未做数据修正(`replaceWriteOffs` 只约束新保存),如需清洗另出脚本。 +6. 应收侧预收/收款认领(ReceiptClaim)与收票流程未在本文展开。