Refs wx/HL#8750 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
17 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 8750 | 团期子订单封掉订单级行程写口:改行程天 / 增改删节点 4 个接口对团期子订单返回 583066,调整快照不再提示行程与出行日期可编辑 | admin | jw(GIT) | 修改接口 | deployed | verified | pending | mmg | v2.1 | 2026-10-03 | PR #8762 已合并 dev-v3(e8d83b0cb)并滚动部署 TEST 双实例。订单行程 4 个写口(改行程天、新增 / 修改 / 删除节点)对团期子订单一律返回新码 583066,零写入;团期管理员仍先返回 581008;散客单不变。调整快照 editableTabLocksHint 对团期子订单去掉 ITINERARY / SCHEDULE。TEST 网关实测:团期子订单 4 个写口 583066 且三表逐字一致、散客单增改删回写 200、团期管理员 581008、快照两侧取值符合。前端待办:团期子订单详情行程页签隐藏编辑 / 新增 / 删除按钮;团期行程汇总下钻去掉「跳去改」入口,保留跳转查看。 | 2026-10-03 | dev-v3 |
order-v3: 团期子订单封掉订单级行程写口
服务: hl-order-service-v3
PR: #8762(已合入 dev-v3,合并提交 e8d83b0cb);文档回写 #8763
Issue: #8750
⚠️ 关键变化
🔴 团期子订单不能再在订单详情里改行程。 改行程天、新增 / 修改 / 删除节点 4 个接口,对团期子订单一律返回新码 583066,整笔零写入。原来定制师还能改成功,现在改不了。
🟢 散客单完全不变。 请求体、响应体结构都没改。
🟢 调整快照的 editableTabLocksHint 对团期子订单不再含 ITINERARY / SCHEDULE。 这两个页签在调整里一提交就是 587045(#8350),提示与实际行为现在一致。
一、背景
#8350(2026-09-24)定案:团期子订单不能在子订单里调整出行日期和行程,但当时只封了 POST /v3/admin/order/:id/adjustment/submit 一个入口。订单详情行程页签直接调的 4 个写接口仍然开着:团期管理员被按角色拦住,定制师仍能改团期子订单的行程。团期层本来就不提供行程编辑(#7378 AC-I7)。jw 2026-10-03 定:封。
封口后,团期子订单的行程只来自下单时的产品快照,随团期转期、改期同步,没有人工编辑通路。订单调整、转期重排、改期同步、下单物化这些内部路径不走这 4 个接口,不受影响。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 修改行程天 | PUT | /v3/admin/order/:orderId/itinerary/days/:dayId |
行为变更 + 新增错误码 | 团期子订单返回 583066 |
| 2 | 新增行程节点 | POST | /v3/admin/order/:orderId/itinerary/nodes |
行为变更 + 新增错误码 | 团期子订单返回 583066 |
| 3 | 修改行程节点 | PUT | /v3/admin/order/:orderId/itinerary/nodes/:nodeId |
行为变更 + 新增错误码 | 团期子订单返回 583066 |
| 4 | 删除行程节点 | DELETE | /v3/admin/order/:orderId/itinerary/nodes/:nodeId |
行为变更 + 新增错误码 | 团期子订单返回 583066 |
| 5 | 调整快照 | GET | /v3/admin/order/:id/adjustment/snapshot |
返回值变更 | 团期子订单 editableTabLocksHint 去掉 ITINERARY / SCHEDULE |
三、接口详情
1. 修改行程天 PUT /v3/admin/order/:orderId/itinerary/days/:dayId
VO: ItineraryDayUpsertReqVO → Result<ItineraryDayRespVO>
使用场景
订单详情行程页签改某一天的叙事内容(标题、描述、封面图、三餐等)。本次只改变团期子订单的放行规则。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| orderId | Path | Long | ✅ | 订单 ID | 不变;团期子订单直接返回 583066 |
| dayId | Path | Long | ✅ | 该订单的行程天 ID | 不变 |
| dayTitle 等叙事字段 | Body | — | ❌ | 同改前 | 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data | ItineraryDayRespVO | 不变(散客单);团期子订单返回 583066,data 为 null |
请求示例
{
"dayTitle": "海拉尔—额尔古纳 湿地观景",
"description": "上午出发前往额尔古纳湿地,午后登观景台"
}
响应示例
散客单(不变):
{
"code": 200,
"message": "成功",
"data": { "id": "7700000000001", "dayNumber": 2, "dayDate": "2026-10-12", "dayTitle": "海拉尔—额尔古纳 湿地观景" },
"success": true
}
空数据 / 降级响应
写接口无空数据场景。
错误响应
团期子订单(本次新增):
{ "code": 583066, "message": "团期子订单的行程随团期产品,不支持在子订单中修改", "data": null, "success": false }
团期管理员角色(存量,先于 583066 判定):
{ "code": 581008, "message": "无权查看此订单", "data": null, "success": false }
业务边界
- 判团口径与 #8350 相同:订单归属团期(
group_batch_id非空)即为团期子订单。 - 先判团期管理员角色(581008),再判团期子订单(583066),都在任何写之前,拒绝即零写入。
- 订单不存在时不在这里拦,仍按原逻辑返回 583050(行程天不存在)。
2. 新增行程节点 POST /v3/admin/order/:orderId/itinerary/nodes
VO: ItineraryNodeUpsertReqVO → Result<ItineraryNodeRespVO>
使用场景
订单详情行程页签在某一天新增一个节点(景点 / 餐厅 / 活动 / 服务)。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| orderId | Path | Long | ✅ | 订单 ID | 不变;团期子订单直接返回 583066 |
| dayId | Body | Long | ✅ | 该订单的行程天 ID | 不变 |
| nodeType | Body | String | ✅ | SCENIC / RESTAURANT / ACTIVITY / SERVICE | 不变 |
| nodeName | Body | String | ✅ | ≤128 | 不变 |
| 其余字段 | Body | — | ❌ | 同改前 | 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data | ItineraryNodeRespVO | 不变(散客单);团期子订单返回 583066,data 为 null |
请求示例
{
"dayId": "7700000000001",
"nodeType": "SCENIC",
"nodeName": "呼伦湖",
"startTime": "09:30"
}
响应示例
散客单(不变):
{
"code": 200,
"message": "成功",
"data": { "id": "8800000000001", "dayId": "7700000000001", "nodeType": "SCENIC", "sortOrder": 3, "nodeName": "呼伦湖" },
"success": true
}
空数据 / 降级响应
写接口无空数据场景。
错误响应
团期子订单(本次新增):
{ "code": 583066, "message": "团期子订单的行程随团期产品,不支持在子订单中修改", "data": null, "success": false }
业务边界
- 同接口 1:团期管理员 581008 先判,团期子订单 583066 后判,都在写之前。
- 散客单的节点类型校验、资源名反查、自费售价校验(583064)等全部不变。
3. 修改行程节点 PUT /v3/admin/order/:orderId/itinerary/nodes/:nodeId
VO: ItineraryNodeUpsertReqVO → Result<ItineraryNodeRespVO>
使用场景
订单详情行程页签修改某个节点的叙事字段和结算字段。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| orderId | Path | Long | ✅ | 订单 ID | 不变;团期子订单直接返回 583066 |
| nodeId | Path | Long | ✅ | 该订单的节点 ID | 不变 |
| nodeName | Body | String | ✅ | ≤128 | 不变 |
| 其余字段 | Body | — | ❌ | 同改前 | 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data | ItineraryNodeRespVO | 不变(散客单);团期子订单返回 583066,data 为 null |
请求示例
{
"nodeType": "SCENIC",
"nodeName": "呼伦湖",
"description": "湖畔栈道步行约 40 分钟"
}
响应示例
散客单(不变):
{
"code": 200,
"message": "成功",
"data": { "id": "8800000000001", "nodeName": "呼伦湖", "description": "湖畔栈道步行约 40 分钟" },
"success": true
}
空数据 / 降级响应
写接口无空数据场景。
错误响应
团期子订单(本次新增):
{ "code": 583066, "message": "团期子订单的行程随团期产品,不支持在子订单中修改", "data": null, "success": false }
业务边界
- 同接口 1。
- 订单调整(
adjustment/submit)内部改节点不走本接口,不受 583066 影响;它对团期子订单带行程已由 587045 拦截(#8350)。
4. 删除行程节点 DELETE /v3/admin/order/:orderId/itinerary/nodes/:nodeId
VO: ItineraryNodeDeleteReqVO(可不传)→ Result<ItineraryNodeRespVO>
使用场景
订单详情行程页签删除某个节点(软删)。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| orderId | Path | Long | ✅ | 订单 ID | 不变;团期子订单直接返回 583066 |
| nodeId | Path | Long | ✅ | 该订单的节点 ID | 不变 |
| editReason | Body | String | ❌ | ≤500 | 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data | ItineraryNodeRespVO | 不变(散客单,删除前快照);团期子订单返回 583066,data 为 null |
请求示例
DELETE /v3/admin/order/2100743225424621570/itinerary/nodes/8800000000001
Authorization: Bearer <管理端令牌>
响应示例
散客单(不变):
{
"code": 200,
"message": "成功",
"data": { "id": "8800000000001", "nodeName": "呼伦湖" },
"success": true
}
空数据 / 降级响应
写接口无空数据场景。
错误响应
团期子订单(本次新增):
{ "code": 583066, "message": "团期子订单的行程随团期产品,不支持在子订单中修改", "data": null, "success": false }
业务边界
- 同接口 1。
- 散客单删除节点时的应付款台账联动(599602 锁定拦截等)不变。
5. 调整快照 GET /v3/admin/order/:id/adjustment/snapshot
VO: Result<AdjustmentSnapshotRespVO>
使用场景
「调整订单」弹窗打开时取快照;editableTabLocksHint 告诉前端哪些页签可编辑。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | ✅ | 订单 ID | 不变 |
| scope | Query | String | ❌ | 逗号分隔子域 | 不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data.editableTabLocksHint | Array<String> | 🔁 团期子订单不再含 ITINERARY / SCHEDULE;散客单不变 |
| 其余字段 | — | 不变 |
请求示例
GET /v3/admin/order/2100743225424621570/adjustment/snapshot
Authorization: Bearer <管理端令牌>
响应示例
团期子订单(资源准备中):
{
"code": 200,
"message": "成功",
"data": {
"basic": { "orderNo": "HL20260924171304411" },
"editableTabLocksHint": ["BASIC", "PEOPLE", "HOTEL_REQ", "VEHICLE_REQ", "FEE"]
},
"success": true
}
空数据 / 降级响应
无变化:订单不存在等错误与改前一致。
{ "code": 200, "message": "成功", "data": { "editableTabLocksHint": ["BASIC"] }, "success": true }
错误响应
非法 scope(存量):
{ "code": 587003, "message": "调整范围取值非法", "data": null, "success": false }
业务边界
- 只对团期子订单从集合里去掉
ITINERARY/SCHEDULE,其余页签按原来的流程状态规则给出。 - 传单个 scope 时原来是原样回显该 scope;团期子订单传
ITINERARY或SCHEDULE现在返回空集合。
四、契约约束与正确调用方式
| 场景 | 调用 | 结果 |
|---|---|---|
| ❌ 团期子订单改行程天 / 增改删节点 | 接口 1~4 | 583066,零写入 |
| ❌ 团期管理员改任意订单行程 | 接口 1~4 | 581008(存量,先于 583066) |
| ✅ 散客单改行程 | 接口 1~4 | 同改前 |
| ✅ 团期子订单打开调整弹窗 | 接口 5 | editableTabLocksHint 不含 ITINERARY / SCHEDULE |
- 前端对团期子订单应隐藏行程页签的编辑、新增、删除按钮,避免用户点了才看到 583066。
- 团期行程汇总下钻(GB-ADM-019)不再提供「跳去改」入口,保留跳转查看即可。
五、数据库行为
- 无 Flyway migration、无 DDL、无新增写入。
- 团期子订单调接口 1~4:在任何写之前拒绝,
order_itinerary_day/order_itinerary_node/order_main零写入。 - 散客单:写入行为与改前一致。
- 接口 5 只读。
六、边界行为
- 团期子订单调接口 1~4 → 583066。
- 团期管理员调接口 1~4 → 581008(不论散客还是团期子订单)。
- 订单不存在 → 不在守卫拦,按原逻辑报 583050 / 583051。
- 团期子订单调接口 5 →
editableTabLocksHint不含ITINERARY/SCHEDULE。 - 散客单 → 全部不变。
六.6、修改前后对比
| 行为(团期子订单) | 改前 | 改后 |
|---|---|---|
| 定制师 / 管理员改行程天、增改删节点 | 200,写入成功 | 583066,零写入 |
| 团期管理员改行程 | 581008 | 581008(不变) |
调整快照 editableTabLocksHint(全量) |
含 ITINERARY,流程状态早时含 SCHEDULE |
两者都不含 |
调整快照单 scope=ITINERARY / SCHEDULE |
回显该 scope | 空集合 |
六.7、影响评估
- 是否破坏向后兼容: 请求 / 响应结构不变;团期子订单原来能成功的行程编辑现在返回 583066。
- 前端是否必须同步上线: 建议同步。行程页签对团期子订单要隐藏编辑、新增、删除按钮;团期行程汇总下钻去掉「跳去改」入口。不改前端也不会写坏数据,只是用户点了会看到 583066 提示。
- 前端 workaround 清理点: 调整弹窗里对团期子订单置灰出行日期 / 行程页签的自判逻辑,现在可以直接读
editableTabLocksHint。
七、不影响范围
- 散客(非团期)订单的全部行程编辑与调整行为。
- 订单调整统一提交(
adjustment/submit),团期子订单仍按 #8350 返回 587045。 - 团期转期、改期同步、下单物化行程等内部路径。
- 团期用餐口径(#8230 / #8343)、团期行程汇总与下钻(GB-ADM-018 / 019)的读取结果。
POST /v3/admin/order/:id/confirm-itinerary(只确认状态、不改行程内容)。
八、测试环境已验证
真实网关(TEST,https://api.test.1814.love,自签 admin token),部署检出 b9f22e3ad(含合并提交 e8d83b0cb),造数:团期子订单 HL20260929154809598(团号 T26-0352,资源准备中)、散客单 HL20260810141518677(资源准备中):
| 用例 | 请求 | 结果 | 库内读数 |
|---|---|---|---|
| 团期子订单改行程天 / 增 / 改 / 删节点 | 接口 1~4,管理员 token | 583066 ×4 | 订单主表、行程天 7 行、节点 28 行前后逐字一致 |
| 散客单原值回写行程天 | 接口 1 | 200 | 该天整行未变 |
| 散客单新增「莫日格勒河」→ 改描述 → 删除 | 接口 2 → 3 → 4 | 200 ×3 | 新节点写入、描述更新、软删;原有 14 个节点无变化 |
| 团期管理员改散客单行程 | 接口 1~4,团期管理员 token | 581008 ×4 | 三表前后逐字一致 |
| 团期管理员改团期子订单行程天 | 接口 1,团期管理员 token | 581008 | 角色守卫先于 583066 |
| 团期子订单调整快照 | 接口 5 | 200 | editableTabLocksHint = BASIC / PEOPLE / HOTEL_REQ / VEHICLE_REQ / FEE |
| 散客单调整快照 | 接口 5 | 200 | editableTabLocksHint 七项齐全,与改前规则一致 |
| 不带令牌 | 接口 1 | 401 | 零写入 |
单元测试:定向集(行程 / 调整 / 错误码 / 架构包 + 转期改期回归)67 类 825 例,失败 2、错误 0;2 条失败在干净基底上逐条复现,属 #8714 既有,与本次无关。本次新增 13 例全部通过,含 ArchTest:订单行程写端点必须调团期子订单守卫、守卫只许该控制器调用。
部署: PR #8762 已合并 dev-v3(合并提交 e8d83b0cb),TEST 双实例滚动部署完成。
十、相关文档
- 关联 Issue: wx/HL#8750
- 关联 PR: wx/HL#8762、文档 wx/HL#8763
- 前置定案: wx/HL#8350
关联 / 联系人
链接
联系人
- 后端负责人: @jw