--- schema: "hl-changelog/v2" ticket: "5953" title: "主报账表展示其他收入/其他支出明细(不影响报账人净额)" consumer: "admin" change_type: "修改接口" author: "yst" backend_status: "deployed" gateway_status: "verified" frontend_status: "not_required" frontend_owner: "mmg" frontend_ref: "4306b65a" target_release: "" verified_at: "2026-08-13" status_note: "PR #5954 已合并 dev-v3(merge commit d945ffc3d6)。纯追加式变更:incomeLines 追加 OTHER_INCOME 其他收入展示行、expenseLines 追加 OTHER_EXPENSE 其他支出展示行并扩充行字段,baseInfo 汇总口径零漂移;字典 settlement_report_line_type 补 OTHER_EXPENSE(user-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`。顶层 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 | 仅 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 | 无凭证不输出该键 | 凭证 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 | 无权限访问 | 房务角色(HOUSE)JWT 调用 | | 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": [] } ``` **边界 2:OTHER_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_001(sys_dict_data 101457);该迁移未部署前 typeName 会落 null,前端需兜底显示原 code。 ### 11.2 回滚方案 - 后端回滚 = revert PR #5954 的 merge commit(d945ffc3d6),重启 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 #5953:https://git.1814.love:8443/wx/HL/issues/5953 - PR #5954:https://git.1814.love:8443/wx/HL/pulls/5954 - Commit(merge):https://git.1814.love:8443/wx/HL/commit/d945ffc3d6 - 服务:hl-order-service-v3(端口 8086);字典迁移在 hl-user-service(V20260813_001,随 user-service 部署生效) - 后端负责人:yst(腰苏图) ## 14. 验证证据 - 后端单测:SettlementReportFlowServiceTest / SettlementReportLabelEnricherTest / SettlementReportLineConverterTest 覆盖 OTHER_INCOME/OTHER_EXPENSE 展示行组装、汇总口径零漂移(代收仍只算 DRIVER_CASH 行、可报账支出仍只算 CASH_PAID 行)、字典 label 回填,PR #5954 CI 通过。 - 代码已合并 dev-v3(merge commit d945ffc3d6)并部署测试服;字典迁移 V20260813_001 随 hl-user-service 部署生效(INSERT IGNORE 幂等)。 - 前端联调验证点:无其他收支订单响应与修改前一致;含其他收支订单按 §8.1 对账关系核对(数组和 ≠ 汇总值属预期)。