From 2106e5be43ec31e8ddf59ccd59c9041df6fa914c Mon Sep 17 00:00:00 2001 From: yaosutu <770858045@qq.com> Date: Sat, 6 Jun 2026 23:29:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=BB=88=E6=AD=A2=E8=A1=8C?= =?UTF-8?q?=E7=A8=8B=E9=80=80=E6=AC=BE=20changelog=EF=BC=88=E9=A2=84?= =?UTF-8?q?=E8=A7=88=E6=96=B0=E6=8E=A5=E5=8F=A3=20+=20=E7=BB=88=E6=AD=A2?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=94=B9=E9=80=A0=EF=BC=8C#3556=20/=20PR=20#?= =?UTF-8?q?3557=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 终止退款预览:新增 POST /v3/admin/order/{id}/terminate/refund-preview,返回资源清单+行程信息 - 终止行程接口改造:入参改资源已用判定+调整额,出参补退款明细字段(破坏性,前端必改) --- ...3556_终止行程接口改造-修改接口-管理后台.md | 243 ++++++++++++++++++ .../06_3556_终止退款预览-新增接口-管理后台.md | 159 ++++++++++++ 2 files changed, 402 insertions(+) create mode 100644 changelogs-v2/2026-06/06_3556_终止行程接口改造-修改接口-管理后台.md create mode 100644 changelogs-v2/2026-06/06_3556_终止退款预览-新增接口-管理后台.md diff --git a/changelogs-v2/2026-06/06_3556_终止行程接口改造-修改接口-管理后台.md b/changelogs-v2/2026-06/06_3556_终止行程接口改造-修改接口-管理后台.md new file mode 100644 index 0000000..12a7ea5 --- /dev/null +++ b/changelogs-v2/2026-06/06_3556_终止行程接口改造-修改接口-管理后台.md @@ -0,0 +1,243 @@ +# 【⚠️修改接口·管理后台】终止行程接口改造(资源级退款计算) (#3556) + +> **PR**: #3557 | **服务**: hl-order-service-v3 | **更新时间**: 2026-06-06 +> ⚠️ **破坏性变更**:入参 / 出参结构均调整,前端必须同步改造。 + +## 1. 接口背景 + +终止行程原先只让定制师手填一个返还金额,既不准确也没真正进入核单结算。现改为**资源级退款计算**:定制师在弹框里选择「停在第几天」并逐项标记资源是否已用,提交时后端按实际成交价重新核算退款额并写入核单返还。 + +## 2. 变更清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 终止行程 | POST | `/v3/admin/order/{id}/terminate` | 修改接口 | 入参从「手填返还额」改为「资源已用判定 + 调整额」;出参补退款明细字段 | + +## 3. 接口详情 + +### 3.1 终止行程 + +- **使用场景**:出行中订单提前终止时调用,配合「终止退款预览」接口(见同日新增接口 changelog)使用 +- **认证**:需要管理端 JWT(`Authorization` 头) +- **幂等性**:是(同一订单二次调用因状态已变为「已完成」返回 581018) +- **限流**:无 + +## 4. 接口入参 + +### 4.1 路径参数 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | String | ✅ | 订单 ID | + +### 4.2 请求体字段 + +| 字段 | 类型 | 必填 | 说明 | 校验规则 | +|------|------|------|------|----------| +| cancelReason | String | ✅ | 终止原因(调整金额的说明也写在此处,不再单列字段) | 非空 | +| endDayNumber | Integer | ✅ | 停在第几天 | 1 ≤ 值 ≤ 行程总天数 | +| rooms | Array<{refId, used}> | ✅ | 住宿各行已用判定 | — | +| tickets | Array<{refId, used}> | ✅ | 门票各行已用判定 | — | +| vehicles | Array<{refId, dayNumber, used}> | ✅ | 用车各行已用判定(同车跨天靠 dayNumber 区分) | — | +| adjustAmount | BigDecimal | ❌ | 人工调整额(正=多退,负=少退),默认 0 | — | + +> `rooms[].refId` / `tickets[].refId` / `vehicles[].refId` 取自「终止退款预览」接口返回的 `refId`。 +> 请求**只需传**资源是否已用(`used`)+ 调整额,**不传任何金额单价**——退款额由后端按预览同源的成交价重新核算(防篡改)。保险不在入参,由后端自动按锁定不退处理。 + +### 4.2.1 rooms / tickets 行(ResourceUsedItem) + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| refId | String | ✅ | 资源记录 ID | +| used | Boolean | ✅ | 该项是否已使用(true=已用不退 / false=未用可退) | + +### 4.2.2 vehicles 行(VehicleUsedItem) + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| refId | String | ✅ | 用车记录 ID | +| dayNumber | Integer | ✅ | 第几天 | +| used | Boolean | ✅ | 当天该车是否已使用 | + +## 5. 出参(响应) + +### 5.1 响应字段(`data`) + +| 字段 | 类型 | 说明 | +|------|------|------| +| terminateRefundId | String | 终止退款记录 ID | +| baselineRefund | BigDecimal | 系统按已用资源算出的建议退款额 | +| adjustAmount | BigDecimal | 人工调整额(回显入参) | +| finalRefund | BigDecimal | 最终退款额(= baselineRefund + adjustAmount,最低 0) | +| settlementRefundId | String | 核单返还记录 ID(已写入核单 Step5 返还,供财务复核展示) | +| newStatus | String | 终止后订单状态(`COMPLETED`=已完成) | +| newFlowStatus | String | 终止后流程状态(`PENDING_REVIEW`=待核单) | + +## 6. 枚举 / 数据字典 + +### 6.1 newStatus(订单状态) + +**所属字段**:`newStatus` | **类型**:`String` + +| 值 | 中文 | 说明 | +|----|------|------| +| `COMPLETED` | 已完成 | 终止后订单进入完成态,转入核单流程 | + +### 6.2 newFlowStatus(流程状态) + +**所属字段**:`newFlowStatus` | **类型**:`String` + +| 值 | 中文 | 说明 | +|----|------|------| +| `PENDING_REVIEW` | 待核单 | 终止后等待核单录入与结算复核 | + +## 7. 错误码 + +| code | 含义 | 触发场景 | +|------|------|----------| +| 581018 | 出行中取消仅适用于出行中订单 | 订单当前状态非「出行中」时调用(含二次终止) | + +## 8. 示例 + +### 8.1 典型成功 + +**请求**: +``` +POST /v3/admin/order/60001234567890/terminate +Authorization: Bearer {token} +``` +```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 业务失败(异常) + +**场景说明**:订单非出行中(如已确认待出发或已终止过)。 + +**响应**: +```json +{ "code": 581018, "message": "出行中取消仅适用于出行中订单", "success": false } +``` + +## 9. 业务边界 + +- ✅ **适用场景**:订单当前状态 = 出行中(TRAVELLING) +- ❌ **不适用场景**:未出发订单请走「取消订单」流程;已终止/已完成订单二次调用返回 581018 +- ⚠️ **特殊边界**: + - `finalRefund` 最低为 0,不会出现负数 + - 退款额最终进入核单返还,由财务复核环节确认放款 + - 保险恒不退,无需在入参体现 + +## 10. 修改前后对比 + +### 10.1 字段级对比 + +**入参**: + +| 字段 | 改前 | 改后 | +|------|------|------| +| cancelReason | ✅ 终止原因 | ✅ 终止原因(+ 调整说明并入此处) | +| returnAmount | ✅ 手填返还金额(必填) | ❌ **删除**(改由后端按资源核算) | +| returnRemark | ✅ 返还备注(必填) | ❌ **删除**(说明并入 cancelReason) | +| endDayNumber | — | ✅ **新增**,停在第几天 | +| rooms / tickets / vehicles | — | ✅ **新增**,各资源行已用判定 | +| adjustAmount | — | ✅ **新增**(可选),人工调整额 | + +**出参**: + +| 字段 | 改前 | 改后 | +|------|------|------| +| settlementRefundId | ✅(此前恒为 null) | ✅ 真实核单返还记录 ID | +| returnAmount | ✅ 返还额(回显入参) | ❌ **删除** | +| newStatus | ✅ | ✅(不变) | +| terminateRefundId | — | ✅ **新增** | +| baselineRefund / adjustAmount / finalRefund | — | ✅ **新增**,退款明细金额 | +| newFlowStatus | — | ✅ **新增** | + +### 10.2 行为级对比 + +| 行为 | 改前 | 改后 | +|------|------|------| +| 退款额来源 | 定制师手填一个数 | 按已用资源 + 实际成交价由后端核算 | +| 退款是否进核单 | 否(仅记录,未落账) | 是(写入核单返还,财务复核放款) | +| 配合接口 | 无 | 需先调「终止退款预览」拿资源清单 | + +## 11. 影响评估 / 回滚 + +### 11.1 影响评估 + +- **是否破坏向后兼容**:是。入参删除 `returnAmount` / `returnRemark`,新增多个必填字段;出参删除 `returnAmount`。前端按旧契约调用会校验失败。 +- **前端是否必须同步上线**:是。终止行程页面需改造为「预览拉清单 → 选结束天 + 勾选已用 → 提交」流程。 +- **前端 workaround 清理点**:若此前有「手填返还额」输入框,应替换为资源勾选界面;旧的 returnAmount/returnRemark 入参与回显逻辑可删除。 + +### 11.2 回滚方案 + +- **回滚方式**:revert PR #3557 +- **回滚后清理**:无需数据迁移(新功能,无历史数据依赖) + +## 12. 注意事项 + +- ⚠️ 本接口为**破坏性改动**,前端务必在后端上线同期改造,否则终止行程功能不可用。 +- 必须配合同日「终止退款预览」新增接口使用:预览拿全部资源清单 → 前端本地按结束天标已用/可退 → 提交时只回传 `used` 判定与 `adjustAmount`。 + +## 13. 关联 / 联系人 + +### 13.1 链接 + +- **Issue**: [#3556](https://git.1814.love:8443/wx/HL/issues/3556) +- **PR**: [#3557](https://git.1814.love:8443/wx/HL/pulls/3557) +- **Merge commit**: [773dcdacf](https://git.1814.love:8443/wx/HL/commit/773dcdacf) +- **配套新增接口**: 终止退款预览(同日 changelog) + +### 13.2 联系人 + +- **后端负责人**: @yst +- **前端对接(管理后台)**: 终止行程弹框页面 diff --git a/changelogs-v2/2026-06/06_3556_终止退款预览-新增接口-管理后台.md b/changelogs-v2/2026-06/06_3556_终止退款预览-新增接口-管理后台.md new file mode 100644 index 0000000..f3463cd --- /dev/null +++ b/changelogs-v2/2026-06/06_3556_终止退款预览-新增接口-管理后台.md @@ -0,0 +1,159 @@ +# 【✨新增接口·管理后台】终止行程·退款预览 (#3556) + +> **PR**: #3557 | **服务**: hl-order-service-v3 | **更新时间**: 2026-06-06 + +## 1. 接口背景 + +出行中订单因特殊原因需要提前终止行程时,需要给定制师一个「按已用资源算应退多少」的界面。本接口提供终止退款弹框所需的**全部资源清单 + 行程时间轴信息**,定制师选择「停在第几天」后,由前端本地标记每项资源已用/未用并实时算出退款额,最终在终止提交接口落账。 + +## 2. 变更清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 终止退款预览 | POST | `/v3/admin/order/{id}/terminate/refund-preview` | 新增接口 | 返回终止退款弹框所需资源清单 + 行程信息 | + +## 3. 接口详情 + +### 3.1 终止退款预览 + +- **使用场景**:出行中订单点击「终止行程」打开退款弹框时调用一次,拿到整趟全部资源清单 +- **认证**:需要管理端 JWT(`Authorization` 头) +- **幂等性**:是(只读查询,不落库) +- **限流**:无 + +## 4. 接口入参 + +### 4.1 路径参数 + +| 字段 | 类型 | 必填 | 说明 | +|------|------|------|------| +| id | String | ✅ | 订单 ID | + +### 4.2 请求体字段 + +无请求体。前端**一次性**拿到整趟全部资源,「停在第几天」的选择与已用/未用标记、退款金额计算全部在前端本地完成,**不需要每选一天再调本接口**。 + +## 5. 出参(响应) + +### 5.1 响应字段(`data`) + +| 字段 | 类型 | 说明 | +|------|------|------| +| paidAmount | BigDecimal | 已付金额(公司账上已收,前端算退款基线用) | +| tripDays | Integer | 行程总天数(画时间轴用,如 7 天 6 晚 = 7) | +| departDate | String(date) | 出发日期(`yyyy-MM-dd`,第 N 天日期 = 出发日 + N−1) | +| tripCurrentDay | Integer | 当前已出行到第几天(时间轴默认选中点) | +| rooms | Array | 住宿资源清单(每晚每组房一行) | +| tickets | Array | 门票资源清单(每景点每天一行) | +| vehicles | Array | 用车资源清单(**整车已按天展开,每天一行**) | +| insurance | Array | 保险清单(整单一行,锁定不退) | + +### 5.2 ResourceItem 字段(rooms / tickets / vehicles / insurance 各行通用) + +| 字段 | 类型 | 说明 | +|------|------|------| +| refId | String | 资源记录 ID(提交终止时按此回传已用判定;用车多天共用同一 refId,靠 dayNumber 区分;保险可能为 null) | +| name | String | 资源名称(酒店名 / 景点名 / 车型 / 保险产品名) | +| dayNumber | Integer | 对应行程第几天(保险为 null) | +| dealPrice | BigDecimal | 成交单价(住宿=每间每晚价 / 门票=每张价 / 用车=每天每辆日租 / 保险=保费) | +| quantity | Integer | 数量(住宿=房间数 / 门票=张数 / 用车=车辆数 / 保险=1) | +| totalAmount | BigDecimal | 本行小计(= dealPrice × quantity) | +| locked | Boolean | 是否锁定不退(保险恒 true,其余 false) | +| lockedReason | String | 锁定原因(如「保险已生效不退」;未锁定为 null) | + +> 响应**不含**「是否已用」标记与「退款合计」——这些由前端按所选结束天(`dayNumber ≤ 结束天` 默认已用,之后默认可退)实时计算。 + +## 6. 枚举 / 数据字典 + +本接口无枚举字段。资源分类通过 `rooms` / `tickets` / `vehicles` / `insurance` 四个数组区分,无独立 `resourceType` 字段。 + +## 7. 错误码 + +| code | 含义 | 触发场景 | +|------|------|----------| +| 581018 | 出行中取消仅适用于出行中订单 | 订单当前状态非「出行中」时调用本接口 | + +## 8. 示例 + +### 8.1 典型成功 + +**请求**: +``` +POST /v3/admin/order/60001234567890/terminate/refund-preview +Authorization: Bearer {token} +(无请求体) +``` + +**响应**: +```json +{ + "code": 200, + "message": "ok", + "success": true, + "data": { + "paidAmount": 6000.00, + "tripDays": 7, + "departDate": "2026-05-12", + "tripCurrentDay": 3, + "rooms": [ + {"refId": "96011", "name": "拉萨瑞吉度假酒店·大床房", "dayNumber": 1, "dealPrice": 1280.00, "quantity": 1, "totalAmount": 1280.00, "locked": false, "lockedReason": null}, + {"refId": "96014", "name": "拉萨瑞吉度假酒店·大床房", "dayNumber": 4, "dealPrice": 1280.00, "quantity": 1, "totalAmount": 1280.00, "locked": false, "lockedReason": null} + ], + "tickets": [ + {"refId": "97001", "name": "布达拉宫门票", "dayNumber": 2, "dealPrice": 200.00, "quantity": 2, "totalAmount": 400.00, "locked": false, "lockedReason": null} + ], + "vehicles": [ + {"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 1, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null}, + {"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 2, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null}, + {"refId": "98001", "name": "丰田赛那 商务车", "dayNumber": 3, "dealPrice": 600.00, "quantity": 1, "totalAmount": 600.00, "locked": false, "lockedReason": null} + ], + "insurance": [ + {"refId": null, "name": "安联境内旅行险·尊享版", "dayNumber": null, "dealPrice": 256.00, "quantity": 1, "totalAmount": 256.00, "locked": true, "lockedReason": "保险已生效不退"} + ] + } +} +``` + +### 8.2 边界情况 + +**场景说明**:某天住两个酒店(同一 dayNumber 出现多行)。 + +**响应(rooms 片段)**: +```json +"rooms": [ + {"refId": "96021", "name": "林芝希尔顿·双床房", "dayNumber": 2, "dealPrice": 980.00, "quantity": 1, "totalAmount": 980.00, "locked": false, "lockedReason": null}, + {"refId": "96022", "name": "林芝工布庄园·大床房", "dayNumber": 2, "dealPrice": 880.00, "quantity": 1, "totalAmount": 880.00, "locked": false, "lockedReason": null} +] +``` + +### 8.3 业务失败(异常) + +**场景说明**:订单非出行中(如已确认待出发)时调用。 + +**响应**: +```json +{ "code": 581018, "message": "出行中取消仅适用于出行中订单", "success": false } +``` + +## 9. 业务边界 + +- ✅ **适用场景**:订单当前状态 = 出行中(TRAVELLING) +- ❌ **不适用场景**:未出发(待支付 / 待完善 / 已确认待出发)→ 返回 581018;这些状态请走「取消订单」流程,不走终止退款 +- ⚠️ **特殊边界**: + - 保险行恒 `locked=true`,不参与退款 + - 同一天可有多行(多酒店 / 多门票 / 多车),按 refId 区分 + - 用车一段车按行程天数展开为多行,多行共用同一 refId + +## 13. 关联 / 联系人 + +### 13.1 链接 + +- **Issue**: [#3556](https://git.1814.love:8443/wx/HL/issues/3556) +- **PR**: [#3557](https://git.1814.love:8443/wx/HL/pulls/3557) +- **Merge commit**: [773dcdacf](https://git.1814.love:8443/wx/HL/commit/773dcdacf) +- **关联 PR(预览状态校验加固)**: [#3559](https://git.1814.love:8443/wx/HL/pulls/3559) + +### 13.2 联系人 + +- **后端负责人**: @yst +- **前端对接(管理后台)**: 终止行程弹框页面