diff --git a/changelogs-v2/2026-06/11_3556_出行中取消路径下线-cancel-on-trip改terminate-修改接口-管理后台.md b/changelogs-v2/2026-06/11_3556_出行中取消路径下线-cancel-on-trip改terminate-修改接口-管理后台.md new file mode 100644 index 0000000..fec721f --- /dev/null +++ b/changelogs-v2/2026-06/11_3556_出行中取消路径下线-cancel-on-trip改terminate-修改接口-管理后台.md @@ -0,0 +1,242 @@ +# 【⚠️修改接口·管理后台】出行中取消旧路径下线:`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`) + +| 字段 | 类型 | 说明 | +|------|------|------| +| 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 +- **前端对接(管理后台)**: 订单详情「出行中取消 / 终止行程」分支