---
schema: "hl-changelog/v2"
ticket: "5969"
title: "核单车辆费用归其他支出——VEHICLE 只留 Fleet 配车日租，5 类车辆费用并入 OTHER_EXPENSE"
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 #5970 已合并 dev-v3（merge commit 522179ecfe），测试服已验证（实证单 HL20260811181352799：油费 300 归其他支出块，用车块只剩 3 行 Fleet 日租 3000）。破坏性变化：单团核算表 vehicleLines 行删 expenseType/expenseTypeName/projectName/expenseDate 4 字段；FUEL/TOLL/PARKING/RENTAL/MAINTENANCE 5 类车辆费用行从 vehicleLines 迁到 otherExpenseLines；otherExpenseLines.expenseType 值域由 OTHER 扩为 6 类。仅出参/归属口径变化，无入参变化、无 DDL。"
updated_at: "2026-08-15"
base: "dev-v3"
---

# 【修改接口·管理后台】核单车辆费用归其他支出——VEHICLE 只留 Fleet 配车日租，5 类车辆费用并入 OTHER_EXPENSE（#5969）

## 1. 接口背景

单团核算表（reports/group）是管理后台订单核单页查看整团收入、成本、毛利全貌的只读报表，成本按 8 分类逐项展开（住宿/门票/餐食/用车/导游/摄影/其他支出/保险）。

此前分类口径存在一个错位：**油费、过路费、停车费、租车费、维修保养 5 类车辆费用在核单录入界面上本来就是在「其他支出」tab 录入的**，但单团核算表却把它们归到「用车（VEHICLE）」分类下展示，和录入界面不一致，财务看报表时同一笔费用录入位置和归集位置对不上。

本次变更把报表分类口径对齐录入界面：

- 5 类车辆费用（FUEL/TOLL/PARKING/RENTAL/MAINTENANCE）从「用车」分类移到「其他支出（OTHER_EXPENSE）」分类；
- 「用车（VEHICLE）」分类此后只承载 Fleet 车务配车日租行（vehicle_fee 表逐日明细）；
- 主报账人报账表（reports/reimbursement）的 OTHER_EXPENSE 展示块归属同步随动。

无入参变化、无新接口、无 DDL；totalCost 总成本口径不变。

## 2. 变更清单

| # | 位置 | 变更 | 类型 |
|---|------|------|------|
| 1 | vehicleLines[] 行 | **字段删除**：expenseType / expenseTypeName / projectName / expenseDate 4 个字段不再下发（车辆费用行已迁出本数组，这 4 个字段失去载体） | ⚠️ 破坏性删除 |
| 2 | vehicleLines[] 行归属 | **行为变化**：数组只含 Fleet 配车日租行（sourceType=FLEET）；不再出现 5 类车辆费用行 | 🔧 行为变化 |
| 3 | otherExpenseLines[] 行归属 | **行为变化**：新增承载 5 类车辆费用行（expenseType=FUEL/TOLL/PARKING/RENTAL/MAINTENANCE），与原 OTHER 费用行、PHONE/OVERTIME 补贴行同数组混排（稀疏并集，每行仅本族字段非 null） | 🔧 行为变化 |
| 4 | otherExpenseLines[].expenseType | **值域扩大**：原来恒为 OTHER，现在可能返回 OTHER/FUEL/TOLL/PARKING/RENTAL/MAINTENANCE 6 值之一 | ✨ 枚举值域扩大 |
| 5 | 分类小计口径 | vehicleLines 合计下降、otherExpenseLines 合计上升（同一批行搬位置）；**totalCost / paidCost / unpaidCost / grossProfit 不变** | 📝 口径声明 |
| 6 | 主报账人报账表 expenseLines | OTHER_EXPENSE 展示块（type=OTHER_EXPENSE 的行）同步纳入 5 类车辆费用行，其 expenseType 值域同步扩为 6 类 | 🔧 行为变化 |
| 7 | 预览态未确认行口径 | 未确认（UNCONFIRMED）车辆费用行旧口径挂 VEHICLE 下不计入成本；新口径归 OTHER_EXPENSE，与 OTHER 类型原有口径一致计入预览态成本。完成核单（finalize）门禁要求全行 CONFIRMED，**终态金额不变** | 📝 口径声明 |

## 3. 接口详情

| 项 | 值 |
|---|---|
| 方法 + 路径 | GET /v3/admin/order/{orderId}/settlement/reports/group |
| 接口名 | 查询单团核算表 |
| 使用场景 | 管理后台订单核单页，查看整团收入/成本/毛利只读报表（含逐项明细） |
| 认证 | 管理后台 JWT（/v3/admin/* 走网关鉴权） |
| 角色限制 | 房务角色（HOUSE）不可访问，调了会被拦截（错误码 581045） |
| 幂等性 | 只读查询，幂等 |
| 限流 | 走网关默认限流，无接口级特殊限流 |

同步受影响的接口（同 PR 一并说明，结构无变化、仅 OTHER_EXPENSE 展示块行归属随动）：

| 项 | 值 |
|---|---|
| 方法 + 路径 | GET /v3/admin/order/{orderId}/settlement/reports/reimbursement |
| 接口名 | 查询主报账人报账表 |
| 变化点 | expenseLines 中 type=OTHER_EXPENSE 的展示行纳入 5 类车辆费用行；expenseType 值域同步扩为 6 类 |

## 4. 接口入参

### 4.1 路径参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| orderId | Long | 是 | 订单 ID，必须 ≥ 1，否则 400 参数校验失败 |

### 4.2 请求体

无请求体，无 Query 参数。

## 5. 出参字段

顶层结构不变（沿用 #5963 拍平后结构）：抬头字段 + 收入/汇总金额字段 + incomeLines + 7 个成本分类明细数组（hotelLines/ticketLines/mealLines/vehicleLines/guideLines/photographerLines/otherExpenseLines）+ insuranceInfo。本 PR 只影响 vehicleLines 行结构与 otherExpenseLines 行归属/值域。

所有行 VO 均带 JsonInclude(NON_NULL)：**null 字段不下发该键**，前端取值请用可选链。

### 5.1 vehicleLines[] 行（变更后，只含 Fleet 配车日租行）

| 字段 | 类型 | 说明 |
|------|------|------|
| serviceDate | String(yyyy-MM-dd) | 服务日期 |
| startDate | String(yyyy-MM-dd) | 服务开始日期 |
| endDate | String(yyyy-MM-dd) | 服务结束日期 |
| vehiclePlate | String | 车牌号，如「蒙A-5376」 |
| vehicleModelName | String | 车型名称，如「坦克500」 |
| driverName | String | 司机姓名 |
| dailyPrice | BigDecimal | 日单价（即"核算单价"列），保留两位小数 |
| paymentTypeName | String | 车务付款类型名称，如「现金已付」 |
| amount | BigDecimal | 核算金额，保留两位小数，恒有值 |
| paymentMethod | String | 付款方式：CASH_PAID/COMPANY_PAID/SIGNED |
| paymentMethodName | String | 付款方式中文名（字典 settlement_payment_method，缺值回退硬编码） |
| sourceType | String | 明细来源类型，本数组恒为 FLEET |
| sourceTypeName | String | 来源中文名，本数组恒为「车务」 |
| remark | String | 备注；无备注时不下发 |
| voucherUrls | String[] | 凭证 URL 数组；无凭证时不下发 |

**已删除（不再下发）**：expenseType / expenseTypeName / projectName / expenseDate。quantity 恒 null 本就不输出。

### 5.2 otherExpenseLines[] 行（变更后，费用行 6 类 + 补贴行稀疏并集）

| 字段 | 类型 | 说明 |
|------|------|------|
| expenseDate | String(yyyy-MM-dd) | 费用发生日期 |
| projectName | String | 项目名称，如「全程油费」「全程矿泉水」 |
| expenseType | String | [EXPENSE 族] 费用类型，**值域 6 值**：OTHER/FUEL/TOLL/PARKING/RENTAL/MAINTENANCE |
| expenseTypeName | String | [EXPENSE 族] 费用类型中文名（字典 expense_type，后端已回填，前端无需再调字典） |
| subsidyType | String | [SUBSIDY 族] 补贴类型：PHONE/OVERTIME |
| subsidyTypeName | String | [SUBSIDY 族] 补贴类型中文名（字典 subsidy_type） |
| amount | BigDecimal | 核算金额（实际金额），保留两位小数，恒有值 |
| paymentMethod | String | 付款方式：CASH_PAID/COMPANY_PAID/SIGNED |
| paymentMethodName | String | 付款方式中文名（字典 settlement_payment_method，缺值回退硬编码） |
| sourceType | String | 明细来源类型；无来源时不下发 |
| sourceTypeName | String | 来源中文名（SettlementDetailSourceType 枚举 label） |
| remark | String | 备注；无备注时不下发 |
| voucherUrls | String[] | 凭证 URL 数组；无凭证时不下发 |

稀疏并集规则：**EXPENSE 族行只输出 expenseType/expenseTypeName，SUBSIDY 族行只输出 subsidyType/subsidyTypeName**，两族字段互斥，另一族恒 null（不下发）。判别方式：expenseType 键存在即费用行，subsidyType 键存在即补贴行。

## 6. 枚举 / 数据字典

### 6.1 expenseType（字典 expense_type，存量字典已含 6 值，前端无需改字典配置）

| 值 | 中文名 | 说明 |
|----|--------|------|
| FUEL | 油费 | 本次从 VEHICLE 迁入 |
| TOLL | 过路费 | 本次从 VEHICLE 迁入 |
| PARKING | 停车费 | 本次从 VEHICLE 迁入 |
| RENTAL | 租车费 | 本次从 VEHICLE 迁入 |
| MAINTENANCE | 维修保养 | 本次从 VEHICLE 迁入 |
| OTHER | 其他 | 原有，保持不变 |

### 6.2 subsidyType（字典 subsidy_type，本接口仅出现 2 值）

| 值 | 中文名 |
|----|--------|
| PHONE | 话补 |
| OVERTIME | 加班补贴 |

### 6.3 paymentMethod（字典 settlement_payment_method）

| 值 | 中文名 |
|----|--------|
| CASH_PAID | 现金已付 |
| COMPANY_PAID | 公司支付 |
| SIGNED | 签单 |

### 6.4 sourceType（SettlementDetailSourceType 枚举 label，非字典）

| 值 | 中文名 |
|----|--------|
| MANUAL | 手工 |
| HOUSE_ASSIGNMENT | 配房结果 |
| SCENIC_ASSIGNMENT | 景区 |
| ACTIVITY_ASSIGNMENT | 游玩项目 |
| MEAL_ASSIGNMENT | 餐饮安排 |
| FLEET | 车务 |
| STAFF_ASSIGNMENT | 人员安排 |
| ORDER_SURCHARGE | 订单增费 |
| SYSTEM | 系统 |

## 7. 错误码

| 错误码 | 文案 | 触发条件 |
|--------|------|----------|
| 581007 | 订单不存在 | orderId 对应的订单不存在（或已软删） |
| 581045 | 房务角色无权查看订单详情，房务仅可配房 | 房务角色（HOUSE）调用本接口 |
| 400 | 订单 ID 必须大于 0 | orderId < 1（参数校验失败） |

## 8. 示例

### 8.1 典型成功（测试服实证单 HL20260811181352799 口径：油费 300 归其他支出，用车只剩 Fleet 日租行）

请求：

    GET /v3/admin/order/197820050123456789/settlement/reports/group

响应（只截取本次变化的两个数组，其余字段省略）：

```json
{
  "code": 200,
  "data": {
    "id": "197820050123456789",
    "orderId": "197820050123456789",
    "orderNo": "HL20260811181352799",
    "totalCost": 3300.00,
    "vehicleLines": [
      {
        "serviceDate": "2026-08-12",
        "startDate": "2026-08-12",
        "endDate": "2026-08-14",
        "vehiclePlate": "蒙A-5376",
        "vehicleModelName": "坦克500",
        "driverName": "司机甲",
        "dailyPrice": 1000.00,
        "paymentTypeName": "现金已付",
        "amount": 1000.00,
        "paymentMethod": "CASH_PAID",
        "paymentMethodName": "现金已付",
        "sourceType": "FLEET",
        "sourceTypeName": "车务"
      }
    ],
    "otherExpenseLines": [
      {
        "expenseDate": "2026-08-12",
        "projectName": "全程油费",
        "expenseType": "FUEL",
        "expenseTypeName": "油费",
        "amount": 300.00,
        "paymentMethod": "CASH_PAID",
        "paymentMethodName": "现金已付",
        "sourceType": "MANUAL",
        "sourceTypeName": "手工",
        "remark": "途中加油"
      },
      {
        "expenseDate": "2026-08-13",
        "projectName": "司机话补",
        "subsidyType": "PHONE",
        "subsidyTypeName": "话补",
        "amount": 50.00,
        "paymentMethod": "COMPANY_PAID",
        "paymentMethodName": "公司支付"
      }
    ]
  },
  "msg": "success"
}
```

要点：油费行的 expenseType=FUEL 出现在 **otherExpenseLines**；vehicleLines 里没有任何带 expenseType 的行。

### 8.2 边界（无车辆费用 + 无配车：两数组均为空）

```json
{
  "code": 200,
  "data": {
    "orderNo": "HL20260810100000001",
    "totalCost": 0.00,
    "vehicleLines": [],
    "otherExpenseLines": []
  },
  "msg": "success"
}
```

要点：空分类固定返回空数组 []，不返回 null；前端判空渲染空态即可。

### 8.3 业务失败（订单不存在）

请求：

    GET /v3/admin/order/999999999999/settlement/reports/group

响应：

```json
{
  "code": 581007,
  "data": null,
  "msg": "订单不存在"
}
```

## 9. 业务边界

- **适用**：所有进入核单流程、需要查看整团成本构成的订单（含预览态与 finalize 终态）。
- **不适用**：房务角色（HOUSE）不可调本接口（581045）。
- **特殊边界**：
  - 5 类车辆费用行的录入入口本来就在核单「其他支出」tab，本次只是报表归集对齐，**不需要重新录入历史数据**。
  - 预览态存在未确认（UNCONFIRMED）车辆费用行时，新口径计入 otherExpenseLines 预览成本（旧口径挂 VEHICLE 不计成本）；finalize 门禁要求全行 CONFIRMED，终态两口径金额一致。
  - 核单已 finalize 的订单，报表行来自终态快照，口径以快照冻结时为准；反确认（reopen）后重新生成走新口径。

## 10. 修改前后对比

### 10.1 字段级

| 位置 | 修改前 | 修改后 |
|------|--------|--------|
| vehicleLines[] 行.expenseType | 有（FUEL/TOLL/PARKING/RENTAL/MAINTENANCE） | **删除，不下发** |
| vehicleLines[] 行.expenseTypeName | 有（油费等） | **删除，不下发** |
| vehicleLines[] 行.projectName | 有（车辆费用项目名） | **删除，不下发** |
| vehicleLines[] 行.expenseDate | 有（费用发生日期） | **删除，不下发** |
| otherExpenseLines[].expenseType | 恒 OTHER | OTHER/FUEL/TOLL/PARKING/RENTAL/MAINTENANCE 6 值之一 |
| 5 类车辆费用行所在数组 | vehicleLines | **otherExpenseLines** |

### 10.2 行为级

| 场景 | 修改前 | 修改后 |
|------|--------|--------|
| 一笔 300 元油费（CASH_PAID） | 出现在 vehicleLines，带 expenseType=FUEL/projectName/expenseDate | 出现在 otherExpenseLines，字段同族（expenseType=FUEL/projectName/expenseDate/amount/...） |
| vehicleLines 内容 | Fleet 日租行 + 5 类车辆费用行混排 | 只含 Fleet 日租行（sourceType=FLEET） |
| 用车分类小计（vehicleLines 合计） | 含 5 类车辆费用 | 只含 Fleet 日租，数值下降 |
| 其他支出小计（otherExpenseLines 合计） | 只含 OTHER 费用 + 补贴 | 增加 5 类车辆费用，数值上升 |
| totalCost / grossProfit | —— | **不变** |
| 报账表 OTHER_EXPENSE 展示块 | 只含 OTHER 费用 + 补贴展示行 | 纳入 5 类车辆费用展示行 |

## 11. 影响评估 / 回滚

- **破坏性**：⚠️ 是。vehicleLines 行 4 个字段删除 + 5 类费用行跨数组迁移，前端若按旧结构渲染「用车」块会丢车辆费用行。
- **前端需要同步上线的改动**：
  1. 「用车」块/页签只渲染 Fleet 日租行，删除对 vehicleLines[].expenseType/expenseTypeName/projectName/expenseDate 的读取（键已不下发）；
  2. 5 类车辆费用行改到「其他支出」块渲染，复用 otherExpenseLines 现有 EXPENSE 族渲染逻辑（expenseTypeName 后端已回填中文，前端无需改字典）；
  3. 若有 workaround 代码把车辆费用从用车块搬到其他支出块展示，可清理；
  4. 分类小计若前端自算，无需改公式（数组内容已就位）。
- **回滚方案**：后端 revert PR #5970 即恢复旧口径；纯代码口径调整，无 DDL、无数据迁移，回滚无副作用。前端若已按新结构上线，后端回滚需前端同步回退。

## 12. 注意事项

1. 行 VO 均带 JsonInclude(NON_NULL)：null 字段不下发该键，前端取值用可选链 / 默认值兜底，不要假定键一定存在。
2. expenseTypeName / subsidyTypeName / paymentMethodName / sourceTypeName 全部后端回填，前端**不要**再自行映射字典。
3. 判别 otherExpenseLines 行族：expenseType 键存在 = 费用行（含 6 类），subsidyType 键存在 = 补贴行，两族字段互斥。
4. 报账表（reports/reimbursement）expenseLines 中 type=OTHER_EXPENSE 展示行的 expenseType 实际值域同步扩为 6 类；该字段 Swagger 注解的 allowableValues 暂未同步更新，**以本文档与实际返回值为准**。
5. 本次无入参变化、无新接口、无 DDL、无字典数据变更（expense_type 字典 6 值为存量）。

## 13. 关联 / 联系人

- Issue：https://git.1814.love:8443/wx/HL/issues/5969
- PR：https://git.1814.love:8443/wx/HL/pulls/5970
- Commit（merge）：https://git.1814.love:8443/wx/HL/commit/522179ecfe
- 后端负责人：腰苏图
