diff --git a/changelogs-v2/2026-09/24_8350_团期子订单调整放开增删出行人并同步已报名人数禁止改出行日期与行程-修改接口-管理后台.md b/changelogs-v2/2026-09/24_8350_团期子订单调整放开增删出行人并同步已报名人数禁止改出行日期与行程-修改接口-管理后台.md new file mode 100644 index 00000000..b73f4728 --- /dev/null +++ b/changelogs-v2/2026-09/24_8350_团期子订单调整放开增删出行人并同步已报名人数禁止改出行日期与行程-修改接口-管理后台.md @@ -0,0 +1,250 @@ +--- +schema: "hl-changelog/v2" +ticket: "8350" +title: "团期子订单调整放开增删出行人并同步已报名人数,禁止改出行日期与行程(新增 587045)" +consumer: "admin" +author: "jw(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "pending" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "PR #8353 已合并 dev-v3(8df1c0e84)并滚动部署 TEST 双实例。调整订单统一提交对团期子订单:放开增删出行人(原 587036 退役),差价按团期报价原态/终态求差,同事务同步团期已报名人数 enrolled_people(加人不校验上限);真正改出发日或提交行程一律返回新码 587045,#7325 改回团期出发日出口下线(587039~587042 退役)。散客单不变。前端待办:去掉出行人页签「团期子订单暂不支持调整出行人」提示,团期子订单出行日期/行程页签置灰且不回传未改动的 itinerary.days。" +updated_at: "2026-09-24" +base: "dev-v3" +--- + +# 订单调整模块: 团期子订单放开增删出行人并同步已报名人数,禁止改出行日期与行程 + +> **存放目录**: 二期(v3) → `changelogs-v2/2026-09/` +> +> **服务**: hl-order-service-v3 +> **PR**: #8353 +> **Issue**: #8350 +> **日期**: 2026-09-24 +> **影响范围**: 管理后台「调整订单」弹窗对团期子订单的出行人 / 出行日期 / 行程三个页签 + +--- + +## ⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写) + +- 本次变化:团期子订单在调整弹窗里**可以增删出行人**,**不能改出行日期和行程**——与上版正好相反。 +- 前端以前以为的:团期子订单增删出行人会被 `587036` 拒;改期只能改回团期出发日(`587039`~`587042`),行程可以随便提交。 +- 实际新行为:增删出行人返回 200,差价按团期报价求差,团期「已报名人数」同步增减;团期子订单只要真正改了出发日(**包括改成团期出发日**)或带了 `updates.itinerary.days`,一律返回新码 `587045`,整笔零写入。`587036`、`587039`~`587042` 不再返回。 + +--- + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|------|------|------|----------|------| +| 1 | 调整订单统一提交 | POST | `/v3/admin/order/{id}/adjustment/submit` | 行为变更 + 新增错误码 | 团期子订单放开增删出行人、同步已报名人数;改出发日 / 提交行程返回 587045 | + +--- + +## 三、接口详情 + +### 1. 调整订单统一提交 `POST /v3/admin/order/{id}/adjustment/submit` + +**VO**: `AdjustmentSubmitReqVO → AdjustmentSubmitRespVO` + +#### 使用场景 + +管理端「调整订单」弹窗一次性提交出行人 / 出行日期 / 行程 / 酒店 / 车辆等子领域改动。本次只改变**团期子订单**在出行人、出行日期、行程三个子领域的放行规则;请求体与响应体结构均未变,散客单行为不变。 + +#### 入参 + +> 仅列与本次改动相关的字段,其余子领域字段结构未变。 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|------|------|------|------|------|------| +| Authorization | Header | String | ✅ | - | 管理端登录令牌 | +| id | Path | Long | ✅ | 订单 ID | 目标订单 | +| updates.travelers.add | Body | Array\ | ❌ | 字段同出行人编辑 | 新增出行人;**团期子订单本次起允许** | +| updates.travelers.remove | Body | Array\ | ❌ | 出行人 ID | 删除出行人;**团期子订单本次起允许** | +| updates.travelers.update | Body | Array\ | ❌ | 带 id | 修改出行人资料(团期子订单原本就允许) | +| updates.schedule.departDate | Body | String | ❌ | `yyyy-MM-dd` | **团期子订单**:与当前出发日不同即返回 587045(改成团期出发日也拒);同值回传不拦 | +| updates.itinerary.days | Body | Array | ❌ | - | **团期子订单**:非 null 即返回 587045;`itinerary` 为空对象(`days` 为 null)不拦 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|------|------|------| +| success | Boolean | 提交是否成功;失败由全局异常处理器返回 `Result{code,message,data:null}` | + +#### 请求示例 + +团期子订单新增 1 名成人: + +```json +{ + "updates": { + "travelers": { + "add": [ + { "name": "张三", "gender": "1", "birthday": "1990-01-01", "idType": "ID_CARD", "idNo": "110101199001011234", "phone": "13800000000" } + ] + } + } +} +``` + +#### 响应示例 + +```json +{ "code": 200, "message": "成功", "data": { "success": true }, "success": true } +``` + +#### 空数据 / 降级响应 + +写接口无空数据场景。团期报价服务不可用时不降级,整笔拒绝(见错误响应 581032)。 + +```json +{ "code": 200, "data": { "success": true }, "success": true } +``` + +#### 错误响应 + +团期子订单改出发日(含改成团期出发日)或提交行程(**本次新增**): + +```json +{ "code": 587045, "message": "团期子订单不支持在子订单中调整出行日期和行程,如需改期请走团期转期或联系团期管理员", "success": false, "data": null } +``` + +团期子订单人数变化、团期报价获取失败(存量码,本接口新可达): + +```json +{ "code": 581032, "message": "团期报价获取失败", "success": false, "data": null } +``` + +团期子订单加人时所属团期已流团(存量码,本接口新可达): + +```json +{ "code": 589551, "message": "该团期已流团,不可下单", "success": false, "data": null } +``` + +团期子订单人数变化但解析不到所属团期(存量码,本接口新可达,fail-closed): + +```json +{ "code": 589500, "message": "团期不存在", "success": false, "data": null } +``` + +#### 业务边界 + +- 鉴权、订单归属、窗口守卫(出行人页签 TRAVELLING 起锁、出行日期页签 PENDING_DEPARTURE 起锁)均未改。 +- 587045 在报价与任何写之前判定,拒绝即零写入、零报价调用。 +- 团期子订单人数变化的差价 = 团期报价(`getGroupQuote(班期, 成人, 儿童, 小童, 婴儿=0, 房数)`)终态 − 原态;正数记加收、负数记优惠;防超付守卫(587032)照常。只变婴儿数时不报价、差价为 0。 +- 团期已报名人数 `enrolled_people` 与出行人改动同事务:加人 +N(**不校验人数上限**)、减人 −N(不减到 0 以下)、只改资料或一增一减不变;报名房数 `enrolled_rooms` 不变。 +- 产品侧班期名额(C 端剩余人数)不随调整同步。 + +--- + +## 四、契约约束与正确调用方式(接口类必写) + +> 本节只写后端接受/拒绝 payload 的规则。 + +| 场景 | payload | 结果 | +|------|---------|------| +| ✅ 团期子订单加人 / 删人 | `updates.travelers.add` / `remove` | 200,差价按团期报价求差,已报名人数同步 | +| ✅ 团期子订单回传未改动的出发日 | `updates.schedule.departDate` = 当前出发日 | 不拦,视为未改期 | +| ✅ 团期子订单行程空对象 | `updates.itinerary = {}` | 不拦 | +| ❌ 团期子订单改出发日 | `updates.schedule.departDate` ≠ 当前出发日(含团期出发日) | 587045,零写入 | +| ❌ 团期子订单带行程 | `updates.itinerary.days` 非 null(哪怕与现状相同) | 587045,零写入 | +| ✅ 散客单任意组合 | 同改前 | 行为不变 | + +- 前端对团期子订单提交时**不要携带 `updates.itinerary.days`**,否则连出行人改动一起被拒。 +- 团期子订单改期请走团期转期,不走本接口。 + +--- + +## 五、数据库行为(涉及写操作时必写) + +- 无 Flyway migration、无 DDL。 +- 团期子订单增删出行人:写 `order_traveler`、`order_main` 四档人数、差价(`order_surcharge` / `order_discount` 及主表镜像)、`order_adjustment_record`,与散客单同一套写法。 +- **新增写入**:同一事务内 `order_group_batch.enrolled_people` 按人数差 ±N(`enrolled_rooms` 不动);与创单 +N、取消 −N、对账 Job 同一人数公式(成人 + 儿童 + 小童 + 婴儿),偏差由 `GroupBatchEnrolledReconcileJob` 兜底。 +- 587045 / 581032 / 589551 / 589500 拒绝时整笔零写入。 + +--- + +## 六、边界行为 + +- 团期子订单改出发日 → 587045(取代 587039~587042)。 +- 团期子订单带 `itinerary.days` → 587045。 +- 团期子订单 `schedule` 同值回传、`itinerary` 空对象 → 不拦。 +- 团期子订单增删出行人 → 200(取代 587036)。 +- 团期报价失败 → 581032;团期已流团时加人 → 589551;解析不到团期 → 589500。 +- 散客单 → 行为不变。 + +--- + +## 六.6、修改前后对比(修改/删除类接口必写,新增跳过) + +| 行为(团期子订单) | 改前 | 改后 | +|------|------|------| +| 增删出行人 | 587036 拒绝 | 200,差价按团期报价求差 | +| 已报名人数 `enrolled_people` | 调整不同步,等对账 Job | 同事务 ±N | +| 改出发日为团期出发日 | 允许(#7325 出口) | 587045 | +| 改出发日为其他日期 | 587039 | 587045 | +| 提交行程 `itinerary.days` | 允许 | 587045 | +| 错误码 587036、587039~587042 | 可能返回 | 不再返回(号段保留不复用) | + +--- + +## 六.7、影响评估(修改/删除类必写) + +- **是否破坏向后兼容**: 请求/响应结构不变;团期子订单原来能成功的「改回团期出发日」「提交行程」现在返回 587045,原来被拒的增删出行人现在成功。 +- **前端是否必须同步上线**: 建议同步。前端当前对出行人页签显示「团期子订单暂不支持调整出行人」,需去掉;出行日期、行程页签需对团期子订单置灰,且提交时不回传未改动的 `itinerary.days`,否则出行人改动会被 587045 连带拒掉。 +- **前端 workaround 清理点**: 前端针对 587036 / 587039~587042 的文案或分支可删除。 + +--- + +## 七、不影响范围(显式声明, 帮前端/QA 缩小排查面) + +- 散客(非团期)订单的全部调整行为。 +- 团期子订单的酒店、车辆、接送机、紧急联系人子领域。 +- 团期转期、团期管理台其他接口。 +- 产品侧班期名额(`enrollBatch` / `unenrollBatch`)。 + +--- + +## 八、测试环境已验证 + +真实网关(TEST,`https://api.test.1814.love`,自签 admin token),造数:班期 `2103050046352322562`(团期报价 1/2/3 成人 = 3000/6000/9000)、团期 `2103050071622983681`、团期子订单 `HL20260924171304411` / `HL20260924171740384`、散客单 `HL20260924172017561`: + +| 用例 | 请求 | 结果 | 库内读数 | +|------|------|------|----------| +| 团期子订单加 1 人 | `updates.travelers.add` | 200 | 成人 2→3;加收 3000(= 9000 − 6000);调整记录「总人数 2→3」;`enrolled_people` 2→3,`enrolled_rooms` 不变 | +| 团期子订单只改资料 | `updates.travelers.update` | 200 | `enrolled_people` 不变 | +| 团期子订单删 1 人 | `updates.travelers.remove` | 200 | 优惠 3000;`enrolled_people` 3→2 | +| 已全额收款团期子订单删人 | `updates.travelers.remove` | 587032 | 零写入(防超付照常) | +| 改出发日为团期出发日 / 其他日期 / 加人 + 改期 | `updates.schedule.departDate` | 587045 ×3 | 前后快照逐字相同,出行人未加 | +| 行程原样回传 / 删一个节点 | `updates.itinerary.days` | 587045 ×2 | 零写入 | +| 出发日同值回传(± 改资料) | `updates.schedule.departDate` = 当前值 | 200 | 只落资料修改,未改期 | +| 散客对照:加人 / 改期 / 删人 / 改行程 | 同上 | 200 ×4 | 差价走个人报价(+8400 / −8400),改期未被 587045 拦 | + +终态一致性:该团未取消子订单人数合计 4,等于 `enrolled_people=4`。 + +单元测试:`AdjustmentServiceSubmitTest` 嵌套类 `GroupSubOrderAdjustTests` 16 例等,定向集 `Tests run: 235, Failures: 0, Errors: 0`;`TransactionalRemoteCallArchTest` 绿。 + +部署: PR #8353 已合并 `dev-v3`(合并提交 `8df1c0e84`),TEST 双实例滚动部署完成。 + +--- + +## 十、相关文档 + +- 关联 Issue: [wx/HL#8350](https://git.1814.love/wx/HL/issues/8350) +- 关联 PR: [wx/HL#8353](https://git.1814.love/wx/HL/pulls/8353) + +## 关联 / 联系人 + +### 链接 + +- **Issue**: [#8350](https://git.1814.love/wx/HL/issues/8350) +- **PR**: [#8353](https://git.1814.love/wx/HL/pulls/8353) +- **Merge commit**: [8df1c0e84](https://git.1814.love/wx/HL/commit/8df1c0e84) + +### 联系人 + +- **后端负责人**: @jw