# 【⚠️修改接口·管理后台】出行中取消旧路径下线：`cancel/on-trip` → `terminate` (#3556)

> **服务**: hl-order-service-v3 | **更新时间**: 2026-06-11
> ⚠️ **破坏性变更（路径级）**：旧端点 `POST /v3/admin/order/{id}/cancel/on-trip` **已删除**，调用返回 404。
> 📌 本篇专补「路径下线」这一环（前期 #3556 changelog 只写了新路径的入参/出参，未点明旧路径已废，导致前端联调时仍在调旧 URL 收到 404）。入参/出参完整改造见 #3556 那篇，本篇做自包含汇总。

## 1. 接口背景

「出行中取消」此前走 `POST /v3/admin/order/{id}/cancel/on-trip`。后端在终止行程改造时把该端点**重命名为 `POST /v3/admin/order/{id}/terminate`**，并改变了语义：

- 旧：出行中取消 → 订单直接进入 `CANCELLED`（已取消）。
- 新：终止行程 → 订单进入 `COMPLETED`（已完成），再在核单子状态（`reviewStatus` / `flowStatus`）中流转结算，**不再直接 CANCELLED**。

后端代码里 `cancel/on-trip` 路径已**全量删除**（全仓 `git grep` 无残留），任何对旧路径的调用都会 404。前端「出行中取消」分支若仍指向旧 URL，必须改指新 URL。

## 2. 变更清单

| # | 操作 | 旧 | 新 | 变更类型 |
|---|------|----|----|----------|
| 1 | 取消/终止 出行中订单 | `POST /v3/admin/order/{id}/cancel/on-trip` | `POST /v3/admin/order/{id}/terminate` | 路径下线 + 重命名 |
| 2 | 退款预览（出行中） | （旧流程无独立预览，或复用 cancel-preview） | `POST /v3/admin/order/{id}/terminate/refund-preview` | 新增（详见 #3556 配套篇） |

## 3. 接口详情

### 3.1 终止行程（替代出行中取消）

- **路径**：`POST /v3/admin/order/{id}/terminate`
- **使用场景**：出行中订单提前终止，定制师调用。需先调「终止退款预览」拿资源清单。
- **认证**：管理端 JWT（`Authorization` 头）
- **幂等性**：是。订单一旦终止状态变为 `COMPLETED`，二次调用因状态非 `TRAVELLING` 返回 `581018`。

## 4. 接口入参

### 4.1 路径参数

| 字段 | 类型 | 必填 | 说明 |
|------|------|:----:|------|
| id | String | ✅ | 订单 ID |

### 4.2 请求体（`OrderTerminateTripReqVO`）

| 字段 | 类型 | 必填 | 说明 | 校验 |
|------|------|:----:|------|------|
| cancelReason | String | ✅ | 终止原因（调整额说明也并入此处，不单列字段） | 非空 |
| endDayNumber | Integer | ✅ | 停在第几天（截断点，1-based） | ≥ 1 |
| rooms | Array<{refId, used}> | ✅ | 住宿各行已用判定 | 列表非 null |
| tickets | Array<{refId, used}> | ✅ | 门票各行已用判定 | 列表非 null |
| vehicles | Array<{refId, dayNumber, used}> | ✅ | 用车各行已用判定（同车跨天靠 dayNumber 区分） | 列表非 null |
| adjustAmount | BigDecimal | ❌ | 人工调整额（±，正=多退 负=少退），默认 0 | — |

> `refId` 全部取自「终止退款预览」接口返回值。入参**只传 `used` 判定 + `adjustAmount`，不传任何金额单价**——退款额由后端按预览同源成交价权威重算（防篡改）。保险不在入参，后端自动按锁定不退处理。

**rooms / tickets 行（ResourceUsedItem）**

| 字段 | 类型 | 必填 | 说明 |
|------|------|:----:|------|
| refId | String | ✅ | 配单记录 ID（住宿=house_hotel_assignment.id；门票=order_scenic_assignment.assignment_id） |
| used | Boolean | ✅ | 是否已使用（true=已用不退 / false=未用可退） |

**vehicles 行（VehicleUsedItem）**

| 字段 | 类型 | 必填 | 说明 |
|------|------|:----:|------|
| refId | String | ✅ | 配车记录 ID（同段车跨天 refId 相同） |
| dayNumber | Integer | ✅ | 第几天（1-based，≥ 1） |
| used | Boolean | ✅ | 当天该车是否已使用 |

## 5. 出参（`Result<OrderTerminateTripRespVO>`）

| 字段 | 类型 | 说明 |
|------|------|------|
| terminateRefundId | String | 终止退款主表 ID |
| baselineRefund | BigDecimal | 系统建议基线 = max(0, paidAmount − usedAmount) |
| adjustAmount | BigDecimal | 人工调整额（回显入参，默认 0） |
| finalRefund | BigDecimal | 最终返还额 = max(0, baselineRefund + adjustAmount) |
| settlementRefundId | String | 核单返还记录 ID（核单模块写入后回填） |
| newStatus | String | 终止后订单粗状态（恒 `COMPLETED`） |
| newFlowStatus | String | 终止后流程细状态（恒 `PENDING_REVIEW`） |

## 6. 枚举 / 数据字典

### 6.1 newStatus

| 值 | 中文 | 说明 |
|----|------|------|
| `COMPLETED` | 已完成 | 终止后订单进入完成态，转入核单流程（**注意：不再是旧的 CANCELLED**） |

### 6.2 newFlowStatus

| 值 | 中文 | 说明 |
|----|------|------|
| `PENDING_REVIEW` | 待核单 | 终止后等待核单录入与结算复核 |

## 7. 错误码

| code | 含义 | 触发场景 |
|------|------|----------|
| 581007 | 订单不存在 | id 无对应订单 |
| 581018 | 出行中取消仅适用于出行中订单 | 订单当前状态非 `TRAVELLING`（未出发 / 已终止 / 已完成时调用，含二次终止） |

## 8. 示例

### 8.1 典型成功

**请求**：
```
POST /v3/admin/order/60001234567890/terminate
Authorization: Bearer {token}
Content-Type: application/json
```
```json
{
  "cancelReason": "客户中途高反送医终止；林芝段酒店已付全款不可退，调整 -300",
  "endDayNumber": 3,
  "rooms": [
    {"refId": "96011", "used": true},
    {"refId": "96014", "used": false}
  ],
  "tickets": [
    {"refId": "97001", "used": true}
  ],
  "vehicles": [
    {"refId": "98001", "dayNumber": 1, "used": true},
    {"refId": "98001", "dayNumber": 2, "used": true},
    {"refId": "98001", "dayNumber": 3, "used": true}
  ],
  "adjustAmount": -300.00
}
```

**响应**：
```json
{
  "code": 200,
  "message": "ok",
  "success": true,
  "data": {
    "terminateRefundId": "9610000001",
    "baselineRefund": 2264.00,
    "adjustAmount": -300.00,
    "finalRefund": 1964.00,
    "settlementRefundId": "9620000001",
    "newStatus": "COMPLETED",
    "newFlowStatus": "PENDING_REVIEW"
  }
}
```

### 8.2 边界（不填调整额，默认 0）

**请求（片段）**：
```json
{ "cancelReason": "客户主动终止", "endDayNumber": 5, "rooms": [], "tickets": [], "vehicles": [] }
```
**响应（片段）**：
```json
{ "code": 200, "data": { "baselineRefund": 0.00, "adjustAmount": 0.00, "finalRefund": 0.00, "newStatus": "COMPLETED", "newFlowStatus": "PENDING_REVIEW" } }
```

### 8.3 异常 —— 调旧路径（前端联调踩的就是这个）

**请求**：
```
POST /v3/admin/order/60001234567890/cancel/on-trip
```
**响应**：
```
HTTP 404 Not Found
```
> 旧路径在后端已无任何映射，必须改调 `POST /v3/admin/order/{id}/terminate`。

### 8.4 异常 —— 订单非出行中

**响应**：
```json
{ "code": 581018, "message": "出行中取消仅适用于出行中订单", "success": false }
```

## 9. 业务边界

- ✅ **适用**：订单当前粗状态 = `TRAVELLING`（出行中）
- ❌ **不适用**：未出发订单走「取消订单」流程（`cancel/pre-trip`）；已终止 / 已完成订单二次调用返回 `581018`
- ⚠️ `finalRefund` 最低为 0，不会出现负数；退款额进入核单返还，由财务复核放款；保险恒不退

## 10. 修改前后对比

### 10.1 路径与语义

| 维度 | 改前 | 改后 |
|------|------|------|
| 路径 | `POST /{id}/cancel/on-trip` | `POST /{id}/terminate` |
| 退款预览 | 复用取消预览（或无独立预览） | `POST /{id}/terminate/refund-preview`（独立，POST） |
| 终止后订单状态 | `CANCELLED`（已取消） | `COMPLETED`（已完成）→ 进核单 `PENDING_REVIEW` |
| 入参 VO | `OrderCancelOnTripReqVO` | `OrderTerminateTripReqVO` |
| 出参 VO | `OrderCancelOnTripRespVO` | `OrderTerminateTripRespVO` |

### 10.2 入参字段级

| 字段 | 改前 | 改后 |
|------|------|------|
| cancelReason | ✅ 终止原因 | ✅ 终止原因（+ 调整说明并入） |
| returnAmount | ✅ 手填返还额（必填） | ❌ **删除**（改由后端按资源核算） |
| returnRemark | ✅ 返还备注（必填） | ❌ **删除**（说明并入 cancelReason） |
| endDayNumber | — | ✅ **新增**，停在第几天 |
| rooms / tickets / vehicles | — | ✅ **新增**，各资源行已用判定 |
| adjustAmount | — | ✅ **新增**（可选），人工调整额 |

### 10.3 出参字段级

| 字段 | 改前 | 改后 |
|------|------|------|
| returnAmount | ✅ 返还额（回显） | ❌ **删除** |
| settlementRefundId | ✅（旧实现恒 null） | ✅ 真实核单返还记录 ID |
| newStatus | ✅（值 `已取消`） | ✅（值变 `COMPLETED`） |
| terminateRefundId | — | ✅ **新增** |
| baselineRefund / adjustAmount / finalRefund | — | ✅ **新增** 退款明细金额 |
| newFlowStatus | — | ✅ **新增**（`PENDING_REVIEW`） |

## 11. 影响评估 / 回滚

- **是否破坏向后兼容**：是。路径、入参、出参、终态全部变化。前端仍调旧路径 → 404；仍按旧 body → 校验失败。
- **前端必须同步**：是。「出行中取消」分支需：① 改 URL 为 `/terminate`；② 改 body 为资源勾选模型；③ 终态判断从「已取消」改为「已完成→待核单」。
- **回滚**：本路径下线在后端已合入主线（rename commit + #3557），如需回滚需后端 revert，前端无单独回滚动作。

## 12. 注意事项

- ⚠️ 旧路径 `cancel/on-trip` 在后端**无任何兼容映射**，不会做 301/308 跳转，直接 404。
- 必须配合「终止退款预览」`POST /{id}/terminate/refund-preview` 使用：预览拿资源清单 → 前端本地按结束天标已用/可退 → 提交时只回传 `used` 判定 + `adjustAmount`。
- 终止后订单是「已完成（待核单）」而非「已取消」，列表/详情的状态展示需按新枚举对齐。

## 13. 关联 / 联系人

### 13.1 链接

- **Issue**: [#3556](https://git.1814.love:8443/wx/HL/issues/3556)
- **入参/出参完整改造 changelog（同 Issue）**: `06_3556_终止行程接口改造-修改接口-管理后台.md` + `06_3556_终止退款预览-新增接口-管理后台.md`
- **PR**: [#3557](https://git.1814.love:8443/wx/HL/pulls/3557)

### 13.2 联系人

- **后端负责人**: @yst
- **前端对接（管理后台）**: 订单详情「出行中取消 / 终止行程」分支
