文件
hl-api-changelog/changelogs-v2/2026-09/16_7721_报账款模块接入指引-新增接口-管理后台.md
T
2026-09-16 10:02:36 +08:00

356 行
19 KiB
Markdown
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
---
schema: "hl-changelog/v2"
ticket: "finance-reimburse-module-onboarding"
title: "报账款模块整模块接入指引(复核管理 5 接口 + 出纳执行 3 接口,含详情支出行明细与退回重推护栏)"
consumer: "admin"
author: "yst(GIT)"
change_type: "新增接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "verified"
frontend_owner: "mmg"
frontend_ref: "0aa4ec7a962205edf8b1e02664b8c2807b28ed02"
target_release: ""
verified_at: "2026-09-16"
status_note: "报账款(核单→复核→出纳打款/回款)整模块首次对接指引,覆盖 Epic #7721 全链路 + Epic #7764 改进(详情内嵌核单支出行明细 lines、核单反确认加报账单执行护栏 584330、退回可重推)。8 个管理后台接口全部为本期新交付,前端此前无任何报账款文档,按本文一次对接即可。金额口径、状态机、错误码、勾稽勾稽区语义均以内联最终态给出。mmg 2026-09-16 前端已交付:api/finance/reimburse.js 复核 5 接口 + finance/reimburse 复核管理页(列表/详情勾稽区/lines 垫付明细/批准/退回/反审)+ CashierQueuePage REIMBURSE 外部单位线(金额锁死=settleAmount)+ ReimburseConfirmInModal(RECEIVABLE 走 confirm-in 无 amount)+ finance/pay/reimburse 薄壳;错误码透 message 不建字典;spec 22 例、checkpoint 13 项全绿。待后端配菜单行:财务域「报账款」component=finance/reimburse、出纳支付管理「报账款」component=finance/pay/reimburse。2026-09-16 后端 sys_menu 已配但落在「付款管理→报账复核」component=/finance/payable/reimburse,前端当日迁址对齐(复核页 git mv finance/reimburse→finance/payable/reimburse,commit 0aa4ec7a);支付行 finance/pay/reimburse 与配置一致。"
updated_at: "2026-09-16"
base: "dev-v3"
---
# 报账款模块整模块接入指引(复核管理 + 出纳执行)
> **服务**: hl-order-service-v3(hl-finance 模块)
> **类型**: 🆕 整模块新增(本期新交付,前端首次对接)
> **日期**: 2026-09-16
> **影响范围**: 管理后台财务域「报账款」菜单 + 出纳支付管理「报账款」页签
> **覆盖 Epic**: #7721(报账款全链路)+ #7764(详情明细 / reopen 护栏 / 退回重推)
---
## 一、模块定位 & 业务闭环
报账款 = **司机/导游等一线人员的行程费用报账**。一条订单核单(settlement)完成后,系统自动生成一张报账单,走「财务复核 → 出纳执行」两段:
```
核单 confirmSettlement ──推送──▶ 报账单(PENDING)
│
财务复核(本模块复核管理 5 接口)
├─ 批准 approve PENDING→APPROVED(净额=0 两清单直通 CLOSED)
├─ 退回 return PENDING→RETURNED(终态留痕,可重推,见 §六)
└─ 反审 un-approve APPROVED→PENDING(已付讫/已回款不可反审)
│ APPROVED
出纳执行(出纳支付管理,按净额方向二选一)
├─ 净额<0 PAYABLE 公司补司机 → 出纳 pay → PAID(OUT 流水,余额减)
├─ 净额>0 RECEIVABLE 司机回款公司 → 出纳 confirm-in → RECEIVED(IN 流水,余额加)
└─ 净额=0 BALANCED 两清 → 复核批准直通 CLOSED(无支付、无流水)
```
**单据来源唯一**:报账单只由核单推送生成,**不提供新建/编辑/删除接口**。前端只做「复核 + 出纳执行 + 查询」。
---
## 二、金额口径(核心,前端展示勾稽区必读)
报账单金额全部由后端快照算出,前端**只读展示**,不参与计算:
| 字段 | 含义 | 说明 |
|---|---|---|
| `collectableAmount` | 应代收 | 核单总额 − 客户线上已付(剔除司机代收 DRIVER_CASH) |
| `actualCollectedAmount` | 实收代收 | 司机实际代收到的现金(勾稽快照) |
| `underCollectAmount` | 欠收额 | = 应代收 − 实收代收(勾稽留痕,**不阻断**,供复核判断) |
| `advanceAmount` | 预支合计 | 该单已预支给报账人的总额 |
| `cashPaidAmount` | 现付垫付合计 | 报账人现付垫付总额(= 详情 `lines` 明细加总,见 §五) |
| `netAmount` | 净额 | = 应代收 − 预支 − 现付垫付(**有符号**,正负定方向) |
| `settleAmount` | 结算金额 | = \|净额\|(BALANCED 两清为 0),出纳执行金额锁死=此值 |
| `direction` | 方向 | `PAYABLE` 公司应付报账人 / `RECEIVABLE` 报账人应回款 / `BALANCED` 两清 |
> **勾稽区**(`actualCollectedAmount` / `underCollectAmount`)是复核依据:实收 ≠ 应代收时欠收额非 0,复核据此判断是否退回,但系统不强制拦。
---
## 三、复核管理接口(5 个,`/admin/finance/reimburses`)
### 3.1 报账款分页 `GET /admin/finance/reimburses/page`
复核视角列表,支持状态/方向筛选 + 订单号/报账人姓名模糊。
**Query 入参**(继承 PageParam:`pageNo` / `pageSize` 必填):
| 参数 | 必填 | 说明 |
|---|---|---|
| `status` | 否 | 单据状态:PENDING/APPROVED/PAID/RECEIVED/CLOSED/RETURNED;空=全部 |
| `direction` | 否 | 方向:PAYABLE/RECEIVABLE/BALANCED;空=全部 |
| `orderNo` | 否 | 订单号(模糊) |
| `reporterName` | 否 | 报账人姓名(模糊) |
**出参行 `ReimburseRowRespVO`**(金额=JSON number;Long ID=string):
`id / reimburseNo(BZ-前缀) / orderId / orderNo / reporterName / reporterRole(GUIDE/DRIVER/PHOTOGRAPHER) / direction / collectableAmount / actualCollectedAmount / underCollectAmount / advanceAmount / cashPaidAmount / netAmount / settleAmount / status / reviewByName / reviewTime / createTime`
### 3.2 报账详情 `GET /admin/finance/reimburses/{id}`
全字段快照 + 勾稽 + 流水回执 + **核单支出行明细 `lines`**。
出参在分页行字段基础上追加:
| 字段 | 说明 |
|---|---|
| `settlementId` / `versionNo` | 关联核单 ID / 同核单推送版本号(本期恒 1) |
| `reporterAssignmentId` | 主报账人人员分配 ID |
| `reviewBy` / `reviewRemark` | 复核人 ID / 复核意见(退回原因落此列) |
| `fundAccountId` / `payFlowId` / `paidAt` | 出纳执行账户 / 资金流水 ID(一单一流水)/ 付讫到账时间 |
| `flowNo` / `flowDirection` / `balanceAfter` | 流水回执(`payFlowId` 反查回填;**未付款/未回款时三字段均 null**) |
| `lines` | **核单可报账支出行明细**(见 §五);无垫付固定返回 `[]` |
| `remark` / `updateTime` | 备注 / 更新时间 |
### 3.3 复核批准 `PUT /admin/finance/reimburses/{id}/approve`
`PENDING → APPROVED`;**净额=0 两清单直通 `CLOSED`**(不进出纳队列)。
入参 body(可空整 body):`{ "remark": "复核意见,可空,≤512字" }`
### 3.4 退回 `PUT /admin/finance/reimburses/{id}/return`
`PENDING → RETURNED`(终态留痕;退回后可到核单反确认重推,见 §六)。
入参 body(必填):`{ "reason": "退回原因,必填,≤512字" }`
### 3.5 反审 `PUT /admin/finance/reimburses/{id}/un-approve`
`APPROVED → PENDING`,清复核快照。**已付讫(PAID)/已回款(RECEIVED) 不可反审**。无 body。
---
## 四、出纳执行接口(`/admin/finance/cashier`,复用出纳统一出口)
报账款进出纳后**复用出纳支付管理既有 4 接口**,靠 `payType`/`bizType = REIMBURSE` 路由。报账款的执行动作按方向二选一:
### 4.1 待付款队列 `GET /admin/finance/cashier/queue?payType=REIMBURSE`
拉「公司欠司机(PAYABLE)已批准待打款」的报账单。
| Query | 必填 | 说明 |
|---|---|---|
| `payType` | 是 | 报账款传 **`REIMBURSE`**(页签下拉值) |
| `pageNo`/`pageSize` | 是 | 分页 |
> 队列只含 `direction=PAYABLE 且 status=APPROVED` 的报账单;RECEIVABLE(司机回款)不进待付款队列,走下 §4.3。
出参行 `CashierQueueRowRespVO`:`id / bizNo(BZ-单号) / payType=REIMBURSE / payTypeName=报账款 / unitId / unitName / category=报账款(固定) / amount(=settleAmount) / fee / actualAmount / operatorName / createTime / occurDate / status=APPROVED / remark`
### 4.2 登记付款(公司补司机)`POST /admin/finance/cashier/pay`
净额<0(PAYABLE)时,出纳打款给报账人 → 记 OUT 流水 + 回写报账单 `PAID` + 重算账户结存。
| body 字段 | 必填 | 说明 |
|---|---|---|
| `bizType` | ✅ | 传 **`REIMBURSE`** |
| `bizId` | ✅ | 报账单 ID |
| `payAccountId` | ✅ | 出账公司账户 ID(fin_fund_account) |
| `payMethod` | 否 | 付款方式字典 fin_pay_way:CASH/BANK/THIRD_PARTY |
| `payChannel` | 条件 | 仅 `payMethod=THIRD_PARTY` 时传 WXPAY/ALIPAY,其余不传 |
| `amount` | ✅ | 付款金额,**必须=settleAmount**,不等抛 598610 |
| `fee` | 否 | 手续费(≥0,挂出账流水) |
| `voucherNo`/`voucherUrl` | 否 | 付款凭证号 / 凭证影像 URL |
| `payDate` | ✅ | 付款日期 yyyy-MM-dd(可回溯补录) |
> 前端金额框建议**只读回填 settleAmount**(后端已锁死,改了必报 598610)。
### 4.3 收款确认入账(司机回款)`POST /admin/finance/cashier/confirm-in`
净额>0(RECEIVABLE)时,司机把多收尾款交回公司 → 记 IN 流水 + 回写报账单 `RECEIVED`。**入账金额 = settleAmount**。
| body 字段 | 必填 | 说明 |
|---|---|---|
| `bizType` | ✅ | 传 **`REIMBURSE`**(空默认 NONBIZ 业务外收入,报账回款必须显式传) |
| `bizId` | ✅ | 报账单 ID(须 direction=RECEIVABLE 且 status=APPROVED) |
| `payAccountId` | ✅ | 入账公司账户 ID |
| `payMethod` | 否 | 收款方式字典 fin_pay_way:CASH/BANK/THIRD_PARTY |
| `payChannel` | 条件 | 仅 THIRD_PARTY 时传 WXPAY/ALIPAY |
| `voucherNo`/`voucherUrl` | 否 | 收款凭证 |
| `payDate` | ✅ | 收款日期 yyyy-MM-dd |
> `confirm-in` 入参**无 amount 字段**——金额后端取单据 settle_amount,前端不传。方向不符(如给 PAYABLE 单调 confirm-in)抛 599207。
### 4.4 已付款流水台账 `GET /admin/finance/cashier/payments/page`
出纳已付款流水(fin_fund_flow OUT),可按 bizType=REIMBURSE 过滤报账款打款记录。入参 `bizType`/`pageNo`/`pageSize` 等,出参与资金流水台账一致。
**pay / confirm-in 统一出参 `CashierPayRespVO`**:`flowId / flowNo(LS+yyyyMMdd+4位序号) / balanceAfter(本笔记完后结存) / bizId(已回写终态)`
---
## 五、详情支出行明细 `lines`(Epic #7766,复核依据)
报账详情出参 `lines` = **主报账人 CASH_PAID 现付垫付支出行**,供复核看「垫付明细构成」。**只含可报账行**,口径与 `cashPaidAmount` 严格一致(明细加总 == cashPaidAmount)。
`SettlementLineItemVO` 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| `category` / `categoryName` | string | 费用类别码 / 中文名(HOTEL/TICKET/MEAL/GUIDE/PHOTOGRAPHER/OTHER_EXPENSE/SERVICE 等) |
| `itemName` | string | 项目名(住宿=酒店-房型,门票=景区-规格,人员=姓名,车辆=车牌 车型/司机,其他=项目名) |
| `unitPrice` / `quantity` | number | 单价 / 数量(可空) |
| `amount` | number | 实际金额 |
| `reimburseAmount` | number | 报账金额(**加总此列 == cashPaidAmount**) |
| `paymentMethod` / `paymentMethodName` | string | 付款方式(本接口恒 `CASH_PAID` 现付垫付)/ 中文名 |
| `date` | string | 业务日期 yyyy-MM-dd(可空) |
| `remark` | string | 备注(可空) |
> 口径说明(前端无需处理,了解即可):人员行(GUIDE/PHOTOGRAPHER)按 staffId 精确匹配主报账人;车辆现金行(VEHICLE)不计入可报账口径故不进 `lines`。**无垫付时 `lines` 固定返回 `[]`,不是 null。**
---
## 六、退回可重推 + 核单反确认护栏(Epic #7764/#7765)
### 6.1 退回可重推(前端只需知流程,无新接口)
复核退回(RETURNED)是终态留痕,但**金额错误可纠正**:财务退回 → 核单员到订单侧「反确认核单」调整 → 重 confirm 产生**新 settlement_id** → 系统推**新报账单**(BZ 单号递增),旧 RETURNED 单不动。前端在退回提示里告知「退回后可到核单反确认重推」即可。
### 6.2 核单反确认护栏(错误码 584330,跨服务)
为防止「钱已动但核单又改」的资金不一致,订单侧反确认核单接口加了护栏:
- **接口**:`POST /v3/admin/order/{orderId}/settlement/final-snapshots/reopen`(在 order-v3 核单域,**非本模块接口**)
- **护栏**:该订单报账单已进入出纳执行(status ∈ PENDING/APPROVED/PAID/RECEIVED)→ 抛 **584330**,禁止反确认
- **放行**:无报账单 / 仅 RETURNED / CLOSED(净额0两清无流水)
> 前端调核单反确认时若收到 **584330**,提示「该订单报账单已进入出纳执行,禁止反确认核单;如需调整请先退回报账单」。
---
## 七、状态机 & 数据字典
### 7.1 报账单状态 `status`
| 值 | 中文 | 含义 / 可达动作 |
|---|---|---|
| `PENDING` | 待复核 | 可 approve / return |
| `APPROVED` | 已批准 | 可 un-approve;PAYABLE 进出纳队列待 pay;RECEIVABLE 待 confirm-in |
| `PAID` | 已付讫 | 终态(公司已打款);不可反审 |
| `RECEIVED` | 已回款 | 终态(司机已回款);不可反审 |
| `CLOSED` | 两清 | 终态(净额0直通,无流水) |
| `RETURNED` | 已退回 | 终态留痕;可核单反确认重推新单 |
### 7.2 方向 `direction`
`PAYABLE` 公司应付报账人 / `RECEIVABLE` 报账人应回款 / `BALANCED` 两清
### 7.3 出纳付款类型 `payType`(队列页签)
`REIMBURSE` 报账款(单号前缀 `BZ-`)。其余页签值:NONBIZ 业务外支出 / EXPENSE 费用报销 / PAYMENT 应付款 / PREPAY 预付款 / STAFF_LOAN 员工借款。
### 7.4 收付方式 `payMethod`(字典 fin_pay_way)
`CASH` 现金 / `BANK` 银行转账 / `THIRD_PARTY` 三方支付(须配 `payChannel`=WXPAY/ALIPAY)
### 7.5 流水方向 `flowDirection`
`OUT` 出账 / `IN` 入账
---
## 八、错误码
### 8.1 报账域(段位 599200-599299)
| 码 | 含义 | 触发场景 |
|---|---|---|
| 599201 | 报账执行单不存在 | 详情/操作 id 无效或已删 |
| 599202 | 报账单状态非法 | 当前状态不允许此操作(如对 PAID 单 approve) |
| 599203 | 报账单状态流转非法 | 并发推进,条件更新 0 行兜底 |
| 599204 | 该核单已生成报账单 | 幂等命中(重推接缝预留) |
| 599205 | 报账单推送快照数据非法 | 脏数据 fail-fast |
| 599206 | 报账单号生成冲突 | 取号并发撞号,请重试 |
| 599207 | 报账单方向与操作不匹配 | RECEIVABLE 走 pay / PAYABLE 走 confirm-in / BALANCED 进队列 |
| 599208 | 退回原因必填 | return 未传 reason |
### 8.2 出纳域(段位 598600-598699,报账相关)
| 码 | 含义 | 触发场景 |
|---|---|---|
| 598601 | 业务单不存在 | bizId 无效 |
| 598602 | 业务单状态非已批准不可付款 | 对非 APPROVED 单 pay |
| 598603 | 出账/入账账户不存在或已停用 | payAccountId 无效 |
| 598604 | 账户余额不足且不允许透支 | 透支闸拦截 |
| 598605 | 付款金额无效 | amount≤0 或 fee<0 |
| 598606 | 收款确认单状态非法 | confirm-in 单非已批准可入账 |
| 598607 | 付款类型非法 | payType/bizType 非已接通枚举 |
| 598608 | 收付方式与渠道不匹配 | THIRD_PARTY 未传渠道 / CASH,BANK 传了渠道 |
| 598609 | 收付账户与方式不匹配 | 现金方式选银行账户等两级校验 |
| 598610 | 付款金额与单据应付金额不一致 | pay 的 amount ≠ settleAmount(金额锁死) |
### 8.3 核单域(跨服务,reopen 护栏)
| 码 | 含义 | 触发接口 |
|---|---|---|
| 584330 | 报账单已进入出纳执行,禁止反确认核单 | `POST /v3/admin/order/{orderId}/settlement/final-snapshots/reopen`(order-v3) |
---
## 九、示例
### 9.1 复核列表(筛选待复核 + PAYABLE)
```http
GET /admin/finance/reimburses/page?status=PENDING&direction=PAYABLE&pageNo=1&pageSize=20
```
### 9.2 批准 → 出纳打款(PAYABLE 公司补司机)
```http
PUT /admin/finance/reimburses/{id}/approve
{ "remark": "复核无误" }
# 待付款队列取单
GET /admin/finance/cashier/queue?payType=REIMBURSE&pageNo=1&pageSize=20
# 出纳打款(金额锁死=settleAmount)
POST /admin/finance/cashier/pay
{ "bizType":"REIMBURSE", "bizId":"<报账单ID>", "payAccountId":"<账户ID>",
"payMethod":"BANK", "amount":975.00, "payDate":"2026-09-16" }
```
### 9.3 司机回款(RECEIVABLE)
```http
POST /admin/finance/cashier/confirm-in
{ "bizType":"REIMBURSE", "bizId":"<报账单ID>", "payAccountId":"<账户ID>",
"payMethod":"CASH", "payDate":"2026-09-16" }
```
### 9.4 边界:金额不符 / 方向不符 / 反确认被拦
```http
# amount≠settleAmount → 598610
POST /admin/finance/cashier/pay {..."amount":999.00...} → 598610 付款金额与单据应付金额不一致
# PAYABLE 单调 confirm-in → 599207
POST /admin/finance/cashier/confirm-in {..."bizId":"<PAYABLE单>"...} → 599207 方向与操作不匹配
# 报账单已进执行 → 核单反确认 584330
POST /v3/admin/order/{orderId}/settlement/final-snapshots/reopen → 584330 禁止反确认核单
```
---
## 十、影响评估 / 回滚
- **纯新增模块**,前端首次对接,无存量调用方,无回滚负担。
- 复核/出纳接口均已部署测试服并行为级验证通过。
- 若前端暂不上报账款页面,后端模块独立运行不受影响(报账单仍由核单推送正常生成)。
## 十一、注意事项
1. **金额一律只读**:报账单所有金额(含勾稽区、settleAmount、lines)由后端快照算出,前端展示即可,不要本地重算。
2. **出纳金额锁死**:pay 的 `amount` 必须 = `settleAmount`;confirm-in **不传 amount**。建议前端金额框只读回填。
3. **Long ID 是 string**:所有 ID(id/orderId/settlementId/bizId/payFlowId 等)序列化为 string,前端按字符串处理防精度丢失。
4. **方向决定动作**:一张报账单面前只有一个可点按钮——PAYABLE 显示「付款」(pay)、RECEIVABLE 显示「收款入账」(confirm-in)、BALANCED/PAID/RECEIVED/CLOSED/RETURNED 均不进出纳。
5. **流水回执可空**:详情的 `flowNo/flowDirection/balanceAfter` 在未付款/未回款时为 null,前端做好空态。
## 十二、关联 / 联系人
- Epic #7721 报账款全链路:[Issue #7721](https://git.1814.love:8443/wx/HL/issues/7721)
- Epic #7764 报账款改进:[Issue #7764](https://git.1814.love:8443/wx/HL/issues/7764)(详情明细 #7766 / reopen 护栏 #7765)
- 合并 PR:[#7771](https://git.1814.love:8443/wx/HL/pulls/7771)(护栏+明细)、[#7774](https://git.1814.love:8443/wx/HL/pulls/7774)(文档+原型)
- 负责人:腰苏图(yst)| 反馈:财务域后端对接群 / 直接 @yst