19 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 | 7325 | 团期子订单改期出口:只允许改回所属团期出发日,新增 4 个错误码 587039-587042 | admin | wx(GIT) | 修改接口 | deployed | not_required | verified | mmg | 0df56c73a2d78e5c7d492733b18c07c7298db9b0 | 2026-09-15 | PR #7743(Issue #7325)已合并 dev-v3(合并提交 88cab06dc,2026-09-15 13:54,squash 直接落在 dev-v3 上)。2026-09-15 14:07:35 测试服部署 dev-v3@88cab06dc(含本次改动,经 deploy-status.sh 实测确认),并做了真实网关端到端取证:越界户 O1(团期 2099674449308545025)POST adjustment/submit 提交 departDate=2026-12-16(该团期出发日)返回 200 成功;整团重新确认需求后 confirm-check 的 outOfRangeOrders 变为空数组、blockedByOutOfRange=false;房务补齐分房并确认后 hotelReady=true、ready=true,验证了本单要解决的产品问题(越界户可经这条出口回到团期区间内)全链路打通。但新增的 4 个拒绝错误码 587039-587042 本轮均未触发(实测走的是成功路径),其响应内容取自源码 AdjustmentErrorCode.java 定义,非测试服抓包。backend_status 记 deployed。gateway_status=not_required:改动的端点 POST /v3/admin/order/{orderId}/adjustment/submit 是已有路由,未新增/修改路径。frontend_status=pending:待前端确认订单调整弹窗改期 tab 对团期子订单是否已限制日期选择器只能选团期出发日,以及新错误码 587039-587042 的文案展示。 前端已闭环(0df56c73):FunItemAdjustModal 团期子订单(groupBatchId 非空或 productType=GROUP)改期日期选择器只放行所属团期出发日(打开拉 getGroupBatchDetail 取 departDate,失败退化仅禁过去),改期 tab 补团期专属提示;587039-587042 走拦截器透 message;时间线 extra.resourceType 新值 RESCHEDULE 前端无映射(EXTRA_KEYS 不含该键)无需动;spec +3 例共 24/24。 | 2026-09-15 | dev-v3 |
团期越界户: 单户改期出口只能回团期出发日
存放目录:
- 一期(v2,无 order-v3 标签的工单)→ changelogs/{YYYY-MM}/
- 二期(v3,order-v3 标签的工单)→ changelogs-v2/{YYYY-MM}/
服务: hl-order-service-v3 (端口 8086) PR: #7743(已合并 dev-v3,合并提交 88cab06dc) Issue: #7325 日期: 2026-09-15 影响范围: 管理后台订单调整弹窗改期 tab,对团期子订单(挂了 productBatchId 的订单)提交新出发日期时的校验规则与新错误码
关键变化
- 本次变了什么:管理端 POST /v3/admin/order/{orderId}/adjustment/submit(改期 tab,即提交体 updates.schedule.departDate)对团期子订单新增一段专属校验:新出发日期必须精确等于所属团期的出发日,不能是团期区间内外的其它任意日期;同时团期子订单改期不再按个人价格日历算改期差价(团期本身按班期定价,改期不产生价格增量)。新增 4 个错误码 587039-587042。
- 前端调用方以前以为的是什么:团期子订单和散客单一样,改期 tab 的日期选择器可选范围由个人价格日历的可售日期决定;提交一个团期区间外的日期会拿到既有的「日期不可售」类错误码(581041)。
- 实际现在是什么:团期子订单改期前先判定是否团期订单,若是则只放行「改回团期出发日」这一个值,其余任何日期一律拒绝(587039),且不再查个人价格日历、不产生改期差价;越界户借由这条路径可以改回团期出发日从而回到团期区间内(这是本次要解决的产品问题:越界户此前既不能保持越界也不能靠个人改期机制回到区间内,双向都被挡死)。
一、背景(选填)
工单 7325:团期越界户(住宿晚落到团期出行区间 [出发日, 结束日) 外)此前没有产品内出口。管理端单户改期原本按个人价格日历报价,团期子订单查不到对应日期,会抛出误导性的 581041「日期不可售」,导致越界户无论是推出区间还是改回区间都被挡住。本次给出唯一出口:团期子订单改期只允许改回所属团期出发日。
| 维度 | 证据 |
|---|---|
| 团期子订单判定 | AdjustmentService.java 第 1627-1629 行 isGroupSubOrder:product_batch_id 非空即团期子订单,与 RequirementService 改期重置分支同口径 |
| 守卫触发时机 | AdjustmentService.java 第 290 行:resolveGroupBatchRescheduleTarget 在报价与一切写之前调用,拒绝即零写入 |
| 判定顺序 | 团期/出发日解析失败(587040) → 日期不等于团期出发日(587039) → 晚数不匹配(587041) → 仍有区间外分房(587042) |
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 订单调整统一提交(改期 tab) | POST | /v3/admin/order/{orderId}/adjustment/submit |
请求校验新增分支 + 错误码新增 | 团期子订单改期新增专属校验链,新增 4 个错误码 587039-587042 |
三、接口详情
1. 订单调整统一提交(改期 tab) POST /v3/admin/order/{orderId}/adjustment/submit
VO: AdjustmentSubmitReqVO → Result<AdjustmentSubmitRespVO>
使用场景
管理后台订单详情页的调整弹窗,改期 tab 填写新出发日期后点提交调用(同一接口也承载出行人、行程、房需求、车需求等其它 tab 的改动,本文件只描述改期 tab 涉及团期子订单时新增的那段校验)。完整的请求体结构、其它子领域字段、既有校验规则见既有契约:changelogs-v2/2026-06/27_4488_订单调整snapshot与submit契约重制-修改接口-管理后台.md;本文件只补团期子订单改期这一新增分支。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| orderId | Path | Long | 是 | - | 本次未改 |
| updates.schedule.departDate | Body | String | 提交改期 tab 时必填 | ISO yyyy-MM-dd,不可与原出发日相同 | 本次未改字段本身,但团期子订单提交此字段时会触发下方新校验链 |
(其它子领域字段 updates.people/travelers/itinerary/hotelRequirement/vehicleRequirement 本次未改,见既有契约)
出参字段表 Result<AdjustmentSubmitRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| data | Object | 提交结果,字段结构本次未改,见既有契约 |
(本次不新增响应字段,改动完全体现在请求校验与错误码上)
请求示例
2026-09-15 14:14:26 测试服真实网关请求(团期 2099674449308545025 出发日为 2026-12-16,户 O1 此前已被 SQL 改到区间外,本次提交改回团期出发日):
{ "updates": { "schedule": { "departDate": "2026-12-16" } } }
响应示例
同一请求的真实响应(roleId=2):
{ "code": 200, "message": "成功", "data": { "success": true }, "success": true }
空数据 / 降级响应
本端点不存在成功但空数据的形态,校验通过即按既有契约返回变更结果。
错误响应
新增错误码(源码 AdjustmentErrorCode.java 第 82、86、94、107 行;⚠️ 以下四个 JSON 均取自源码定义,本轮 2026-09-15 测试服实测走的是成功路径(见上方请求/响应示例),未触发任何一个拒绝分支,拒绝码未实测,文案取自 AdjustmentErrorCode):
{ "code": 587039, "message": "团期子订单只能改回所属团期的出发日(2026-06-08)", "data": null, "success": false }
{ "code": 587040, "message": "团期子订单未找到所属团期出发日,无法改期,请先核对团期信息", "data": null, "success": false }
{ "code": 587041, "message": "行程 3 晚与团期 4 晚不一致,改期无法回到团期区间,请走转期或由团期管理员处理", "data": null, "success": false }
{ "code": 587042, "message": "该户仍有 2 条团期分房落在团期区间外,改期前请先由房务释放这些分房", "data": null, "success": false }
业务边界
- 只对团期子订单(product_batch_id 非空)且本次提交确实会改变出发日期时才触发这条校验链;散客单沿用既有改期规则,不受影响。
- 四个错误码在任何写操作之前判定完,触发任意一个都是零写入(不改订单、不改需求、不扣库存),与既有的「拒绝即零写入」调用约定一致。
- 判定顺序固定:团期/出发日解析失败(587040) 优先于 日期不等于团期出发日(587039) 优先于 晚数不匹配(587041) 优先于 仍有区间外分房(587042);前端可按此顺序设计错误码分支的优先级,但不需要自己复刻这个顺序判断,后端只会返回命中的第一个。
- 团期子订单改期不再走个人价格日历报价:本次提交若只改期不改其它子领域,不会产生改期差价(团期按班期定价,出发日只能改回团期出发日,价格不因此变化)。
四、契约约束与正确调用方式(接口类必写)
本节只写后端接受拒绝 payload 的规则与调用后必须知道的取值规则,不写 UI 渲染建议。
正确与错误调用方式对照
| 场景 | 说明 |
|---|---|
| 正确:团期子订单改期前先查该户所属团期的出发日,日期选择器只放开这一个值 | 提交其它任何日期都会拿到 587039,不如提前在 UI 上限制选择范围 |
| 正确:587042 出现时引导用户联系房务先释放区间外分房,而不是重试提交 | 该错误码是兜底防御,正常路径下不应触发;重试同样的请求不会成功,需要先由房务操作 |
| 错误:对团期子订单沿用散客单的个人价格日历可选日期范围渲染选择器 | 团期子订单的可选范围只有团期出发日一个值,与个人价格日历无关 |
| 错误:把 587039/587040/587041 当成同一类日期错误统一兜底文案 | 三者含义不同(改期目标不对 / 团期数据缺失 / 晚数不匹配),建议分别给出引导文案 |
切换状态时的必要动作
改期成功(团期子订单改回团期出发日)后,后端会连带触发:该子订单用车需求按团期口径重新生成版本、团期 hotel_ready 置回待重判、整团需求确认标记清零(触发整团重新确认流程)。前端若在改期成功后停留在该订单详情页,建议主动刷新一次房需求/车需求/团期状态区块,因为这些数据可能在改期这次提交里被后端连带改动,而不是显式出现在改期本身的响应体里。
五、数据库行为(涉及写操作时必写)
| 场景 | 写行为 |
|---|---|
| 四个新错误码任一命中 | 零写入 |
| 团期子订单改期成功 | order_main 出发日/返程日更新(本次未改这一步本身);该户用车需求按团期口径重新生成版本(沿用转期同款入口,散客改期入口对团期子订单直接返回 0);group_batch.hotel_ready 置回待重判;group_batch 的整团需求确认标记(requirement_confirmed)条件清零,仅当此前确实是已确认状态才会真的清成未确认并写团期时间线 |
| 团期时间线新增记录 | 若确认标记被真的清零,会在既有事件 BATCH_REQUIREMENT_REOPENED 下新写一条时间线,extra 里的 resourceType 字段本次新增一个取值 RESCHEDULE(此前该字段只出现 HOTEL/VEHICLE 两种取值,见「六.5」) |
六、边界行为
- 未登录 → 401(网关拦截,本次未改)
- 非团期子订单提交改期 → 不触发本次新增的任何校验,走既有散客改期规则
- 团期子订单提交与当前出发日相同的日期 → 不算改期,不触发本次新增校验(既有的「无实际变化」判定,本次未改)
- 团期解析失败或团期缺出发日 → 587040,fail-closed,不回退到个人价格日历
- 出发日正确但行程晚数与团期晚数不一致 → 587041
- 出发日与晚数都正确但仍有分房行落在团期区间外 → 587042,需房务先释放
六.5、枚举 / 数据字典(接口出现枚举时必写)
resourceType(团期状态流水 extra.resourceType,既有字段新增一个取值)
所属字段: GET /v3/admin/order/group-batch/{groupBatchId}/status-logs 里 eventType=BATCH_REQUIREMENT_REOPENED 记录的 extra.resourceType(既有字段,非本文件改动的端点直接返回,但本次改动会让它出现新取值) | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
HOTEL |
房需求触发 | 既有取值,定制师改酒店需求触发确认标记清零 |
VEHICLE |
车需求触发 | 既有取值,定制师改车需求触发确认标记清零 |
RESCHEDULE |
改期触发 | 本次新增取值,团期子订单改期触发确认标记清零;前端若对这个字段做了枚举映射,需要补上这个新值的展示文案 |
六.6、修改前后对比(修改/删除类接口必写,新增跳过)
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
| adjustment/submit 请求体/响应体字段结构 | 见既有契约 | 不变 |
| 团期状态流水 extra.resourceType 取值域 | HOTEL、VEHICLE | 新增 RESCHEDULE |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 团期子订单提交改期到团期区间外的日期 | 按个人价格日历查不到该日期,抛误导性的 581041「日期不可售」 | 明确拒绝,587039,文案指出唯一合法目标是团期出发日 |
| 团期子订单改回团期出发日 | 同样走个人价格日历报价,可能因查不到日期而失败 | 放行,不查个人价格日历,不产生改期差价 |
| 团期子订单改期成功后的连带效果 | 无(此前这条路径走不通) | 用车需求按团期口径重版、hotel_ready 置回待重判、整团确认标记清零 |
六.7、影响评估(修改/删除类必写)
- 是否破坏向后兼容:对散客单无影响。对团期子订单,此前改期到区间外日期会拿到 581041(且报价环节可能有不可预期的副作用),现在会拿到语义明确的 587039-587042 四个新码之一;如果前端对 581041 有团期专属的兜底文案,需要确认新码是否需要补充对应文案。
- 前端是否必须同步上线:建议同步——四个新错误码的文案与既有 581041 不同,若前端没有兜底会展示成未知错误码。
- 前端 workaround 清理点:若前端此前为团期子订单改期失败做过 581041 特殊文案的 workaround,本次上线后可以针对新码调整为更准确的引导文案。
七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
- 仅影响:团期子订单(product_batch_id 非空)通过 adjustment/submit 改期 tab 提交新出发日期时的校验与错误码;连带触发的用车需求重版、hotel_ready 重判、整团确认标记清零。
- 零影响:
- 散客单(无 productBatchId)的改期行为
- adjustment/submit 的其它子领域(出行人、行程、房需求、车需求)
- 团期子订单的行程天数/人数等非改期字段的调整
- 团期看板 H7-H11 系列端点(本身不受本次改动触碰,只是本次改动的后置效果会让它们在下次重判时看到最新状态)
八、测试环境已验证
部署:PR #7743(合并提交 88cab06dc,2026-09-15 13:54)已合并 dev-v3;测试服 2026-09-15 14:07:35 部署 hl-order-service-v3@88cab06dc(deploy-status.sh 实测确认),本节取证全程在此版本上进行。
真实网关端到端取证(团期 2099674449308545025,户 O1=2099674449094635522,出发日 2026-12-16;该户之前已被 SQL 改到出发日 2026-12-17/返程 2026-12-19、制造 2026-12-18 越界晚,即 15_7325 文件里记录的越界样本):
| 时刻 | 步骤 | 接口 | 结果 |
|---|---|---|---|
| 14:14:21 | 改期前 confirm-check | GET confirm-check | outOfRangeOrders 含 O1 一条(tripNights=2, stayDate=2026-12-18, reason=OUT_OF_RANGE),blockedByOutOfRange=true |
| 14:14:26 | 提交改期回团期出发日 | POST adjustment/submit,body={"updates":{"schedule":{"departDate":"2026-12-16"}}} | 200,data={"success":true} |
| 14:14:40 | 整团重新确认需求 | POST requirement/confirm | 200 |
| 14:14:40 | 改期+重新确认后 confirm-check | GET confirm-check | outOfRangeOrders=[],blockedByOutOfRange=false——越界户已回到区间内 |
| 14:14:54-14:15:43 | 房务补订房(H4 新增 1 间 → H5 调整到 3 间 → H7 确认 2026-12-16) | POST/PUT/POST room-plans 系列 | 均 200 |
| 14:15:45 | 补订房后 confirm-check | GET confirm-check | hotelReady=true,ready=true,blockedByOutOfRange=false,两日 dayReady 均为 true |
结论:本单要解决的产品问题(越界户此前无法靠改期机制回到团期区间)经真实网关全链路验证已打通——改期成功、越界名单清空、房务补齐后配房完成标志正确置真。
新增的 4 个拒绝错误码 587039-587042 本轮未触发(实测走的是成功路径),如实标注:
本轮测试服请求参数(departDate=2026-12-16)恰好是合法目标值(团期出发日本身),
未构造「提交非法日期」的对照请求,故 587039-587042 四个拒绝分支本轮无测试服实测证据;
四个错误码的响应内容取自源码 AdjustmentErrorCode.java 定义。
以下为 PR 正文自报的本机单测/变异测试验证,不是测试服抓包:
定向 6 类(AdjustmentServiceSubmitTest 78 例、AdjustmentServiceTest 10 例、AdjustmentSnapshotTest 43 例、
HouseAssignmentServiceTest 183 例含 Skipped 6、RedLineArchTest 12 例、HouseModuleBoundaryArchTest 5 例)
基线与复绿一致,MVN_EXIT=0
变异 11 个逐个变红:团期子订单判定、团期跳过个人价日历、587039/587040/587041/587042 四个拒绝分支、
团期出发日解析、改期后团期分支、分房删除计数、清除整团需求确认、单户 finalize 守卫顺序;还原后复绿
已 rebase 到 dev-v3 64c3f72a3(含工单 7441 PR-2 对 GroupBatchService/RequirementService 的改动)后定向复跑绿
网关:本次未新增/修改路径,沿用既有路由,取证均经网关(via: gateway)完成。
十、相关文档
- 关联 Issue: wx/HL#7325
- 关联 PR: wx/HL#7743(已合并 dev-v3)
- 改期 tab 完整契约背景: changelogs-v2/2026-06/27_4488_订单调整snapshot与submit契约重制-修改接口-管理后台.md
- 同一 Issue 下的另一改动(confirm-check 预检 + 旧 finalize 拒绝越界户,PR #7700,已合并): changelogs-v2/2026-09/15_7325_越界户预检列出末晚与旧finalize拒绝越界户-修改接口-管理后台.md
关联 / 联系人
链接
联系人
- 后端负责人: @wx