---
schema: "hl-changelog/v2"
ticket: "5253"
title: "按车辆记录订单总车费并接入核单"
consumer: "multiple"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "implemented"
frontend_owner: "hl-ui-codex"
frontend_ref: "mmg/hl-ui@e43200d6eede059f82aacfa00de5656b379f8981"
target_release: ""
verified_at: ""
status_note: "后端已合入 dev-v3 并部署测试环境；自动计价、手工总价、缺价阻断、部分改派分段、核单实时合计与冻结均已通过网关验证。前端尚未领取，frontend_status 保持 pending。"
updated_at: "2026-07-26T04:47:17.025Z"
base: "dev-v3"
generated: "2026-07-26T08:57:17+08:00"
---

# 按车辆记录订单总车费并接入核单

车务在每个车辆槽位/派车段记录一个最终总车费；价格日历只提供自动参考，
车务可以手工改总价但不回写价格日历。订单核单冻结 Fleet 最终快照并按同一来源计入实际成本。

## 关联

- Issue: #5253
- 后端分支: `feat/5253-vehicle-total-fee`
- Changelog 分支: `docs/5253-vehicle-total-fee`

## 变更接口

| 表面 | 方法 | 路径 | 变化 |
|---|---|---|---|
| `frontend_api` | `POST` | `/admin/fleet/assignments/candidates` | 入参新增计费服务日；车辆候选新增自动总车费、完整性和缺价日期 |
| `frontend_api` | `POST` | `/admin/fleet/assignments` | 入参新增单车最终总车费、调整原因、计费日/免费日口径；响应回显费用快照 |
| `frontend_api` | `POST` | `/admin/fleet/assignments/batch` | 每辆车分别提交最终总车费与调整原因，并共享计费日/免费日口径 |
| `frontend_api` | `POST` | `/admin/fleet/assignments/:assignmentId/confirm` | 最终确认前可补/改该派车段总车费；响应回显最终费用 |
| `frontend_api` | `POST` | `/admin/fleet/assignments/:assignmentId/change` | 改派新段与原车保留段分别记录总车费 |
| `frontend_api` | `GET` | `/admin/fleet/board/orders/:orderId` | 每个派车组新增自动参考、最终总价、来源、调整原因、计费/免费日期与冻结态 |
| `frontend_api` | `GET` | `/v3/admin/order/:orderId/settlement/vehicle-fees` | 新增核单车辆总车费明细；冻结前读 Fleet，冻结后读 Order 快照 |
| `frontend_api` | `POST` | `/v3/admin/order/:orderId/settlement/vehicle-fees/confirm` | 新增确认并冻结车辆总车费 |
| `frontend_api` | `POST` | `/v3/admin/order/:orderId/settlement/step6/submit` | 响应新增 `vehicleCost` |
| `frontend_api` | `GET` | `/v3/admin/order/:orderId/settlement/summary` | 响应新增 `vehicleCost` |
| `internal_feign` / `shared_java` | `GET` | `/internal/fleet/orders/:orderId/vehicle-fees` | 新增 Fleet→Order 的按派车组只读费用快照 |

路径中的 `:orderId`、`:assignmentId` 表示既有雪花 ID 字符串传输约定。

## 字段与行为

### 派车候选与写接口

- `AssignmentCandidateReqVO` 新增 `chargeableServiceDates`；不传默认全部服务日，
  空数组表示全部免费。
- 候选车辆新增：
  - `autoVehicleFeeTotal`：价格日历覆盖日期的小计，金额按字符串消费；
  - `vehicleFeePriceComplete`：是否覆盖全部计费服务日；
  - `missingVehicleFeeDates`：缺价的计费服务日；
  - 旧字段 `protocolPrice` 保留但已废弃，新页面不得用它计算总车费。
- 创建/批量创建/改派新增 `vehicleFeeTotal`、`vehicleFeeAdjustmentReason`、
  `chargeableServiceDates`、`vehicleFeeWaiverReason`、
  `confirmAllServiceDatesFree`。
- 部分改派额外新增 `retainedVehicleFeeTotal` 与
  `retainedVehicleFeeAdjustmentReason`。原车保留段和替换段分别录入，
  后端不按天数比例拆分。
- 最终确认新增 `vehicleFeeTotal` 与 `vehicleFeeAdjustmentReason`。
- 创建、改派和确认响应新增 `vehicleFeeAutoTotal`、
  `vehicleFeeAutoComplete`、`vehicleFeeTotal`、`vehicleFeeSource`、
  `vehicleFeeAdjustmentReason`；金额字段按字符串消费。

### 看板详情

每个派车组新增：

- `chargeableServiceDates`、`freeServiceDates`、`vehicleFeeWaiverReason`；
- `vehicleFeeAutoTotal`、`vehicleFeeAutoComplete`；
- `vehicleFeeTotal`、`vehicleFeeSource`（`AUTO`、`MANUAL`、`INCOMPLETE`）；
- `vehicleFeeAdjustmentReason`、`vehicleFeeFrozen`。

派车完成后 `vehicleFeeFrozen=true`，不得原地编辑费用；只能走改派形成新的费用段。
订单核单完成后禁止继续改派。

### 核单车辆总车费

`SettlementVehicleFeesRespVO`：

- 顶层：`orderId`、`frozen`、`totalVehicleFee`、`items`；
- 每项按一个派车组返回车辆、司机、日期、计费/免费日期、自动参考、
  最终总价、来源、调整审计和 `settlementReady`；
- `POST .../confirm` 仅接受全部当前派车组 `settlementReady=true`
  且最终总车费非空的快照，成功后 `frozen=true`；
- 两辆车返回两项并分别计费，`totalVehicleFee` 是各项 `vehicleFeeTotal` 之和；
- `vehicleCost` 同步进入核单提交与汇总实际成本，司机费用只保留司机额外费用，
  避免车辆基础服务费重复计入。

### 内部契约

新增共享 DTO `OrderVehicleFeeSnapshotDTO`，包含需求、派车组、稳定车辆槽位、
车辆/司机、服务区间、计费/免费日期、自动参考、最终总价、调整审计和
`settlementReady`。Order 必须按当前 `requirementId` 精确筛选，
不得跨需求或跨改派段合并。

## 契约影响文件

- `hl-common/hl-common-core/src/main/java/com/hulalv/common/dto/fleet/OrderVehicleFeeSnapshotDTO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/controller/OrderDriverVehicleInternalController.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/AssignmentCandidateReqVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/AssignmentCandidateRespVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/AssignmentWriteRespVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/BatchCreateAssignmentReqVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/ChangeAssignmentReqVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/ChangeAssignmentRespVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/ConfirmReqVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/ConfirmRespVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/assignment/vo/CreateAssignmentReqVO.java`
- `hl-fleet-service/src/main/java/com/hulalv/fleet/board/vo/BoardOrderDetailVO.java`
- `hl-fleet-service/src/test/java/com/hulalv/fleet/assignment/controller/OrderDriverVehicleInternalControllerTest.java`
- `hl-order-service-v3/src/main/java/com/hulalv/order/fleet/feign/FleetDriverVehicleFeignClient.java`
- `hl-order-service-v3/src/main/java/com/hulalv/order/fleet/feign/FleetDriverVehicleFeignFallbackFactory.java`
- `hl-order-service-v3/src/main/java/com/hulalv/order/settlement/controller/admin/SettlementController.java`
- `hl-order-service-v3/src/main/java/com/hulalv/order/settlement/controller/admin/vo/SettlementSubmitRespVO.java`
- `hl-order-service-v3/src/main/java/com/hulalv/order/settlement/controller/admin/vo/SettlementSummaryRespVO.java`
- `hl-order-service-v3/src/main/java/com/hulalv/order/settlement/controller/admin/vo/SettlementVehicleFeesRespVO.java`
- `hl-order-service-v3/src/test/java/com/hulalv/order/fleet/feign/FleetDriverVehicleFeignContractTest.java`
- `hl-order-service-v3/src/test/java/com/hulalv/order/settlement/controller/admin/SettlementControllerTest.java`

## 前端/调用方动作

- 派车弹窗按“每辆车一个总车费”展示和提交；不要展示或要求车务填写每日价格。
- 默认展示后端 `autoVehicleFeeTotal`。缺价时用
  `vehicleFeePriceComplete=false` 和 `missingVehicleFeeDates` 提示，
  车务仍必须填写该车最终总车费及调整原因后才能直接派定/最终确认。
- 车务手改只提交 `vehicleFeeTotal`，不得写回车型价格日历。
- 收费日/免费日仅作为记录与核单依据；全部免费时必须提交免费原因和二次确认。
- 多车订单为每个车辆槽位分别编辑总车费，不提供订单级总价输入框。
- 已派定/已完成段按 `vehicleFeeFrozen` 禁用直接编辑，只保留改派入口；
  已核单订单同时禁用改派。
- 核单页先查询 `GET .../vehicle-fees` 展示逐车明细和合计，
  再调用 `POST .../vehicle-fees/confirm` 冻结；冻结后只读。
- 所有雪花 ID 和金额字段按字符串处理，禁止转 JavaScript `number`。
- `frontend_status` 保持 `pending`；真实前端领取后使用工作流迁移到 `claimed`。

## 验证证据

- Fleet producer：`mvn -pl hl-fleet-service -am verify` 通过；
  `mvn -pl hl-fleet-service -am spotless:check` 通过。
- Order consumer：`mvn -pl hl-order-service-v3 -am verify` 通过。
- 契约定向测试：
  `OrderDriverVehicleInternalControllerTest`、
  `FleetDriverVehicleFeignContractTest`、
  `SettlementControllerTest` 通过。
- 费用行为覆盖：自动合计、缺价、手工覆盖、全免费、部分改派、
  派定后冻结、核单冻结、首个计费日只入账一次及并发门禁均有测试。
- OpenAPI/oasdiff：`not_configured`；fallback 证据见任务胶囊
  `openapi-fallback.md`。
- producer/consumer 或 Spring Cloud Contract：`not_configured`；
  fallback 证据见任务胶囊 `consumer-contract-fallback.md`。
- 测试部署：Fleet Deploy Panel 任务 `5131f604` 成功，8087/8187
  双实例健康；补充修复 PR `wx/HL#5261` 已合入 `dev-v3`。
- 网关验证：自动计价完整；缺价返回 `605044` 阻断；多车分别保存
  `1720.00` 与 `1234.56`；部分改派同一稳定槽位拆为原车保留段
  `900.00` 与新车接替段 `1100.00`，核单实时合计 `2000.00`；
  核单确认后冻结快照只读。`gateway_status=verified`。
- 测试数据：隔离订单已按 `hl-data-cleanup/v1` manifest
  `5253-cfcc4c8eea2b` 事务清理，全部目标后置计数为 0，价格日历未变化。
- 兼容性结论：现有路径均为增量字段；旧 `protocolPrice` 继续返回，
  但新页面必须改用每车总费用字段。
