docs(changelogs-v2): 订单调整 snapshot/submit 契约重制(#4488/#4498/#4502/#4509/#4516)
snapshot 出参:basic 每次必返+承载订单号/产品名/团号+5金额,删顶层 discounts/surcharges/金额,行程改 days[].nodes[] 带价; submit 入参:删 editReason/tabLocks/confirmDiffHash/basic/feeChanges,行程改 days[].nodes[];出参精简为仅 success。
这个提交包含在:
父节点
8941096a45
当前提交
ea9d7ed769
@ -0,0 +1,217 @@
|
|||||||
|
# 订单调整 snapshot / submit 契约重制——basic 承载订单信息+金额、行程 tab 定价化、submit 入出参大幅精简
|
||||||
|
|
||||||
|
> 端类型:管理后台
|
||||||
|
> 变更类型:修改接口(**破坏性**,前端需同步改造)
|
||||||
|
> 涉及接口:
|
||||||
|
> - `GET /v3/admin/order/{id}/adjustment/snapshot`(调整弹窗预填快照)
|
||||||
|
> - `POST /v3/admin/order/{id}/adjustment/submit`(调整统一提交)
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
订单调整弹窗的预填快照与统一提交接口经一轮重制:snapshot 的 `basic` 改为每次必返并承载订单身份+金额、行程 tab 升级为带价展示、删除前端用不到的优惠/附加费列表;submit 入参删除若干无用/已不支持字段、行程改嵌套结构、出参精简为只剩成功标志。**两个接口的入出参结构均有破坏性变化,前端需按本文同步改造。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、`GET /v3/admin/order/{id}/adjustment/snapshot`(出参重制)
|
||||||
|
|
||||||
|
### 入参(不变)
|
||||||
|
|
||||||
|
| 位置 | 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|---|---|---|:---:|---|
|
||||||
|
| path | `id` | Long | 是 | 订单 ID |
|
||||||
|
| query | `scope` | String | 否 | 限定返回子域,逗号分隔,不传返全部。枚举:`BASIC`/`PEOPLE`/`SCHEDULE`/`ITINERARY`/`HOTEL_REQ`/`VEHICLE_REQ`(**`FEE` 已移除**) |
|
||||||
|
|
||||||
|
### 关键变更
|
||||||
|
|
||||||
|
1. **`basic` 每次必返**(不再受 `scope` 限制,传任意 scope 都返回 basic)。
|
||||||
|
2. **`basic` 新增订单身份字段**:`orderNo`/`productName`/`teamNo`/`productType`(只读展示)。
|
||||||
|
3. **订单金额从顶层移入 `basic`**:`orderAmount`/`surchargeAmount`/`discountAmount`/`receivableAmount`/`balanceAmount`。其中 `receivableAmount`(应收总额)为新增字段。
|
||||||
|
4. **删除顶层字段**:`discounts[]`、`surcharges[]`、`orderAmount`、`surchargeAmount`、`discountAmount`、`balanceAmount`(金额已并入 basic;优惠/附加费列表下线)。
|
||||||
|
5. **行程 `itinerary` 改嵌套带价**:原顶层 `nodes[]` 删除,节点改挂在 `days[].nodes[]` 下,并新增单价/数量/小计/本日合计。
|
||||||
|
|
||||||
|
### 出参 `basic`(OrderBasicVO)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `orderNo` | String | 订单号(只读)🆕 |
|
||||||
|
| `productName` | String | 产品名(快照,只读)🆕 |
|
||||||
|
| `teamNo` | String | 团号(订金支付后生成,未支付为 null,只读)🆕 |
|
||||||
|
| `productType` | String | 订单类型 CORE/ROUTE/CUSTOM/GROUP(只读)🆕 |
|
||||||
|
| `customerName` | String | 客户姓名(脱敏) |
|
||||||
|
| `customerPhone` | String | 客户手机(脱敏) |
|
||||||
|
| `emergencyContact` | String | 紧急联系人 |
|
||||||
|
| `customerRemark` | String | 客户备注 |
|
||||||
|
| `consultantRemark` | String | 顾问备注(内部) |
|
||||||
|
| `tags` | String[] | 订单标签 |
|
||||||
|
| `adultCount` / `childCount` / `youngChildCount` / `babyCount` | Integer | 成人/儿童/幼童/婴儿人数 |
|
||||||
|
| `orderAmount` | String(金额) | 订单基价(由顶层迁入)🔁 |
|
||||||
|
| `surchargeAmount` | String(金额) | 已有附加费合计(由顶层迁入)🔁 |
|
||||||
|
| `discountAmount` | String(金额) | 已有优惠合计(由顶层迁入)🔁 |
|
||||||
|
| `receivableAmount` | String(金额) | 应收总额 = 基价+附加费−优惠,≥0,取消单为 0 🆕 |
|
||||||
|
| `balanceAmount` | String(金额) | 待付尾款 = 应收−净已付,≥0,取消单为 0(由顶层迁入)🔁 |
|
||||||
|
|
||||||
|
> 金额字段均序列化为**字符串**(防 JS 精度丢失)。
|
||||||
|
|
||||||
|
### 出参 `itinerary`(ItineraryEditVO,嵌套带价)
|
||||||
|
|
||||||
|
| 路径 | 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| days[] | `id`/`dayNumber`/`dayDate`/`theme` | - | 行程天信息 |
|
||||||
|
| days[] | `nodes[]` | 数组 | 当天节点(**已过滤 HOTEL 节点**)🆕 |
|
||||||
|
| days[] | `dayTotal` | 金额 | 本日合计 = Σ节点 subtotal,后端派生只读 🆕 |
|
||||||
|
| days[].nodes[] | `id`/`dayId`/`nodeType`/`title`/`startTime`/`sortOrder` | - | 节点信息 |
|
||||||
|
| days[].nodes[] | `unitPrice` | 金额 | 单价(叙事展示;非 SCENIC 节点当前为 0)🆕 |
|
||||||
|
| days[].nodes[] | `quantity` | Integer | 数量(默认 1)🆕 |
|
||||||
|
| days[].nodes[] | `subtotal` | 金额 | 小计 = unitPrice×quantity,后端派生只读 🆕 |
|
||||||
|
|
||||||
|
> ⚠️ 原顶层 `itinerary.nodes[]` 已删除,全部迁入 `days[].nodes[]`。
|
||||||
|
> 其余子域 `travelers` / `schedule` / `hotelRequirement` / `hotelDayDefaults` / `vehicleRequirement` / `lockedDays` / `editableTabLocksHint` 不变。
|
||||||
|
|
||||||
|
### snapshot 出参示例(节选)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"code": 200,
|
||||||
|
"data": {
|
||||||
|
"basic": {
|
||||||
|
"orderNo": "HL202608010001",
|
||||||
|
"productName": "长白山深度5日游",
|
||||||
|
"teamNo": "GB202608001",
|
||||||
|
"productType": "CORE",
|
||||||
|
"customerName": "张*",
|
||||||
|
"adultCount": 4,
|
||||||
|
"orderAmount": "12000.00",
|
||||||
|
"surchargeAmount": "800.00",
|
||||||
|
"discountAmount": "200.00",
|
||||||
|
"receivableAmount": "12600.00",
|
||||||
|
"balanceAmount": "3000.00"
|
||||||
|
},
|
||||||
|
"itinerary": {
|
||||||
|
"days": [
|
||||||
|
{
|
||||||
|
"id": "1001", "dayNumber": 1, "dayDate": "2026-08-01", "theme": "天池徒步",
|
||||||
|
"nodes": [
|
||||||
|
{ "id": "2001", "nodeType": "SCENIC", "title": "长白山天池门票", "unitPrice": "128.00", "quantity": 1, "subtotal": "128.00" },
|
||||||
|
{ "id": "2002", "nodeType": "RESTAURANT", "title": "午餐", "unitPrice": "0", "quantity": 1, "subtotal": "0" }
|
||||||
|
],
|
||||||
|
"dayTotal": "128.00"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、`POST /v3/admin/order/{id}/adjustment/submit`(入参 + 出参重制)
|
||||||
|
|
||||||
|
### 入参 `AdjustmentSubmitReqVO`
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|---|---|:---:|---|
|
||||||
|
| `updates` | 对象 | 是 | 各子域改动(按需填,未改置 null,但不能全 null) |
|
||||||
|
|
||||||
|
> ⚠️ **删除入参字段**:`editReason`(原必填)、`tabLocks`、`confirmDiffHash`。这三个一律不再传。
|
||||||
|
|
||||||
|
### `updates`(AdjustmentUpdatesVO)—— 现仅 5 个子域
|
||||||
|
|
||||||
|
| 子域 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `travelers` | 对象 | 出行人增删改:`add[]` / `update[]`(含 id)/ `remove[]`(id 列表) |
|
||||||
|
| `schedule` | 对象 | 改期:`departDate`(新出发日 yyyy-MM-dd,本子域存在时必填,不可同原值) |
|
||||||
|
| `itinerary` | 对象 | 行程:`days[].nodes[]`(见下) |
|
||||||
|
| `hotelRequirement` | 对象 | 房需求完整新版本:`totalRoomCount`/`roomTypeSummary`/`specialTags[]`/`remark`/`days[]` |
|
||||||
|
| `vehicleRequirement` | 对象 | 车需求完整新版本:`vehicleType`/`requiredSeats`/`remark`/`fleet[]` |
|
||||||
|
|
||||||
|
> ⚠️ **删除子域**:`basic`(订单基础信息不再在调整弹窗修改)、`feeChanges`(手动加优惠/附加费下线)。
|
||||||
|
|
||||||
|
### `updates.itinerary` 行程入参
|
||||||
|
|
||||||
|
| 路径 | 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| days[] | `id`/`dayNumber` | - | 定位天;`days` 数量比现有多/少 → 后端差量增/减天 |
|
||||||
|
| days[].nodes[] | `id` | Long | 定位要改的节点;为 null 视为新建(本期不支持,忽略) |
|
||||||
|
| days[].nodes[] | `unitPrice` / `quantity` | - | 传了即改单价/数量(patch,不传不动) |
|
||||||
|
| days[].nodes[] | `deleted` | Boolean | true=删除该节点 |
|
||||||
|
|
||||||
|
### 出参 `AdjustmentSubmitRespVO`(精简)
|
||||||
|
|
||||||
|
| 字段 | 类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `success` | Boolean | 提交是否成功 |
|
||||||
|
|
||||||
|
> ⚠️ 出参从原 15 字段精简为**仅 `success`**。删除:`appliedScopes`/`affectedRows`/`newHotelRequirementId`/`newHotelVersion`/`newVehicleRequirementId`/`newVehicleVersion`/`assignmentDeletedCount`/`statusLogId`/`changedDims`/`affectedDays`/`priceDelta`/`newDepartDate`/`newReturnDate`/`newFlowStatus`。
|
||||||
|
> **失败时**统一走全局异常:HTTP 200 + `Result{code: 587xxx, message: "..."}`,前端按已有错误码机制读 `code`/`message`。
|
||||||
|
|
||||||
|
### submit 入参示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"updates": {
|
||||||
|
"schedule": { "departDate": "2026-09-01" },
|
||||||
|
"itinerary": {
|
||||||
|
"days": [
|
||||||
|
{ "id": "1001", "dayNumber": 1, "nodes": [
|
||||||
|
{ "id": "2001", "unitPrice": "150.00", "quantity": 2 },
|
||||||
|
{ "id": "2003", "deleted": true }
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"travelers": { "remove": [70001005] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### submit 成功出参示例
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": 200, "message": "success", "data": { "success": true } }
|
||||||
|
```
|
||||||
|
|
||||||
|
### submit 失败出参示例(如:减员致有效总额低于已付)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "code": 587032, "message": "调整后总额低于已支付金额,不允许本次调整", "data": null }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、错误码(submit 失败可能返回,前端按 code/message 展示)
|
||||||
|
|
||||||
|
| code | message | 含义 |
|
||||||
|
|---|---|---|
|
||||||
|
| 587002 | 订单已是终态,不可调整 | 订单 COMPLETED/CANCELLED 不可调整 |
|
||||||
|
| 587012 | updates 所有子领域均为空,无实际修改 | 未提交任何子域 |
|
||||||
|
| 587032 | 调整后总额低于已支付金额,不允许本次调整 | 防超付 |
|
||||||
|
| 587034 | 已出行,出行人不可调整 | 出行中改出行人被拦 |
|
||||||
|
| 587035 | 行程已确认,出发日期不可修改 | 改期窗口已关 |
|
||||||
|
| 587036 | 团期子订单不支持通过调整弹窗增删出行人,请前往团期管理台操作 | 团期出行人增删拦截 |
|
||||||
|
|
||||||
|
> 注:上表为常见项,完整错误码以后端 IErrorCode 段位为准;前端只需读 `code`/`message`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、业务边界 / 注意
|
||||||
|
|
||||||
|
- **团期(GROUP)订单不能在调整弹窗改人数**:团期增删出行人被拦截,且基础信息子域已删,故团期人数变更不在本弹窗。非团期订单通过增减出行人(`travelers`)改人数。
|
||||||
|
- **行程单价为叙事展示价**,不进结算、不影响订单应付总额(改单价不触发算价)。
|
||||||
|
- **HOTEL 节点**不在 `itinerary.days[].nodes[]` 出现(配房默认值另走 `hotelDayDefaults`)。
|
||||||
|
- 人数/天数/行程改动触发的**自动价差**仍会写入订单加费/优惠(后端处理,前端无需关心)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、影响评估 / 前端改造点
|
||||||
|
|
||||||
|
1. snapshot:金额与订单号/产品名/团号读取改从 `data.basic.*`(原顶层金额字段已无);不再渲染 `discounts`/`surcharges` 列表。
|
||||||
|
2. snapshot:行程 tab 改读 `itinerary.days[].nodes[]`(含单价/数量/小计/本日合计),原顶层 `itinerary.nodes[]` 不存在。
|
||||||
|
3. submit:请求体去掉 `editReason`/`tabLocks`/`confirmDiffHash`/`updates.basic`/`updates.feeChanges`;行程改提交 `days[].nodes[]`。
|
||||||
|
4. submit:响应只读 `data.success`(其余字段已删);失败读 `code`/`message`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、关联
|
||||||
|
|
||||||
|
- Issue:#4488(行程 tab 定价化)/ #4498(应收总额)/ #4502(金额挪 basic + basic 恒返 + 身份字段)/ #4509(submit 删 editReason/tabLocks)/ #4516(submit 删 confirmDiffHash/basic/feeChanges + 出参精简)
|
||||||
|
- PR:#4497 / #4500 / #4504 / #4521
|
||||||
|
- 负责人:腰苏图(yst)
|
||||||
正在加载...
x
在新工单中引用
屏蔽一个用户