diff --git a/changelogs-v2/2026-09/22_8070_应付款建议清单统计页切流读台账-修改接口-管理后台.md b/changelogs-v2/2026-09/22_8070_应付款建议清单统计页切流读台账-修改接口-管理后台.md new file mode 100644 index 00000000..fc643262 --- /dev/null +++ b/changelogs-v2/2026-09/22_8070_应付款建议清单统计页切流读台账-修改接口-管理后台.md @@ -0,0 +1,206 @@ +--- +schema: "hl-changelog/v2" +ticket: "8070" +title: "应付款建议清单/统计页切流读推送台账,出参补 applied/paid/owed 口径字段" +consumer: "admin" +author: "yst(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "not_required" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "backend_status: deployed - hl-order-service-v3 已部署测试服(dev-v3,含 finance 同进程),Epic #8070 三轮 E2E PASS + 最终验收已交付(2026-09-21 取证); gateway_status: not_required - 零网关改动,/admin/finance/** 走 hl-gateway 既有通配路由; frontend_status: pending - 前端适配情况未知,后端不代填。" +updated_at: "2026-09-22" +base: "dev-v3" +--- + +# 财务:应付款建议清单/统计页切流读推送台账(Epic #8070 PR-5) + +> 应付款「申请建议清单」与「按供应商/按团统计」接口的数据源由实时扫订单切换为读应付款推送台账(`fin_payable_line/team/supplier` 三表),出参补充申请中/已付/欠款口径字段,并前置台账锁定闸。 + +## ① 接口背景 + +应付款域此前「建议清单」「统计页」靠实时聚合订单/配房/行程节点数据计算,口径分散、与台账不一致。Epic #8070 建立应付款推送台账星型模型(明细行 `fin_payable_line` + 团头 `fin_payable_team` + 供应商头 `fin_payable_supplier`),订单确认/配房确认即推送台账。PR-5 把**读侧**(申请建议清单 + 统计页)切流到台账,让申请、审批、统计共用同一套 applied(申请中)/paid(已付)/owed(欠款)口径,并加 `isLocked` 前置闸(审批中行锁定禁重复申请)。 + +## ② 变更清单 + +| 类型 | 接口 | 变更 | +|---|---|---| +| 修改 | `GET /admin/finance/payments/suggestion` 申请建议清单 | 数据源切台账;行出参补口径/资格字段 | +| 修改 | `GET /admin/finance/payments/stats/by-supplier` 按供应商统计 | 数据源切台账头表;出参补 applied/owed | +| 修改 | `GET /admin/finance/payments/stats/by-team` 按团统计 | 数据源切台账头表;出参补 applied/owed | + +> 申请/审批写入侧(建单占用 applied、付讫转 paid、驳回释放)同步切台账,属内部实现,接口签名不变。 + +## ③ 接口详情 + +### 3.1 申请建议清单 + +``` +GET /admin/finance/payments/suggestion?... +``` + +返回可申请的应付款明细行(来自台账 NORMAL 行),每行带是否可申请资格与原因,已被申请占用或审批锁定的行不可重复申请。 + +### 3.2 按供应商统计 / 按团统计 + +``` +GET /admin/finance/payments/stats/by-supplier?... +GET /admin/finance/payments/stats/by-team?... +``` + +返回台账头表聚合的应付/申请中/已付/欠款四口径,与明细行求和一致。 + +## ④ 入参 + +入参字段与旧版一致(分页 + 既有筛选条件),无新增/无删除。 + +## ⑤ 出参 + +### 5.1 建议清单行 `PaymentSuggestionRowVO`(关键字段) + +| 字段 | 类型 | 说明 | +|---|---|---| +| `sourceType` | string | 来源类型(配房/行程节点等) | +| `sourceId` | Long(string) | 来源单据 ID | +| `resourceId` / `resourceName` | Long / string | 资源 ID / 名称 | +| `qty` / `unitPrice` / `amount` | number | 数量 / 单价 / 应付金额 | +| `payWay` | string | 付款方式 | +| `paymentType` | string | 付款类型(fin_payment_type 字典标签) | +| `supplierId` / `supplierName` | Long / string | 供应商 ID / 名称(降级行可空) | +| `payeeAccountId` | Long(string) | 供应商生效收款账户 | +| `eligible` | boolean | 是否可申请(false 时看 `eligibleReason`) | +| `eligibleReason` | string | 不可申请原因(已占用/审批锁定/无价等) | +| `alreadyGenerated` | boolean | 是否已生成付款单 | + +### 5.2 按供应商统计行 `PaymentStatsBySupplierRowVO` + +| 字段 | 类型 | 说明 | +|---|---|---| +| `supplierId` / `supplierName` | Long / string | 供应商 ID / 名称 | +| `category` | string | 类别(fin_payment_type 字典标签) | +| `payableAmount` | number | 应付总额 | +| `appliedAmount` | number | **申请中金额(新增/真值化)** | +| `paidAmount` | number | 已付金额 | +| `owedAmount` | number | **欠款 = 应付 − 已付(可为负=多付)** | +| `teamCount` | int | 涉及团数 | +| `status` | string | 状态 | + +### 5.3 按团统计行 `PaymentStatsByTeamRowVO` + +| 字段 | 类型 | 说明 | +|---|---|---| +| `teamNo` | string | 团号 | +| `productName` / `customerName` / `orderNos` | string | 产品 / 客户 / 订单号 | +| `departDate` / `returnDate` | string(date) | 出团 / 回团日期 | +| `payableAmount` | number | 应付总额 | +| `appliedAmount` | number | **申请中金额(新增/真值化)** | +| `paidAmount` | number | 已付金额 | +| `owedAmount` | number | **欠款 = 应付 − 已付** | +| `supplierCount` | int | 涉及供应商数 | +| `status` | string | 状态 | + +## ⑥ 枚举/数据字典 + +- `paymentType` / `category` 走 `fin_payment_type` 字典标签:住宿 / 门票·游玩 / 餐食 / 车辆 / 导游 / 摄影 / 保险 / 其他支出 / 退款 / 其他应付。 +- 台账行 `line_type`:`NORMAL` 正常 / `CLOSED` 红冲(建议清单只出 NORMAL)。 +- 台账行 `close_status` / `recover_status` 为内部治理字段,不外透出参。 + +## ⑦ 错误码 + +本批为读侧切流,无新增对外错误码。台账推送/占用相关错误码(5996xx 段)见既有应付款推送台账 changelog。 + +## ⑧ 示例 + +### 8.1 按供应商统计 + +请求 `GET /admin/finance/payments/stats/by-supplier?pageNo=1&pageSize=10`: + +```json +{ + "code": 200, + "data": { + "list": [ + { + "supplierId": "2096854417461403650", + "supplierName": "呼伦贝尔羊和远方牧业有限公司", + "category": "住宿", + "payableAmount": 3000.00, + "appliedAmount": 800.00, + "paidAmount": 1200.00, + "owedAmount": 1800.00, + "teamCount": 3, + "status": "NORMAL" + } + ], + "total": 1 + } +} +``` + +### 8.2 建议清单(含不可申请资格) + +```json +{ + "code": 200, + "data": { + "list": [ + { + "sourceType": "GROUP_BATCH_STAY", + "sourceId": "2100484891404648449", + "resourceName": "呼和诺尔湖景房", + "amount": 800.00, + "paymentType": "住宿", + "supplierId": "2096854417461403650", + "supplierName": "呼伦贝尔羊和远方牧业有限公司", + "eligible": false, + "eligibleReason": "已存在审批中付款单,行已锁定", + "alreadyGenerated": true + } + ] + } +} +``` + +### 8.3 边界:降级行(供应商未绑定) + +配资源时供应商未绑定/反查失败的行,`supplierId`/`supplierName` 为 null,落台账待绑定区,不阻断主流程: + +```json +{ "sourceId": "...", "supplierId": null, "supplierName": null, "eligible": false, "eligibleReason": "供应商待绑定" } +``` + +## ⑨ 业务边界 + +- **applied 占用口径**:建单(PENDING)即占用,付讫转 paid,驳回/删除释放;防止同一应付行被重复申请。 +- **isLocked 前置闸**:存在审批中付款单的台账行锁定,建议清单 `eligible=false`。 +- **无价节点不推送**:结算价 NULL 或 0 的资源不推送台账(不炸订单确认)。 +- **owed 可为负**:多付/台账外付款时 owed 为负,属正确表达。 + +## ⑩ 修改前后对比 + +| 项 | 修改前 | 修改后 | +|---|---|---| +| 数据源 | 实时扫订单/配房/节点 | 读推送台账三表 | +| 申请中金额 | 无独立口径 | `appliedAmount` 真值化 | +| 欠款 | 各页自算、口径不一 | `owedAmount = payable − paid` 统一 | +| 重复申请 | 可能重复 | isLocked 闸拦截 | + +## ⑪ 影响评估 / 回滚 + +- **出参新增字段**(appliedAmount/owedAmount 等)为增量,旧前端不读取不受影响;但**数值口径变化**(切台账后与旧实时聚合可能有差),前端需以台账口径为准。 +- **回滚**:读侧切回实时聚合需回退代码;台账数据保留。 + +## ⑫ 注意事项 + +- 台账为「订单确认/配房确认」时推送,历史未推送的老订单不在台账内(开发阶段老数据可清,生产上线另起迁移)。 +- 供应商降级行(supplierId null)不累计供应商头表。 + +## ⑬ 关联 / 联系人 + +- Issue:https://git.1814.love:8443/wx/HL/issues/8070 +- PR:#8071 / #8075 / #8079 / #8081 / #8083 / #8092(本批切流)/ #8097 / #8109 +- 负责人:yst diff --git a/changelogs-v2/2026-09/22_8127_应付款付款支持冲抵供应商预付款-修改接口-管理后台.md b/changelogs-v2/2026-09/22_8127_应付款付款支持冲抵供应商预付款-修改接口-管理后台.md new file mode 100644 index 00000000..513d25a7 --- /dev/null +++ b/changelogs-v2/2026-09/22_8127_应付款付款支持冲抵供应商预付款-修改接口-管理后台.md @@ -0,0 +1,246 @@ +--- +schema: "hl-changelog/v2" +ticket: "8127" +title: "应付款付款支持冲抵供应商预付款(差额付款 + 占用/付讫/回冲状态机)" +consumer: "admin" +author: "yst(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "not_required" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "backend_status: deployed - hl-order-service-v3 已部署测试服(dev-v3,含 finance 同进程),E2E 全链路 PASS(改单加冲抵→审批→出纳差额付款,往来净额/预付余额/冲抵明细 SETTLED 全对,2026-09-22 取证); gateway_status: not_required - 零网关改动,/admin/finance/** 走 hl-gateway 既有通配路由; frontend_status: pending - 前端适配情况未知,后端不代填。" +updated_at: "2026-09-22" +base: "dev-v3" +--- + +# 财务:应付款付款支持冲抵供应商预付款(Epic #8127) + +> 应付款付款时可用「该供应商已付讫且有余额的预付款」冲抵,出纳只付差额现金。涉及 4 个建单/改单接口入参新增、付款单详情出参新增、新增 1 个可冲抵预付查询接口。 + +## ① 接口背景 + +供应商常有预付(先打款后结算)。此前预付款与应付款是两条独立线,应付款付款只能全额现金支出,无法用已预付的余额抵扣,资金占用高。本变更让应付款付款单可勾选「该供应商的预付款」做冲抵:冲抵部分无现金流出,出纳仅按「应付金额 − 冲抵金额 = 实付金额」付差额。 + +三个口径决策(后端已定): +- **冲抵算 paid**:冲抵部分随现金一并计入应付台账已付,清偿方式不影响应付债务的付讫认定。 +- **占用时点=建单时**:建单/改单(PENDING 草稿)即扣减预付可用余额并落「占用中」明细,驳回/删改草稿回冲,付讫转「已冲抵」。 +- **往来差额归零**:付讫时补一对抵销分录,付款单文档净额=0、预付单文档净额=剩余可用余额,供应商往来对账自清。 + +## ② 变更清单 + +| 类型 | 接口 | 变更 | +|---|---|---| +| 修改 | `POST /admin/finance/payments` 创建付款单 | 入参新增 `prepayOffsets[]` | +| 修改 | `POST /admin/finance/payments/batch` 按订单批量创建 | 入参新增 `prepayOffsets[]`(按供应商分组) | +| 修改 | `POST /admin/finance/payments/batch-by-supplier` 按供应商合并创建 | 入参新增 `prepayOffsets[]`(按供应商分组) | +| 修改 | `PUT /admin/finance/payments/{id}` 编辑草稿 | 入参新增 `prepayOffsets[]`(整体置换语义) | +| 修改 | `GET /admin/finance/payments/{id}` 付款单详情 | 出参新增 `offsets[]`;`prepayOffsetAmount`/`actualPayAmount` 由恒 0 真值化 | +| 新增 | `GET /admin/finance/payments/offsettable-prepays` 可冲抵预付查询 | 新接口 | + +## ③ 接口详情 + +### 3.1 新增:可冲抵预付查询 + +``` +GET /admin/finance/payments/offsettable-prepays?supplierId={supplierId} +``` + +供付款申请页勾选「用哪笔预付冲抵」。返回该供应商下**已付讫(PAID)且可用余额 > 0** 的预付款,按付款日期升序。 + +### 3.2 创建/编辑付款单(冲抵) + +在既有入参基础上加 `prepayOffsets`,提交即占用预付余额;不冲抵则该字段不传或传空数组(行为与旧版完全一致)。 + +### 3.3 付款单详情 + +详情返回本单的冲抵明细 `offsets[]` 及冲抵状态;`actualPayAmount`(实付)为出纳真正付现的金额。 + +## ④ 入参 + +### 4.1 `prepayOffsets[]`(创建/编辑付款单新增,可空) + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `prepayId` | Long(string) | 是 | 预付款申请单 ID(须为本供应商 PAID 且余额充足) | +| `offsetAmount` | number | 是 | 该笔预付冲抵金额(>0,≤预付可用余额) | + +> 批量接口(按订单批量/按供应商合并)按供应商分组传:`prepayOffsets: [{ supplierId, offsets: [{ prepayId, offsetAmount }] }]`。 +> 编辑草稿为**整体置换语义**:传入的 `prepayOffsets` 全量替换旧占用(先回冲旧占用再按新入参重占)。 + +### 4.2 可冲抵预付查询入参 + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `supplierId` | Long(string) | 是 | 供应商 ID(查询其可冲抵预付) | + +## ⑤ 出参 + +### 5.1 付款单详情 `GET /admin/finance/payments/{id}`(新增/真值化字段) + +| 字段 | 类型 | 说明 | +|---|---|---| +| `amount` | number | 应付金额(= Σ明细行,不随冲抵变化) | +| `prepayOffsetAmount` | number | **冲抵金额合计**(= Σoffsets.offsetAmount;原恒 0,本期真值化) | +| `actualPayAmount` | number | **实付金额 = amount − prepayOffsetAmount**(出纳按此现金付款;原恒等于 amount) | +| `offsets` | array | **本单冲抵明细列表**(新增,无冲抵时为 `[]`) | + +`offsets[]` 元素: + +| 字段 | 类型 | 说明 | +|---|---|---| +| `offsetId` | Long(string) | 冲抵明细 ID | +| `prepayId` | Long(string) | 预付款申请单 ID | +| `prepayNo` | string | 预付款单号(YF- 前缀) | +| `offsetAmount` | number | 该笔冲抵金额 | +| `status` | string | 冲抵状态:`OCCUPYING` 占用中 / `SETTLED` 已冲抵(付讫)/ `CANCELLED` 已取消(驳回/删改草稿回冲) | +| `settleTime` | string(datetime) | 付讫冲抵时间(仅 SETTLED 有值,否则 null) | + +### 5.2 可冲抵预付查询 `offsettable-prepays` 出参(数组) + +| 字段 | 类型 | 说明 | +|---|---|---| +| `prepayId` | Long(string) | 预付款申请单 ID | +| `prepayNo` | string | 预付款单号 | +| `amount` | number | 预付本金 | +| `availableAmount` | number | 可用余额(可被冲抵的上限) | +| `payDate` | string(date) | 付款日期 | +| `supplierId` | Long(string) | 供应商 ID | +| `supplierName` | string | 供应商名称 | + +## ⑥ 枚举/数据字典 + +**冲抵明细状态 `offsets[].status`**: + +| 值 | 含义 | +|---|---| +| `OCCUPYING` | 占用中(建单~付讫前) | +| `SETTLED` | 已冲抵(付讫,终态) | +| `CANCELLED` | 已取消(驳回/删草稿/改草稿回冲,留痕) | + +`paymentType` 仍走既有 `fin_payment_type` 字典标签(住宿/门票·游玩/餐食/车辆/导游/摄影/保险/其他支出/退款/其他应付),本次未新增。 + +## ⑦ 错误码 + +| 码 | 语义 | +|---|---| +| 598812 | 冲抵入参非法(金额≤0 / 同一预付单重复传) | +| 598813 | 冲抵合计超应付金额(Σoffset > amount) | +| 598814 | 预付单不可用(不存在 / 非已付讫 / 可用余额不足 / 金额非法) | +| 598815 | 预付单冲抵单位与付款供应商不一致(跨供应商拦截) | +| 598816 | 预付可冲抵余额并发不足(CAS 扣减失败,整批回滚) | +| 598817 | 冲抵回冲账实不符(回冲 CAS 失败,fail-fast) | + +## ⑧ 示例 + +### 8.1 典型:创建付款单并冲抵预付 + +请求 `POST /admin/finance/payments`: + +```json +{ + "supplierId": "2096854417461403650", + "payeeAccountId": "2096854417490763777", + "amount": 800.00, + "paymentType": "住宿", + "reason": "9月羊和远方住宿结算", + "orderId": "2100482290093039617", + "prepayOffsets": [ + { "prepayId": "2100473583917580290", "offsetAmount": 500.00 } + ] +} +``` + +响应(`data.paymentId` 为新单 ID)。此时预付 `available_amount` 1000→500,`prepayOffsetAmount=500`、`actualPayAmount=300`,offset 行 `OCCUPYING`。 + +详情出参(付讫后): + +```json +{ + "code": 200, + "data": { + "id": "2100485199803359234", + "paymentNo": "FK-202609170057", + "amount": 800.00, + "prepayOffsetAmount": 500.00, + "actualPayAmount": 300.00, + "status": "PAID", + "offsets": [ + { + "offsetId": "2102204...", + "prepayId": "2100473583917580290", + "prepayNo": "YF-202609170002", + "offsetAmount": 500.00, + "status": "SETTLED", + "settleTime": "2026-09-22 09:15:35" + } + ] + } +} +``` + +### 8.2 边界:可冲抵预付查询 + +请求 `GET /admin/finance/payments/offsettable-prepays?supplierId=2096854417461403650`: + +```json +{ + "code": 200, + "data": [ + { + "prepayId": "2100473583917580290", + "prepayNo": "YF-202609170002", + "amount": 1000.00, + "availableAmount": 500.00, + "payDate": "2026-09-17", + "supplierId": "2096854417461403650", + "supplierName": "呼伦贝尔羊和远方牧业有限公司" + } + ] +} +``` + +(该预付已被冲抵 500,故 `availableAmount` 由 1000 降为 500。) + +### 8.3 异常:冲抵超应付 / 跨供应商 + +```json +{ "code": 598813, "message": "冲抵合计超应付金额", "success": false } +{ "code": 598815, "message": "预付单冲抵单位与付款供应商不一致", "success": false } +{ "code": 598814, "message": "预付单不可用(不存在/非已付讫/余额不足)", "success": false } +``` + +## ⑨ 业务边界 + +- **可冲抵资格**:预付单须 `status=PAID`(钱真出了)且 `availableAmount>0` 且其「冲抵单位」= 付款供应商;未付讫(APPROVED 未出钱)不可勾选。 +- **出纳只付差额**:付款金额锁死 = `actualPayAmount`,冲抵部分无现金流出、无资金流水。 +- **回冲时机**:仅 PENDING 草稿可编辑/删除;驳回(REJECTED)、删除、改草稿均回冲预付余额并置 offset 行 CANCELLED。**付讫(PAID)后无回冲**——已消耗预付不回退(供应商退回走退回形态,只退现金)。 +- **台账外手工单**:无台账锚点的手工付款单同样支持冲抵,行级/头表回写跳过(WARN),不影响付款主流程。 + +## ⑩ 修改前后对比 + +| 项 | 修改前 | 修改后 | +|---|---|---| +| 付款方式 | 只能全额现金 | 可勾选预付冲抵,出纳付差额 | +| `prepayOffsetAmount` | 恒 0 | 真值化 = Σ冲抵 | +| `actualPayAmount` | 恒等于 amount | = amount − 冲抵 | +| 详情 `offsets` | 无 | 返回冲抵明细及状态机 | + +## ⑪ 影响评估 / 回滚 + +- **向后兼容**:不冲抵(不传 `prepayOffsets` 或传空)时行为与旧版完全一致(offset=0、actualPay=amount),旧前端不感知。 +- **回滚**:代码回滚即恢复全额现金逻辑;已产生的冲抵数据(fin_prepay_offset)保留不影响。 + +## ⑫ 注意事项 + +- 列表行 `PaymentRowRespVO` 暂未加 `prepayOffsetAmount`,列表「实付」列如需区分冲抵单,另提需求(详情已全量返回)。 +- 冲抵不改变应付台账 `applied` 占用口径(建单占全额,付讫全额转 paid)。 + +## ⑬ 关联 / 联系人 + +- Issue:https://git.1814.love:8443/wx/HL/issues/8127 +- PR:#8134(地基)/ #8144(建单链路)/ #8145(付讫+回冲)/ #8146(收尾) +- 负责人:yst