33 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 | 7441 | 团期整团确认改造接入车侧——预检/确认新增车侧字段,checkedResourceTypes 扩至用车,免车团确认不放行车侧 | admin | wx(GIT) | 修改接口 | deployed | verified | verified | mmg | a91d62f837637d54ce9814c8e4df64758e5e0419 | 2026-09-16 | 本单(#7441 PR-4)已由 PR #7778 squash 合入 dev-v3(合并提交 f0277a14f),测试服 order-v3 于 2026-09-16 01:21 部署该提交。confirm-check/confirm 两端点的核心场景(vehicleWaived 逃生口、ready 语义变化、809100/809103/809108/589533 收窄、重复确认幂等、PENDING_RECONFIRM 推进、CAS 回滚 809112)均经 hl-gateway 网关真实调用验证,见第八节。TRAVEL+TRANSFER 同户两类需求并存的场景(AC-13/14/21)因测试环境 TRANSFER 写侧全局开关关闭(809009,#7443 未上线的既有开关)未能验证,按源码核对列示,第八节已如实说明覆盖边界。mmg 2026-09-16 前端已交付:RequirementTab 预检区并列渲染 vehicleMissing 车侧缺失清单(detail 人话直显)+「本团整团免车」标识 + 预检文案两类缺失合并计数;确认成功提示补车侧放行条数(vehicleDispatchedCount 条数口径);直读 ready 不自算,809 段码走拦截器透 message;RequirementTab.spec +3 例 9/9,checkpoint 全绿。 | 2026-09-16 | dev-v3 |
order-v3: 团期整团确认改造接入车侧
存放目录:
changelogs-v2/{YYYY-MM}/(管理后台,二期 order-v3)服务: hl-order-service-v3 (端口 8083) PR: #7778(squash 合入 dev-v3,合并提交
f0277a14f,同批含 PR-2d/PR-2e,另有一份 changelog 覆盖) Issue: #7441 日期: 2026-09-16 影响范围: 团期需求页「整体确认前预检」GET .../requirement/confirm-check与「整体确认需求」POST .../requirement/confirm两个既有管理后台端点,响应新增车侧字段,confirm新增 4 个车侧错误码
⚠️ 关键变化(本版与上版行为不同,必读)
checkedResourceTypes从["HOTEL"]变为["HOTEL","VEHICLE"]——#7535当时明确承诺「扩到用车是另一张单」,本单就是那张单。若前端此前按「该数组恒为["HOTEL"]」写死判断,这里会翻转。ready的必要条件变多:改前ready = missing.isEmpty() && 阶段可确认;改后ready = missing.isEmpty() && vehicleMissing.isEmpty() && 阶段可确认。同一个团可能出现missing为空数组但ready=false的情况,此时必须读新增的vehicleMissing才能知道原因,不能再假设「missing空即可确认」。- 确认响应新增 7 个车侧字段,3 个旧字段语义保持不变(
dispatchedOrderIds/skippedOrderIds/dispatchedCount仍然只统计住宿,不含车)。 groupVehicleRequirementStatus不再恒为CONFIRMED:车侧已进入DISPATCHED或DONE的团再次确认时该字段回原状态(不倒退),这是正常态,不要渲染成异常。- 免车团(
vehicleWaived=true)整团确认不放行车侧:vehicleDispatchedCount=0,三个车侧 ID 列表为空数组,正式需求不推进——这不是漏放,是设计如此。 589533触发条件收窄为「只管住宿」:改前住宿或车任一缺失都可能报589533;本单起车侧缺失改抛 809 段专属码,589533的{0}只统计住宿缺失户数。- 背景信息(非本单改动,供理解字段含义):团期管理员可在需求页对整团声明「本团无需用车」(
POST /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/waive,已上线)或撤销声明(POST .../vehicle-requirement/withdraw,已上线)。本单不改这两个端点的契约,只是预检/确认从此会读取它们产生的结果。声明免车曾经在「已有分组仍要声明免车」时报错码809113;该码自#7441PR-3(已合并 dev-v3)起停用不再抛出(改为整份换版为免车版本),本单起进一步不出现vehicleMissing意义上的相关缺失项,前端若还留有809113专属提示文案,可以确认无需再触发但不必删除(错误码本身仍占位保留)。
一、背景
#7210 交付的「整体确认」原本只校验、只放行住宿:预检 GET .../requirement/confirm-check 只看住宿缺失清单,确认 POST .../requirement/confirm 只推进住宿需求。团期正式车需求(分组 × 逐日 × 成员,由 PUT/GET .../vehicle-requirement 两个已上线端点维护)与「本团无需用车」声明(waive/withdraw,已上线)此前完全不接入这两个端点——车侧需要逐单在订单详情页另行放行,管理员在团期需求页看不到车侧是否齐备。
本单(#7441 PR-4)让这两个已有端点在住宿之外对称接入车侧:预检同时给出车侧缺失清单,确认在住宿放行完成后,如果不是免车团,再推进正式车需求并批量放行在团户的车需求。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 整体确认前的缺失预检 | GET | /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check |
响应新增字段 | 新增 5 个顶层字段 + 车侧缺失清单;ready/checkedResourceTypes 语义变化 |
| 2 | 整体确认需求(放行住宿+车) | POST | /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm |
响应新增字段 + 新增错误码 | 车侧校验接入;免车团跳过车侧放行;新增 7 个响应字段 + 4 个车侧错误码;589533 收窄为只管住宿 |
三、接口详情
1. 整体确认前的缺失预检 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check
VO: 无请求体 → Result<GroupBatchRequirementCheckRespVO>
使用场景
团期需求页进入「查看需求」Tab 时调用,以及点击「确认」按钮前调用,用于据 ready 置灰按钮、据 missing/vehicleMissing 展示缺哪些户/哪些车侧问题。只读,零副作用,可任意重复调用。本单起该端点同时覆盖住宿与车侧两类资源。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | 是 | - | 团期聚合主键(不变) |
(无查询参数、无请求体,本单未改动。)
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(序列化为 String) | 团期聚合主键(不变) |
| batchStatus | String | 团期当前状态码(不变) |
| batchStatusName | String | 团期当前状态中文名(不变) |
| ready | Boolean | 语义变化:是否可以整体确认,改为 missing 为空 且 vehicleMissing 为空 且团期处于可确认阶段 |
| missing | List | 改名为「住宿缺失清单」(字段名不变,含义收窄为只描述住宿),结构不变 |
| checkedResourceTypes | List | 取值变化:恒为 ["HOTEL","VEHICLE"](改前恒为 ["HOTEL"]),服务端常量,非按团期配置动态算出 |
| 🆕 vehicleWaived | Boolean | 整团都不需要车时为 true,此时车侧校验整体跳过、vehicleMissing 恒为空数组。这是合法逃生口,不是异常 |
| 🆕 vehicleMissing | List | 车侧缺失清单(按校验顺序全部列出,不按户合并);vehicleWaived=true 时为空数组 |
| 🆕 groupVehicleRequirementId | Long(序列化为 String) | 当前活跃正式用车需求主键;无活跃正式需求时为 null |
| 🆕 groupVehicleRequirementStatus | String | 当前活跃正式用车需求状态;无则 null。取值 DRAFT/CONFIRMED/DISPATCHED/DONE/PENDING_RECONFIRM——DISPATCHED 与 DONE 同样属于预检可通过的正常状态,不要渲染成异常 |
| 🆕 groupVehicleRequirementVersion | Integer | 当前活跃正式用车需求版本号;无则 null |
missing[](MissingItem,结构不变,仅补充在本节自包含):
| 字段 | 类型 | 说明 |
|---|---|---|
| orderId | Long(序列化为 String) | 子订单 ID |
| orderNo | String | 子订单号 |
| customerName | String | 客户姓名 |
| consultantId | String | 定制师 adminId |
| consultantName | String | 定制师姓名快照 |
| reason | String | NOT_SUBMITTED/ROOM_CATEGORY_MISSING/INVALID_REQUIREMENT/NIGHTS_MISMATCH/DAY_NUMBER_INVALID |
| reasonName | String | 缺失原因中文名 |
| dayNumber | Integer | 第几晚(仅 ROOM_CATEGORY_MISSING 有值) |
| segmentIndex | Integer | 第几段(仅 ROOM_CATEGORY_MISSING 有值) |
| expectedNights | Integer | 应住晚数(仅 NIGHTS_MISMATCH/DAY_NUMBER_INVALID 有值) |
| actualNights | Integer | 实际填写晚数(仅 NIGHTS_MISMATCH/DAY_NUMBER_INVALID 有值) |
🆕 vehicleMissing[](VehicleMissingItem):
| 字段 | 类型 | 说明 |
|---|---|---|
| reason | String | 取值见「六.5」,与 809 段错误码/809007 一一对应 |
| groupCode | String | 涉及的乘车分组编码;无分组维度时为 null |
| tripDate | LocalDate | 涉及的日期;无日期维度时为 null |
| orderId | Long(序列化为 String) | 涉及的子订单 ID;无订单维度时为 null |
| orderNo | String | 子订单号快照 |
| detail | String | 人话描述,与整团确认时抛出的错误报文逐字相同,可直接展示 |
请求示例
GET /v3/admin/order/group-batch/1867000000001/requirement/confirm-check HTTP/1.1
Authorization: Bearer {token}
(无请求体,仅 Path 参数 groupBatchId。)
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"groupBatchId": "1867000000001",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusName": "资源准备中",
"ready": false,
"missing": [],
"checkedResourceTypes": ["HOTEL", "VEHICLE"],
"vehicleWaived": false,
"vehicleMissing": [
{
"reason": "ORDER_DAY_UNCOVERED",
"groupCode": null,
"tripDate": null,
"orderId": "60123456789001",
"orderNo": "HL2606010001",
"detail": "子订单 60123456789001 的 2026-09-13 没有被任何乘车分组覆盖"
}
],
"groupVehicleRequirementId": "1868000000001",
"groupVehicleRequirementStatus": "DRAFT",
"groupVehicleRequirementVersion": 3
}
}
免车团示例(vehicleWaived=true):
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"groupBatchId": "1867000000002",
"batchStatus": "RESOURCE_PREPARING",
"batchStatusName": "资源准备中",
"ready": true,
"missing": [],
"checkedResourceTypes": ["HOTEL", "VEHICLE"],
"vehicleWaived": true,
"vehicleMissing": [],
"groupVehicleRequirementId": "1868000000005",
"groupVehicleRequirementStatus": "CONFIRMED",
"groupVehicleRequirementVersion": 1
}
}
空数据 / 降级响应
团期尚未提交任何正式车需求(未编辑过 PUT .../vehicle-requirement、也未 waive)时,车侧三个身份字段(groupVehicleRequirementId/Status/Version)均为 null,vehicleMissing 按住宿同款缺失校验给出实际内容(不是空数组,除非该团确实零缺失或已免车)。本端点全程同步内存/DB 读取,不经 Feign/MQ,不产生降级分支。
{ "code": 200, "success": true, "data": { "groupVehicleRequirementId": null, "groupVehicleRequirementStatus": null, "groupVehicleRequirementVersion": null, "vehicleMissing": [] } }
错误响应
沿用既有码,本单未新增:
{
"code": 589500,
"message": "团期不存在",
"success": false,
"data": null
}
业务边界
- 判权沿用既有 group-batch:demand:confirm(GroupBatchPermissionGuard.PERMISSION_DEMAND_CONFIRM),本单未改。
- 车侧校验集合口径与保存草稿(PUT .../vehicle-requirement)、整团确认(见下条)完全共用一份校验内核,三处同一份数据得到同一个结论——本端点的 vehicleMissing 为空当且仅当真去点确认不会报车侧错误码(并发写入除外)。
- vehicleWaived=true 时车侧校验整体跳过,与是否有历史违规无关。
- 老数据兼容:本单不改任何已有字段的类型或序列化方式,存量前端若忽略新字段仍可正常渲染住宿部分;但 checkedResourceTypes 与 ready 的取值/语义已变,见「⚠️ 关键变化」。
2. 整体确认需求(放行住宿+车) POST /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm
VO: 无请求体 → Result<GroupBatchRequirementConfirmRespVO>
使用场景
团期需求页点击「确认」按钮时调用。改前只校验并放行住宿;本单起在住宿放行成功之后,非免车团额外推进正式车需求并批量放行在团户的车需求(行程用车 TRAVEL + 接送机 TRANSFER 两类)。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | 是 | - | 团期聚合主键(不变) |
(无请求体,本单未改动。)
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| groupBatchId | Long(序列化为 String) | 团期聚合主键(不变) |
| requirementConfirmed | Boolean | 团期需求整体确认标记,成功后恒 true(不变) |
| dispatchedOrderIds | List(String) | 语义不变:仍只统计住宿,本次放行的住宿子订单 |
| skippedOrderIds | List(String) | 语义不变:仍只统计住宿 |
| dispatchedCount | Integer | 语义不变:仍只统计住宿(= dispatchedOrderIds.size()) |
| 🆕 vehicleDispatchedOrderIds | List(String) | 本次由「待审核」放行的【行程用车 TRAVEL】需求所属子订单 |
| 🆕 transferDispatchedOrderIds | List(String) | 本次由「待审核」放行的【接送机 TRANSFER】需求所属子订单 |
| 🆕 vehicleSkippedOrderIds | List(String) | 车侧本次未动的子订单(两类合并去重;该户该类车需求已非「待审核」)。整团免车时为空数组 |
| 🆕 vehicleDispatchedCount | Integer | 车侧本次放行的需求条数 = vehicleDispatchedOrderIds.size() + transferDispatchedOrderIds.size()。⚠️ 是条数不是户数,一户两类都放行计 2 |
| 🆕 groupVehicleRequirementId | Long(序列化为 String) | 本次确认所对应的正式车需求主键;整团免车且无正式需求(存量判据)时为 null |
| 🆕 groupVehicleRequirementStatus | String | 确认后正式车需求的实际状态,不是恒为 CONFIRMED:源状态 DRAFT/PENDING_RECONFIRM → 回 CONFIRMED;CONFIRMED 保持 CONFIRMED;DISPATCHED/DONE 回原值(车侧不动、状态不倒退,属正常态)。免车且无正式需求时为 null |
| 🆕 groupVehicleRequirementVersion | Integer | 确认后正式车需求版本号(推进到 CONFIRMED 时已 +1,原样返回时不变);免车且无正式需求时为 null |
请求示例
POST /v3/admin/order/group-batch/1867000000001/requirement/confirm HTTP/1.1
Authorization: Bearer {token}
(无请求体,仅 Path 参数 groupBatchId。)
响应示例
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"groupBatchId": "1867000000001",
"requirementConfirmed": true,
"dispatchedOrderIds": ["60123456789001", "60123456789002", "60123456789003"],
"skippedOrderIds": [],
"dispatchedCount": 3,
"vehicleDispatchedOrderIds": ["60123456789001", "60123456789002", "60123456789003", "60123456789004", "60123456789005"],
"transferDispatchedOrderIds": [],
"vehicleSkippedOrderIds": [],
"vehicleDispatchedCount": 5,
"groupVehicleRequirementId": "1868000000001",
"groupVehicleRequirementStatus": "CONFIRMED",
"groupVehicleRequirementVersion": 2
}
}
免车团响应示例(vehicleDispatchedCount=0):
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"groupBatchId": "1867000000002",
"requirementConfirmed": true,
"dispatchedOrderIds": ["60123456789006"],
"skippedOrderIds": [],
"dispatchedCount": 1,
"vehicleDispatchedOrderIds": [],
"transferDispatchedOrderIds": [],
"vehicleSkippedOrderIds": [],
"vehicleDispatchedCount": 0,
"groupVehicleRequirementId": "1868000000005",
"groupVehicleRequirementStatus": "CONFIRMED",
"groupVehicleRequirementVersion": 1
}
}
空数据 / 降级响应
不存在空态:本端点是写操作,要么全部成功返回上述结构,要么整个事务回滚并抛错误码。没有部分成功或静默降级的分支。
{ "code": 200, "success": true, "data": { "vehicleDispatchedOrderIds": [], "transferDispatchedOrderIds": [], "vehicleSkippedOrderIds": [], "vehicleDispatchedCount": 0 } }
错误响应
| 码 | 符号 | 触发 | 本单 |
|---|---|---|---|
| 589501 | GROUP_BATCH_STATUS_INVALID | 团期非可确认阶段 | 不变 |
| 589533 | GROUP_BATCH_REQUIREMENT_INCOMPLETE | 语义收窄:只在住宿缺失时抛,{0} 仍是住宿缺失户数 | 收窄 |
| 🆕 809100 | GROUP_VEHICLE_REQUIREMENT_NOT_FOUND | 有在团需车户却无正式车需求 | 本单起会抛 |
| 🆕 809101 | GROUP_VEHICLE_REQUIREMENT_STATUS_INVALID | 正式车需求状态不在 {DRAFT,CONFIRMED,DISPATCHED,DONE,PENDING_RECONFIRM},或推进 CAS 落空 | 本单起会抛 |
| 🆕 809103-809110 | 车侧八条逐日/成员/人数校验 | 见「六.5」 | 本单起会抛 |
| 🆕 809007 | TRANSFER_SERVICE_DATES_NOT_BACKFILLED | 待放行的接送机需求未回填服务日;{0} 为该需求主键(数字,非字符串) | 本单起会抛 |
| 🆕 809112 | GROUP_VEHICLE_DISPATCH_CAS_FAILED | 放行某户车需求时并发冲突(CAS 落空),整团事务回滚,零写入 | 本单起会抛 |
{
"code": 589533,
"message": "仍有 2 户未提交需求或需求不完整,无法整体确认,请先查看缺失清单",
"success": false,
"data": null
}
车侧违规示例(该团抛第一条命中的违规,取决于哪条违规先被发现):
{
"code": 809109,
"message": "子订单 60123456789001 的 2026-09-13 没有被任何乘车分组覆盖",
"success": false,
"data": null
}
业务边界
- 顺序不可调换:① 阶段守卫(589501)→ ② 住宿缺失校验(589533,零写入)→ ③ 车侧校验(免车团整体跳过,否则抛第一条违规,零写入)→ ④ 置团级标记 + 写团级时间线 → ⑤ 逐户住宿放行 → ⑥ 非免车团:推进正式车需求 → ⑦ 非免车团:逐户放行车需求两类 → ⑧ 事务提交后异步通知房务。全部在同一个事务里,任一步失败整团零写入(809112 整团回滚即靠这一点)。
- 住宿排在车侧之前:两边都缺时仍报 589533,与改造前一致;只有住宿齐备、车侧有问题时才会看到 809 段码。
- 免车团(vehicleWaived=true)跳过 ⑥⑦ 两步:正式需求不推进(版本不 +1)、逐户车需求不放行(在团户残留的待审核车需求本次不动,需要就走逐单放行入口)。
- 809007 排在放行动作之前抛:预检阶段(上一条端点)已经把这类需求列进 vehicleMissing,ready=true 时不会再遇到本码,两者结构性一致。
- 重复确认不失败:正式车需求已是 CONFIRMED 时重复确认走幂等成功,不抛 809101;已放行的车需求本次计入 vehicleSkippedOrderIds 而不是报错——与住宿侧口径一致。
- 只改住宿的再次确认必须成功:车侧已 DISPATCHED/DONE、只有住宿需求被打回重提时,再次点整团确认——正式车需求保持原状态不倒退,车侧逐户按「已放行」计入 vehicleSkippedOrderIds(vehicleDispatchedCount=0),住宿正常放行。改前这一场景会被状态白名单直接拒掉,团再也确认不了;本单起这条路走通。
- 本端点不取车侧专属锁:与住宿放行共用团期需求锁,车侧两步不额外加锁(避免自锁)。
- 判权沿用既有 group-batch:demand:confirm,本单未改。
四、契约约束与正确调用方式
正确 / 错误 调用结果对照
| 场景 | 结果 |
|---|---|
| 预检 ready=true 后立即点确认,期间无其他人并发改动(正确) | confirm 成功,不因校验类错误码失败(CAS 类失败如 809101/809112 不在此等价关系内) |
| 前端只判断 missing.isEmpty() 就以为可以确认(错误) | 车侧仍可能缺失,点确认会报 809 段码;必须同时判 vehicleMissing.isEmpty()(或直接看 ready) |
| 前端按「checkedResourceTypes 恒为 ["HOTEL"]」写死判断(错误) | 本单起恒为 ["HOTEL","VEHICLE"],写死判断会得出错误结论 |
| 前端按「groupVehicleRequirementStatus 恒为 CONFIRMED」渲染确认结果(错误) | 车侧已 DISPATCHED/DONE 时该字段回原值,不是 CONFIRMED;按恒等判断会误判为异常 |
切换状态时的必要动作
前端渲染「整体确认」按钮的可用性时,必须把 vehicleMissing.isEmpty() 并入判断(或直接读 ready,不要自己用 missing.isEmpty() 重新计算);确认成功后的提示文案不能只读旧三个字段(否则车侧放行结果对用户不可见)。
五、数据库行为
预检端点全程只读,不产生任何写入。确认端点在同一个事务里,除既有的「置团级确认标记 + 住宿放行」外,本单额外做两件事:①非免车团把当前活跃正式车需求的状态从「待确认」推进为「已确认」(若已经是「已确认」及之后的状态则保持不变,不会倒退);②非免车团把在团户的行程用车与接送机需求从「待审核」批量放行为「待处理」。任一步失败(含并发写入冲突)都会让本次确认动作(含住宿放行)整体回滚,不会出现部分成功。
六、边界行为
- 未登录 → 401(网关拦截)
- 无权限 → 沿用既有 group-batch:demand:confirm 判权(未改)
- 团期不存在 → 589500(未改)
- 团期非可确认阶段 → 589501(未改)
- 住宿缺失 → 589533(收窄为只管住宿)
- 车侧缺失(非免车团)→ 809 段码,见「三、2」错误响应表
- 免车团 → 车侧校验/放行整体跳过,不产生任何车侧相关错误
- 老数据兼容:存量团期第一次读取本端点时,若从未编辑过车需求,groupVehicleRequirementId/Status/Version 均为 null,不异常
六.5、枚举
vehicleMissing[].reason(服务端内部校验原因码,无独立 Java 枚举类,值见下表)
所属字段: vehicleMissing[].reason | 类型: String
| 值 | 对应错误码 | 说明 |
|---|---|---|
| GROUP_REQUIREMENT_NOT_FOUND | 809100 | 有在团需车户却无正式车需求 |
| GROUP_REQUIREMENT_STATUS_INVALID | 809101 | 正式车需求状态不在合法集合 |
| NO_GROUP | 809103 | 本团存在需要用车的子订单,却零乘车分组 |
| GROUP_CODE_INVALID | 809104 | 乘车分组重复或试图改名 |
| DAY_OUT_OF_GROUP_RANGE | 809105 | 分组逐日行不在本组服务日范围内或重复提交 |
| DAY_GAP_IN_GROUP_RANGE | 809106 | 分组缺少某日的用车人数 |
| MEMBER_FOREIGN_ORDER | 809107 | 子订单不属于本团期,不能作为乘车成员 |
| MEMBER_DUPLICATE_DAY | 809108 | 子订单在同一日同时属于两个分组 |
| ORDER_DAY_UNCOVERED | 809109 | 子订单某日没有被任何乘车分组覆盖 |
| HEADCOUNT_LESS_THAN_MEMBERS | 809110 | 分组当日用车人数小于当日成员户数 |
| 🆕 TRANSFER_SERVICE_DATES_NOT_BACKFILLED | 809007 | 待放行的接送机需求未回填服务日;只带 orderId,groupCode/tripDate 为 null;处置是先回填服务日再确认;复用 #7439 既有码,非本单新增 |
groupVehicleRequirementStatus(com.hulalv.order.groupbatch.enums.GroupVehicleRequirementStatus)
所属字段: confirm-check/confirm 响应的 groupVehicleRequirementStatus | 类型: String
| 值 | 中文 | 说明 |
|---|---|---|
| DRAFT | 草稿 | 尚未提交审核 |
| CONFIRMED | 已确认 | 整团确认推进后的常见终态 |
| DISPATCHED | 已放行车务 | 团车已开始配车;确认时保持不动,不倒退 |
| DONE | 已完成 | 团车配完;确认时保持不动,不倒退 |
| PENDING_RECONFIRM | 待重确认 | 再次确认时可推进到 CONFIRMED |
六.6、修改前后对比
字段级对比
| 字段 | 改前 | 改后 |
|---|---|---|
| confirm-check.checkedResourceTypes | 恒 ["HOTEL"] | 恒 ["HOTEL","VEHICLE"] |
| confirm-check.ready | missing.isEmpty() && 阶段可确认 | missing.isEmpty() && vehicleMissing.isEmpty() && 阶段可确认 |
| confirm-check 车侧字段 | 不存在 | 新增 vehicleWaived/vehicleMissing/groupVehicleRequirementId/Status/Version 5 个 |
| confirm.dispatchedOrderIds/skippedOrderIds/dispatchedCount | 语义为「住宿」 | 语义不变,仍只统计住宿 |
| confirm 车侧字段 | 不存在 | 新增 7 个:见出参字段表 |
| 589533 触发条件 | 住宿或车任一缺失 | 只在住宿缺失时触发 |
行为级对比
| 行为 | 改前 | 改后 |
|---|---|---|
| 团期需求页点「确认」,住宿齐、车不齐 | 200 成功(车侧无感) | 809 段码阻断(非免车团) |
| 车侧已 DISPATCHED/DONE,住宿被打回重提后再次确认 | 809101 阻断,团再也确认不了 | 200 成功,车侧保持原状态、住宿正常放行 |
| 免车团点「确认」 | (本端点改造前免车概念不影响本端点) | 200 成功,车侧三个 ID 列表为空、vehicleDispatchedCount=0 |
| 预检时车侧有缺失 | ready 不受车侧影响(预检本不检查车) | ready=false,需读 vehicleMissing |
六.7、影响评估
- 是否破坏向后兼容: 是。此前 ready=true(只看住宿)的部分团在本单合并部署后,若车侧未齐备会变成 ready=false;589533 触发条件收窄,改前依赖它同时报告车缺失的前端提示会失真。
- 前端是否必须同步上线: 是。按「⚠️ 关键变化」逐条改:checkedResourceTypes 判断、ready/vehicleMissing 联合判断、确认响应新增字段的展示、groupVehicleRequirementStatus 不再恒 CONFIRMED 的容错。
- 前端 workaround 清理点: 无(新增字段与语义收紧,非清理旧逻辑)。
七、不影响范围
- 仅影响:
GET .../requirement/confirm-check与POST .../requirement/confirm两个既有端点的响应体与confirm的错误码集合。 - 零影响:
- 路径、Path 参数、请求体(均无请求体)——完全不变。
- 判权码 group-batch:demand:confirm——未改。
- PUT/GET .../vehicle-requirement、POST .../vehicle-requirement/withdraw、POST .../vehicle-requirement/waive 四个已上线端点自身的契约——本单不改,只是被读取结果。
- POST .../requirement/reject(按户打回)、GET .../requirement-summary(全团需求汇总)——本单未改,按户打回逐户需求的语义完全不动。
- POST /v3/admin/order/{id}/vehicle-requirement/dispatch(逐单放行)——保留,与本单整团路径共用同一份副作用实现,未新增未删除。
- hl-common-*、hl-fleet-service、hl-gateway 路由——本单只改 hl-order-service-v3,/v3/admin/** 路由沿用既有通配,未新增路由配置。
八、测试环境已验证
取证环境:order-v3 = dev-v3 f0277a14f(2026-09-16 01:21 部署,含本单 PR-4 全部改动),经 hl-gateway 网关真实调用,见工单 #7441 验收评论 54924(AC-8/9/10/11/12/15/18)与 54939(AC-16)。
GET .../requirement/confirm-check:
- 免车逃生口(
vehicleWaived=true):ready=true、missing=[]、vehicleMissing=[],车侧三个身份字段均为null(团 2099918391610314754)。 - 车侧正式需求缺失(
vehicleWaived=false):vehicleMissing=[{"reason":"GROUP_REQUIREMENT_NOT_FOUND","detail":"团期 2099918391610314754 尚未形成正式用车需求"}]。 ready语义变化:房齐备、车零分组的团返回ready=false、missing=[]、vehicleMissing=[{"reason":"NO_GROUP",...}]——「missing空但ready=false」的形态经真实调用坐实。- 同日同户重复归属(数据经 SQL 直接向
order_group_vehicle_group/order_group_vehicle_group_day造重叠行,读侧取证):vehicleMissing=[{"reason":"MEMBER_DUPLICATE_DAY","groupCode":"GB","tripDate":"2026-10-24","orderId":"2099919145398046721","orderNo":"HL20260916015153509"}]。 - 房侧缺失清单:
missing含两条真实户(orderId2099918640269627394 / 2099918650218516481,reason=NOT_SUBMITTED)。
POST .../requirement/confirm:
- 免车团确认成功:
code=200、vehicleDispatchedCount=0、groupVehicleRequirementId=null。 - 车侧需求缺失:
code=809100,message="团期 2099918596187598850 尚未形成正式用车需求"。 - 房齐车零分组:
code=809103,message="本团存在需要用车的子订单,至少要提交一个乘车分组"。 - 房缺 2 户、车侧已免车:
code=589533,message="仍有 2 户未提交需求或需求不完整,无法整体确认,请先查看缺失清单"({0}=2坐实)。 - 同日同户重复归属:三入口(
PUT/confirm-check/confirm)均报code=809108,message="子订单 2099919145398046721 在 2026-10-24 同时属于分组 GA、GB,同一户同一日只能属于一个分组"——PUT由业务接口直接触发重叠数据被拒;confirm-check/confirm因PUT会在写入前就拒绝重叠数据、结构上无法经业务路径把该状态存进库,按 SQL 造重叠行后走读侧验证。 - 重复确认幂等:单户团 T0
confirm成功(vehicleDispatchedOrderIds=["2099919607505596417"]、vehicleDispatchedCount=1、groupVehicleRequirementStatus=CONFIRMED、version=2),间隔 >5 秒后 T1 再次confirm成功且不抛 809101(vehicleSkippedOrderIds=["2099919607505596417"]、vehicleDispatchedCount=0,状态与版本不变)。 PENDING_RECONFIRM → CONFIRMED:正式需求经 SQL 置为PENDING_RECONFIRM后再次confirm,成功且groupVehicleRequirementStatus=CONFIRMED(version=3)。- CAS 落空整团回滚:并发导致放行第 3 户车需求时 CAS 落空,抛
809112,前 2 户车需求状态、房侧放行结果、正式需求状态、团期确认标记全部回滚,零写入(评论 54939)。
仅代码核对,未经该场景网关验证:AC-13/14/21 要求的「同一户同时提交 TRAVEL + TRANSFER 两类需求、confirm 一次响应内房 3 户 + 车 5 条同时出现」这一组合场景,因测试环境 TRANSFER 写侧全局开关关闭(既有错误码 809009,#7443 派车侧尚未上线的独立开关,与本单代码无关)未能取得;待该开关在测试环境临时打开后补测,结果回写工单 #7441 验收评论。已取得的替代证据:全员仅提交 TRAVEL 需求的团确认成功,vehicleDispatchedOrderIds 含 3 户、transferDispatchedOrderIds=[]、vehicleDispatchedCount=3——证明 TRAVEL 单类路径工作正常,但未覆盖两类需求同户并存、以及打回其中一类后另一类不受影响(POST .../vehicle-requirement/reject?kind=TRANSFER)的场景;相关字段的类型与计算口径已按源码核对(见「出参字段表」与「六.6」),这部分示例响应仍是按源码拼装的合理构造,不是该组合场景的实测原文。
十、相关文档
- 关联 Issue: wx/HL#7441
- 关联 PR: #7778(squash 合入 dev-v3,合并提交
f0277a14f) - 前置依赖:
#7535(首次引入 checkedResourceTypes,本单是其承诺的「扩到用车」那张单)、#7210(confirm-check/confirm 首次交付,只管住宿)、#7441PR-1/PR-2/PR-2b/PR-2c/PR-3(团期正式车需求声明、整团免车、团车完成回写、结算闸,均已合并 dev-v3,本单依赖它们提供的数据但不改它们的契约) - 关联文档:本单合并部署后的户级/团级联动效果(确认行程清单、待办、团期详情看板、物资门等)见同批另一份 changelog(
#7441PR-2d/PR-2e,同一个 PR #7778) - 验收口径边界:页面完成状态单独跟踪(前端归 mmg),不计入 #7441 验收;#7441 验收范围 = API 契约 + 状态流转 + 占用账本 + changelog 交接件。