docs(changelog): 主报账表展示其他收入/其他支出明细(不影响报账人净额)(#5953 / PR #5954)管理后台
所有检测均成功
changelog-filename-gate / validate (push) Successful in 1s

这个提交包含在:
yaosutu 2026-08-13 14:31:29 +08:00
父节点 17bc59e6d8
当前提交 0a689d93c5

查看文件

@ -0,0 +1,408 @@
---
schema: "hl-changelog/v2"
ticket: "5953"
title: "主报账表展示其他收入/其他支出明细(不影响报账人净额)"
consumer: "admin"
change_type: "修改接口"
author: "yst"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "pending"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: "PR #5954 已合并 dev-v3merge commit d945ffc3d6。纯追加式变更incomeLines 追加 OTHER_INCOME 其他收入展示行、expenseLines 追加 OTHER_EXPENSE 其他支出展示行并扩充行字段,baseInfo 汇总口径零漂移;字典 settlement_report_line_type 补 OTHER_EXPENSEuser-service Flyway V20260813_001,随 hl-user-service 部署生效)。"
updated_at: "2026-08-13"
base: "dev-v3"
---
# 【修改接口·管理后台】主报账表展示其他收入/其他支出明细(不影响报账人净额)(#5953
## 1. 接口背景
主报账人报账表reimbursement是管理后台订单核单页查看主报账人通常是司机代收、垫付支出、预支与净额结算情况的只读报表。
此前报表有两个信息缺口:
- **收入侧**:只有 DRIVER_CASH_RECEIPT报账人现金收款一类行,订单的「其他收入」升级房型、下马酒等逐项增收完全看不到,财务对账时要跳到别的页面查。
- **支出侧**只含报账人现金垫付CASH_PAID的支出,「其他支出」分类其他费用/补贴)整类不透出,签单/公司直付的其他支出也无从展示。
本次变更把 **OTHER_INCOME 其他收入****OTHER_EXPENSE 其他支出** 两类的逐项明细以**展示行**形式追加进报账表:**纯展示、不并入 baseInfo 任何汇总值**,报账人净额口径与之前完全一致(零漂移)。
## 2. 变更清单
| # | 位置 | 变更 | 类型 |
|---|------|------|------|
| 1 | incomeLines | 追加 OTHER_INCOME 其他收入展示行type=OTHER_INCOME,逐行透出 itemName/content/unitPrice/quantity/amount/paymentMethod(+Name)/sourceType(+Name)/remark/voucherUrls | ✨ 新增展示行 |
| 2 | incomeLines 元素 | 新增 9 个字段itemName / content / unitPrice / quantity / paymentMethod / paymentMethodName / sourceType / sourceTypeName / voucherUrls仅 OTHER_INCOME 行输出) | ✨ 新增字段 |
| 3 | expenseLines | 追加 OTHER_EXPENSE 其他支出展示行type=OTHER_EXPENSE,整类追加在支出行数组尾部,透出实际付款方式不再固定 CASH_PAID | ✨ 新增展示行 |
| 4 | expenseLines 元素 | 新增 8 个字段type / typeName / expenseType / expenseTypeName / subsidyType / subsidyTypeName / sourceType / sourceTypeName仅 OTHER_EXPENSE 展示行输出 type 系字段) | ✨ 新增字段 |
| 5 | baseInfo 汇总口径 | **不变但更明确**primaryReporterCollectedAmount 仍只算 DRIVER_CASH_RECEIPT 行;reportablePaidCostAmount 仍只算 CASH_PAID 垫付行(含 OTHER_EXPENSE 分类中的 CASH_PAID 行;reporterNetAmount 公式不变 | 🔧 口径声明(数值零漂移) |
| 6 | expenseLines 排序 | OTHER_EXPENSE 分类的 CASH_PAID 行**从原主排序块移到支出行数组尾部**(整类统一走尾部展示块) | 🔧 行为变化 |
| 7 | 字典 | settlement_report_line_type 新增 OTHER_EXPENSE=其他支出dict_data_id=101457 | ✨ 新增字典值 |
无入参变化、无新接口、无删除字段,属**非破坏性追加**。
## 3. 接口详情
| 项 | 值 |
|---|---|
| 方法 + 路径 | GET /v3/admin/order/{orderId}/settlement/reports/reimbursement |
| 接口名 | 查询主报账人报账表 |
| 使用场景 | 管理后台订单核单页,查看主报账人代收/垫付/预支/净额结算报表(含其他收入/其他支出逐项展示) |
| 认证 | 管理后台 JWT/v3/admin/* 走网关鉴权) |
| 角色限制 | 房务角色HOUSE不可访问,调了会被 403 拦截 |
| 幂等性 | 只读查询,幂等 |
| 限流 | 走网关默认限流,无接口级特殊限流 |
## 4. 接口入参
### 4.1 路径参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| orderId | Long | 是 | 订单 ID,必须大于 0否则 400「订单 ID 必须大于 0」 |
### 4.2 请求体 / Query
无请求体、无 Query 参数。
## 5. 出参字段
返回 `Result<SettlementReimbursementReportRespVO>`。顶层 4 个字段不变baseInfo / incomeLines / expenseLines / advanceLines。baseInfo 与 advanceLines 字段结构**本次零变化**baseInfo 汇总口径见 §9,下面只列**有变化的 incomeLines / expenseLines**。
### 5.1 incomeLines 元素字段表两类行DRIVER_CASH_RECEIPT + OTHER_INCOME
| 字段 | 类型 | 输出条件 | 说明 |
|------|------|----------|------|
| type | String | 恒输出 | 行类型DRIVER_CASH_RECEIPT报账人现金收款/ **OTHER_INCOME其他收入展示行,本次新增** |
| typeName | String | 恒输出 | 行类型中文名(字典 settlement_report_line_type |
| receiptId | Long(String) | 仅收款行 | 线下收款记录 ID,序列化为字符串 |
| amount | BigDecimal | 恒输出 | 金额,保留两位小数 |
| channel | String | 仅收款行 | 收款渠道DRIVER_CASH / BANK_TRANSFER / CONSULTANT_COLLECTION |
| channelName | String | 仅收款行 | 收款渠道中文名(枚举 label |
| payType | String | 仅收款行 | 收款款项类型DEPOSIT / FULL / BALANCE |
| payTypeName | String | 仅收款行 | 款项类型中文名(枚举 label |
| collectorStaffId | Long(String) | 仅收款行 | 收款人人员安排 ID,序列化为字符串 |
| collectorName | String | 仅收款行 | 收款人姓名 |
| collectorRole | String | 仅收款行 | 收款人角色(如 DRIVER |
| collectorRoleName | String | 仅收款行 | 收款人角色中文名(字典 staff_role |
| receivedAt | String | 仅收款行 | 收款时间,格式 yyyy-MM-dd HH:mm:ss |
| remark | String | 无备注不输出 | 备注 |
| **itemName** | String | **仅 OTHER_INCOME 行** | 项目名(与支出行 / 明细 tab 的 itemName 同义对齐,如「升级房型」) |
| **content** | String | 仅 OTHER_INCOME 行,无规格不输出 | 规格/内容(如「豪华蒙古包」) |
| **unitPrice** | BigDecimal | 仅 OTHER_INCOME 行 | 单价,保留两位小数 |
| **quantity** | BigDecimal | 仅 OTHER_INCOME 行 | 数量 |
| **paymentMethod** | String | 仅 OTHER_INCOME 行 | 收付款方式CASH_PAID / COMPANY_PAID / SIGNED |
| **paymentMethodName** | String | 仅 OTHER_INCOME 行 | 收付款方式中文名(字典 settlement_payment_method,缺值回退硬编码 |
| **sourceType** | String | 仅 OTHER_INCOME 行,无来源不输出 | 明细来源类型(如 ORDER_SURCHARGE,全量取值见 §6 |
| **sourceTypeName** | String | 仅 OTHER_INCOME 行 | 明细来源类型中文名SettlementDetailSourceType 枚举 label |
| **voucherUrls** | Array<String> | 仅 OTHER_INCOME 行,无凭证不输出该键 | 凭证 URL 数组 |
**排序**收款行DRIVER_CASH_RECEIPT按收款时间升序在前,OTHER_INCOME 展示行按分类快照稳定序**追加在后**。
### 5.2 expenseLines 元素字段表CASH_PAID 垫付行 + OTHER_EXPENSE 展示行)
| 字段 | 类型 | 输出条件 | 说明 |
|------|------|----------|------|
| **type** | String | **仅 OTHER_EXPENSE 展示行输出,其余支出行不输出该键** | 行类型,固定 OTHER_EXPENSE |
| **typeName** | String | 仅 OTHER_EXPENSE 展示行 | 行类型中文名(字典 settlement_report_line_type,值「其他支出」 |
| category | String | 恒输出 | 费用类别HOTEL / TICKET / MEAL / VEHICLE / GUIDE / PHOTOGRAPHER / OTHER_EXPENSE / INSURANCE |
| categoryName | String | 恒输出 | 费用类别中文名(字典 settlement_category |
| itemName | String | 恒输出 | 项目名(分类特有信息折叠:住宿=酒店-房型,餐食=餐食名(餐类型),其他支出=项目名 等) |
| unitPrice | BigDecimal | 无单价概念不输出 | 单价,保留两位小数 |
| quantity | BigDecimal | 无数量概念不输出 | 数量 |
| amount | BigDecimal | 恒输出 | 实际金额,保留两位小数 |
| reimburseAmount | BigDecimal | 恒输出 | 报账金额;注意 **OTHER_EXPENSE 非 CASH_PAID 展示行的 reimburseAmount 也是全额**(仅展示口径,不代表可报账),前端自算合计见 §9 警示 |
| paymentMethod | String | 恒输出 | 付款方式CASH_PAID / COMPANY_PAID / SIGNED;非 OTHER_EXPENSE 支出行固定 CASH_PAID,**OTHER_EXPENSE 展示行透出实际付款方式** |
| paymentMethodName | String | 恒输出 | 付款方式中文名(字典 settlement_payment_method,缺值回退硬编码 |
| date | String | 无日期概念不输出 | 业务日期,格式 yyyy-MM-dd |
| remark | String | 无备注不输出 | 备注 |
| voucherUrls | Array<String> | 无凭证不输出该键 | 凭证 URL 数组 |
| **expenseType** | String | 仅 OTHER_EXPENSE 展示行EXPENSE 族) | 其他费用类型(如 OTHER |
| **expenseTypeName** | String | 仅 OTHER_EXPENSE 展示行EXPENSE 族) | 其他费用类型中文名(字典 expense_type |
| **subsidyType** | String | 仅 OTHER_EXPENSE 展示行SUBSIDY 族) | 补贴类型PHONE / OVERTIME |
| **subsidyTypeName** | String | 仅 OTHER_EXPENSE 展示行SUBSIDY 族) | 补贴类型中文名(字典 subsidy_type,如「话补」 |
| **sourceType** | String | 仅 OTHER_EXPENSE 展示行,无来源不输出 | 明细来源类型(全量取值见 §6 |
| **sourceTypeName** | String | 仅 OTHER_EXPENSE 展示行 | 明细来源类型中文名SettlementDetailSourceType 枚举 label |
**排序**:原主排序块(全分类 CASH_PAID 垫付行,不含 OTHER_EXPENSE在前;OTHER_EXPENSE 分类**整类追加在支出行数组尾部**(含其中的 CASH_PAID 行——这类行原本混在主排序块里,本次统一移到尾部展示块)。
### 5.3 baseInfo / advanceLines
结构零变化。baseInfo 汇总口径(数值与修改前完全一致):
- primaryReporterCollectedAmount = 仅 DRIVER_CASH_RECEIPT 收款行合计(**不含** OTHER_INCOME 展示行)
- reportablePaidCostAmount = 仅 CASH_PAID 现金垫付支出行合计(**含** OTHER_EXPENSE 分类中的 CASH_PAID 行,不含其它付款方式展示行)
- reporterNetAmount = 代收 + 预支 - 支出,公式不变
## 6. 枚举 / 数据字典
| 字段 | 来源 | 取值 |
|------|------|------|
| incomeLines[].type | settlement_report_line_type 字典 | DRIVER_CASH_RECEIPT司机现金收款/ **OTHER_INCOME其他收入** |
| expenseLines[].type | settlement_report_line_type 字典 | **OTHER_EXPENSE其他支出—— 本次新增字典值**dict_data_id=101457,sort=70;其余支出行不输出 type 键 |
| incomeLines[].channel | PaymentChannelEnum 枚举 | DRIVER_CASH / BANK_TRANSFER / CONSULTANT_COLLECTION |
| incomeLines[].payType | PayType 枚举 | DEPOSIT订金/ FULL全款/ BALANCE尾款 |
| *.paymentMethod | settlement_payment_method 字典 | CASH_PAID现金已付/ COMPANY_PAID公司直付/ SIGNED签单 |
| expenseLines[].expenseType | expense_type 字典 | 如 OTHER其他等 |
| expenseLines[].subsidyType | subsidy_type 字典 | PHONE话补/ OVERTIME加班补等 |
| *.sourceType | SettlementDetailSourceType 枚举 | MANUAL手工/ HOUSE_ASSIGNMENT / SCENIC_ASSIGNMENT / ACTIVITY_ASSIGNMENT / MEAL_ASSIGNMENT / FLEET / STAFF_ASSIGNMENT / ORDER_SURCHARGE订单增费/ SYSTEM |
| collectorRole 等角色字段 | staff_role 字典 | DRIVER司机/ GUIDE导游等 |
## 7. 错误码
本次无新增错误码,沿用既有:
| code | message | 触发场景 |
|------|---------|----------|
| 400 | 订单 ID 必须大于 0 | orderId 路径参数校验失败 |
| 403 | 无权限访问 | 房务角色HOUSEJWT 调用 |
| 581007 | 订单不存在 | orderId 查不到订单 |
## 8. 示例
### 8.1 典型成功(含 OTHER_INCOME / OTHER_EXPENSE 展示行)
GET /v3/admin/order/2087088947225038849/settlement/reports/reimbursement
```json
{
"code": 200,
"message": "成功",
"data": {
"baseInfo": {
"orderId": "2087088947225038849",
"orderNo": "HL20260730001",
"primaryReporterName": "司机甲",
"primaryReporterRole": "DRIVER",
"primaryReporterCollectedAmount": 2000.00,
"approvedAdvanceAmount": 500.00,
"reportablePaidCostAmount": 1500.00,
"reporterNetAmount": 1000.00,
"outstandingAmount": 0.00
},
"incomeLines": [
{
"type": "DRIVER_CASH_RECEIPT",
"typeName": "司机现金收款",
"receiptId": "8001",
"amount": 2000.00,
"channel": "DRIVER_CASH",
"channelName": "报账人收款",
"payType": "BALANCE",
"payTypeName": "尾款",
"collectorStaffId": "7001",
"collectorName": "司机甲",
"collectorRole": "DRIVER",
"collectorRoleName": "司机",
"receivedAt": "2026-07-30 18:20:30",
"remark": "尾款现金"
},
{
"type": "OTHER_INCOME",
"typeName": "其他收入",
"itemName": "升级房型",
"content": "豪华蒙古包",
"unitPrice": 50.00,
"quantity": 2,
"amount": 100.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"sourceType": "ORDER_SURCHARGE",
"sourceTypeName": "订单增费",
"remark": "客人现场升级",
"voucherUrls": ["https://oss/i1.jpg"]
},
{
"type": "OTHER_INCOME",
"typeName": "其他收入",
"itemName": "下马酒",
"unitPrice": 50.00,
"quantity": 1,
"amount": 50.00,
"paymentMethod": "SIGNED",
"paymentMethodName": "签单",
"sourceType": "MANUAL",
"sourceTypeName": "手工"
}
],
"expenseLines": [
{
"category": "HOTEL",
"categoryName": "住宿",
"itemName": "草原明珠大酒店-标间",
"unitPrice": 400.00,
"quantity": 3,
"amount": 1200.00,
"reimburseAmount": 1200.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"date": "2026-07-30",
"voucherUrls": ["https://oss/v1.jpg"]
},
{
"type": "OTHER_EXPENSE",
"typeName": "其他支出",
"category": "OTHER_EXPENSE",
"categoryName": "其他支出",
"itemName": "景区停车费",
"amount": 300.00,
"reimburseAmount": 300.00,
"paymentMethod": "CASH_PAID",
"paymentMethodName": "现金已付",
"expenseType": "OTHER",
"expenseTypeName": "其他",
"sourceType": "MANUAL",
"sourceTypeName": "手工",
"voucherUrls": ["https://oss/v2.jpg"]
},
{
"type": "OTHER_EXPENSE",
"typeName": "其他支出",
"category": "OTHER_EXPENSE",
"categoryName": "其他支出",
"itemName": "司机话补",
"amount": 200.00,
"reimburseAmount": 200.00,
"paymentMethod": "SIGNED",
"paymentMethodName": "签单",
"subsidyType": "PHONE",
"subsidyTypeName": "话补",
"sourceType": "STAFF_ASSIGNMENT",
"sourceTypeName": "人员安排"
}
],
"advanceLines": []
},
"success": true
}
```
注意上例的**对账关系**(本变更的核心语义):
- incomeLines 三行 amount 合计 2150.00,但 baseInfo.primaryReporterCollectedAmount = **2000.00**(只算 DRIVER_CASH_RECEIPT 行)—— 数组和 ≠ 汇总值属**预期**。
- expenseLines 三行 amount 合计 1700.00,但 baseInfo.reportablePaidCostAmount = **1500.00**(只算 CASH_PAID 行:住宿 1200 + 其他支出现金垫付 300;签单的话补 200 仅展示不入账)。
- reporterNetAmount = 2000 + 500 - 1500 = **1000.00**,与修改前公式完全一致。
### 8.2 边界情况
**边界 1无其他收入/其他支出** —— incomeLines / expenseLines 只有原有行(或空数组 []),不出现 OTHER_INCOME / OTHER_EXPENSE 行;新增字段键一律不输出NON_NULL 省略),与修改前响应完全一致:
```json
{ "incomeLines": [], "expenseLines": [], "advanceLines": [] }
```
**边界 2OTHER_INCOME 行无规格/无凭证/无来源** —— content / voucherUrls / sourceType 键不输出(不是 null
```json
{
"type": "OTHER_INCOME",
"typeName": "其他收入",
"itemName": "下马酒",
"unitPrice": 50.00,
"quantity": 1,
"amount": 50.00,
"paymentMethod": "COMPANY_PAID",
"paymentMethodName": "公司直付"
}
```
### 8.3 业务失败
**房务角色HOUSE访问被拦**
```json
{ "code": 403, "message": "无权限访问", "success": false }
```
**订单不存在**
```json
{ "code": 581007, "message": "订单不存在", "success": false }
```
## 9. 业务边界
**适用**
- 核单页查看主报账人结算全貌:代收 + 垫付 + 预支 + 净额baseInfo,以及其他收入 / 其他支出的逐项展示incomeLines / expenseLines 展示行)。
**不适用**
- 拿 incomeLines / expenseLines **数组自算合计去对 baseInfo 汇总值** —— 两者口径不同(见下「特殊边界」),对不上属预期。
- 想看整单收入/成本/毛利 —— 走单团核算表reports/group,报账表是主报账人维度。
**特殊边界(前端必知)**
1. **数组和 ≠ 汇总值属预期**OTHER_INCOME / OTHER_EXPENSE 展示行**纯展示不计入** baseInfo 任何汇总。primaryReporterCollectedAmount 仍只算 DRIVER_CASH_RECEIPT 行;reportablePaidCostAmount 仍只算 CASH_PAID 垫付行;reporterNetAmount 公式不变。**汇总值一律直接读 baseInfo,不要前端自算。**
2. **OTHER_EXPENSE 非 CASH_PAID 展示行的 reimburseAmount 也是全额**(如签单话补 reimburseAmount=200.00),但它不代表可报账。前端若坚持自算 sum(reimburseAmount),必须**按 type=OTHER_EXPENSE 排除展示行**(更精确的做法是按 paymentMethod=CASH_PAID 过滤,与后端口径一致;直接排除全部 OTHER_EXPENSE 行会漏掉其中 CASH_PAID 垫付行,与 reportablePaidCostAmount 差出该行金额)。
3. **OTHER_EXPENSE 的 CASH_PAID 行位置变了**:这类行原本混在支出行主排序块里,本次整类移到**支出行数组尾部**。若前端曾按「位置/下标」识别这类行,需改为按 type=OTHER_EXPENSE 识别。
4. **行类型判别方式两侧不对称**
- 收入行:靠 **type 值**判别DRIVER_CASH_RECEIPT / OTHER_INCOME,type 恒输出);
- 支出行:靠 **type 键是否出现**判别(仅 OTHER_EXPENSE 展示行输出 type=OTHER_EXPENSE,其余支出行**没有 type 键**——不是 null,是键不存在
5. OTHER_EXPENSE 展示行**全量付款方式**都透出CASH_PAID / COMPANY_PAID / SIGNED,不再像普通支出行那样固定 CASH_PAID。
## 10. 修改前后对比
### 10.1 字段级对比
| 位置 | 字段 | 修改前 | 修改后 |
|------|------|--------|--------|
| incomeLines | type 取值 | 仅 DRIVER_CASH_RECEIPT | DRIVER_CASH_RECEIPT + **OTHER_INCOME** |
| incomeLines 元素 | itemName / content / unitPrice / quantity / paymentMethod(+Name) / sourceType(+Name) / voucherUrls | 无 | **新增**(仅 OTHER_INCOME 行输出) |
| expenseLines 元素 | type / typeName | 无 | **新增**(仅 OTHER_EXPENSE 展示行输出) |
| expenseLines 元素 | expenseType(+Name) / subsidyType(+Name) / sourceType(+Name) | 无 | **新增**(仅 OTHER_EXPENSE 展示行输出) |
| expenseLines | paymentMethod 取值 | 固定 CASH_PAID | 普通支出行仍固定 CASH_PAID;**OTHER_EXPENSE 展示行透出实际付款方式**CASH_PAID / COMPANY_PAID / SIGNED |
| baseInfo | 全部汇总字段 | 原口径 | **零变化**(仅口径描述更明确,数值不变) |
| 字典 | settlement_report_line_type | 6 值(无 OTHER_EXPENSE | **+OTHER_EXPENSE=其他支出** |
### 10.2 行为级对比
| 场景 | 修改前 | 修改后 |
|------|--------|--------|
| 其他收入逐项 | 报账表完全看不到 | incomeLines 尾部追加 OTHER_INCOME 展示行 |
| 其他支出逐项 | 仅 CASH_PAID 垫付行混在主排序块 | OTHER_EXPENSE 整类(全付款方式)追加在 expenseLines 尾部展示 |
| OTHER_EXPENSE CASH_PAID 行位置 | 支出行主排序块内(按金额等排序) | **移到支出行数组尾部**展示块 |
| baseInfo 汇总值 | 代收=收款行合计,支出=CASH_PAID 合计 | **数值逐分不差**(展示行不入账) |
| 无其他收支的订单 | 原样 | **响应与原样完全一致**(新行不出现、新字段键不输出) |
## 11. 影响评估 / 回滚
### 11.1 影响评估
- **破坏兼容性**:非破坏性。纯追加行 + 追加字段,既有字段名/类型/结构零变化;无其他收支的订单响应与修改前逐字节一致。
- **前端是否必须同步上线****不强制**。只读 baseInfo 汇总 + 渲染既有行的前端**零改动可继续用**;但要看到其他收入/其他支出明细,需按 §5 新行结构做渲染,并按 §9 特殊边界处理(汇总读 baseInfo、支出行按 type 键识别 OTHER_EXPENSE
- **前端如有 workaround 需清理**:若前端曾从别的接口拼「其他收入/其他支出」进报账页,可改读本接口展示行;若前端曾自算 sum(incomeLines.amount) 当代收,需改读 baseInfo.primaryReporterCollectedAmount此前碰巧相等,现在会虚高
- **字典依赖**expenseLines[].typeName「其他支出」依赖 hl-user-service 字典迁移 V20260813_001sys_dict_data 101457;该迁移未部署前 typeName 会落 null,前端需兜底显示原 code。
### 11.2 回滚方案
- 后端回滚 = revert PR #5954 的 merge commitd945ffc3d6,重启 hl-order-service-v3。
- 字典迁移残留V20260813_001 新增的 OTHER_EXPENSE 字典值在回滚后无消费方,残留无害,无需回退。
- 零业务表 DDL,回滚无数据残留风险。
## 12. 注意事项
1. **汇总只读 baseInfo**primaryReporterCollectedAmount / reportablePaidCostAmount / reporterNetAmount 是后端算好的权威值,前端不要拿 incomeLines / expenseLines 数组自算(口径不同,必然对不上)。
2. **NON_NULL 省略**incomeLines / expenseLines 元素带 @JsonInclude(NON_NULL),**null 字段不下发该 key**(不是下 null;OTHER_INCOME / OTHER_EXPENSE 专属字段在普通行上键不存在,前端读取必须兜底。
3. **行判别**:收入行看 type 值;支出行看 type 键**是否存在**JS 可用 'type' in line 判别)。
4. **Long 主键序列化为字符串**orderId / receiptId / collectorStaffId 等),前端按 string 处理,不要 Number() 转换。
5. OTHER_EXPENSE 展示行的 expenseType 与 subsidyType 互斥EXPENSE 族出费用类型 / SUBSIDY 族出补贴类型),渲染时按存在的键展示即可。
6. 排序约定:收入行 = 收款行(按收款时间升序)在前 + OTHER_INCOME 展示行在后;支出行 = 主排序块在前 + OTHER_EXPENSE 展示块在尾部。前端按数组顺序渲染即可,不要自行重排。
7. 本变更只影响 reimbursement 报账表;单团核算表reports/group结构本次零变化。
## 13. 关联 / 联系人
- Issue #5953https://git.1814.love:8443/wx/HL/issues/5953
- PR #5954https://git.1814.love:8443/wx/HL/pulls/5954
- Commitmergehttps://git.1814.love:8443/wx/HL/commit/d945ffc3d6
- 服务hl-order-service-v3端口 8086;字典迁移在 hl-user-serviceV20260813_001,随 user-service 部署生效)
- 后端负责人yst腰苏图
## 14. 验证证据
- 后端单测SettlementReportFlowServiceTest / SettlementReportLabelEnricherTest / SettlementReportLineConverterTest 覆盖 OTHER_INCOME/OTHER_EXPENSE 展示行组装、汇总口径零漂移(代收仍只算 DRIVER_CASH 行、可报账支出仍只算 CASH_PAID 行)、字典 label 回填,PR #5954 CI 通过。
- 代码已合并 dev-v3merge commit d945ffc3d6并部署测试服;字典迁移 V20260813_001 随 hl-user-service 部署生效INSERT IGNORE 幂等)。
- 前端联调验证点:无其他收支订单响应与修改前一致;含其他收支订单按 §8.1 对账关系核对(数组和 ≠ 汇总值属预期)。