文件
hl-api-changelog/changelogs-v2/2026-09/20_8023_需求汇总与确认预检不再只认needs_hotel标记位-修改接口-管理后台.md
T

20 KiB
原始文件 Blame 文件历史

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 8023 需求汇总与确认预检不再只认 needs_hotel 标记位 + 提交住宿需求时就地纠正该标记 admin jw(GIT) 修改接口 deployed verified verified mmg 9a14ad866b3ef6ac9acb0ca9ab9e9f0fe98f6559 2026-09-20 后端已合并 dev-v3(df66ec357)并部署 TEST,网关实测 AC-1~AC-8 全通过。一处口径放宽 + 一个纯新增出参 + 一处写侧副作用。口径:全团需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary 的 dailyRoomBreakdown 与整体确认预检 GET .../requirement/confirm-check,此前都只认订单上的 needs_hotel 标记位,导致「标记说不需要住宿、定制师却已提交完整需求」的户被整户静默丢弃——间数不进汇总(页面用房表空白)、确认时也不放行给房务(需求填了没人配房);现在计入条件改为「标记为真 或 已提交有效需求」,打回态仍不计。新增出参 hotelFlagMismatchOrderCount 把这种不一致显式暴露。写侧:PUT /v3/admin/order/{id}/hotel-requirement 提交成功后,若该单 needs_hotel 不为真则就地置 1(单向 0→1,同事务,已为真时不写)——该标记原先只在创单时按产品有没有配酒店派生一次、之后全仓无写通道,存量错单改不回来。既有字段一个没删没改,入参与路径不变。 前端实证维持 not_required(mmg 2026-09-20):requirement-summary/dailyRoomBreakdown/hotelNeededOrderCount/hotelFlagMismatchOrderCount 全仓零命中(汇总端点未接入,同 #7925/#7937 结论);confirm-check 已消费(orderV2GroupBatch.js)但出参结构不变,ready/missing 直渲自动受益;hotel-requirement 标记纠正为服务端同事务副作用、响应不变,零感知。 2026-09-20 前端接入(mmg):「用房 · 汇总」建页随 hl-admin v2.1 交付——requirement-summary 经 getGroupRequirementSummary 接入「查看需求」页 RoomSummarySection:户数条(在团/需订房/已提交)+不一致只提示不扣减+Day N|酒店|房型|所需间数扁平表;stayDate null 按 Day N、hotelName null 显「未知酒店」不隐藏行、roomCategoryName null 回落编码、全天合计直读 rooms[] 禁跨酒店累加、hotelId null 组间数不丢;整团确认/按户打回后自动重拉。定向 Vitest 17/17,checkpoint 全绿。 2026-09-20 dev-v3

order-v3: 需求汇总/预检不再只认 needs_hotel,提交需求时就地纠正该标记

服务: hl-order-service-v3 (端口 8086) PR: #8028 Issue: #8023 日期: 2026-09-20 影响范围: 管理后台「团期订单 → 查看需求」页的用房汇总、整体确认预检;定制师提交住宿需求的副作用


⚠️ 关键变化

  • 不再只认标记位:汇总与预检的计入条件从「needs_hotel=1」放宽为「标记为真 或 已提交有效需求」。需求是事实,标记只是创单时的推测,两者冲突时以事实为准。
  • 新增出参 hotelFlagMismatchOrderCount:「标记为假却已提交有效需求」的户数,把这种不一致显式暴露出来,不再静默吞掉。
  • hotelNeededOrderCount 口径同步放宽:改为「标记为真的户 ∪ 已提交有效需求的户」,保证 hotelSubmittedOrderCount ≤ hotelNeededOrderCount 恒成立。
  • 提交住宿需求会就地纠正标记:needs_hotel 不为真时置 1,单向、同事务、已为真时不写。
  • 打回态仍不计:#7925 立的那条判定原样保留,不受本次放宽影响。

一、背景

needs_hotel 只在创建订单那一刻由「产品有没有配酒店 / 有没有默认房数」派生一次,之后全仓没有任何写通道(OrderCreateTransactionExecutor.deriveNeedsHotel)。产品当时没配酒店、后来补配了,或定制师按客户实际情况提了住宿需求,这个标记都改不回来。

而汇总与预检都按它筛户,于是出现了自相矛盾的一屏:子订单列表显示该户「待审核」,需求汇总却说这个团「0 户需要住宿」,用房表全空。

TEST 实证(团期 jw测试1期):三户 needs_hotel=0,其中一户已提交 6 晚 12 间的 PENDING_REVIEW 需求,改前 dailyRoomBreakdown 为空数组。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 全团需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary 修改 计入户口径放宽为「标记为真或已提交有效需求」;新增 1 个出参
2 整体确认预检 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check 修改 取户口径同步放宽,字段结构不变
3 提交住宿需求 PUT /v3/admin/order/{id}/hotel-requirement 修改 新增副作用:提交成功后就地纠正 needs_hotel

三、接口详情

1. 全团需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary

VO: Result<GroupRequirementSummaryRespVO>

使用场景

团期详情「查看需求」页顶部的「用房 · 汇总」表:全团逐日要订几间、什么房型,运营据此向酒店报数。

入参

本次入参不变。

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ 团期 ID 团期不存在返回 589500

出参

字段 类型 说明
activeOrderCount Integer 在团户数(不变)
hotelRequirementCount Integer 有效房需求条数(不变;不看标记位也不看打回状态)
hotelNeededOrderCount Integer 口径放宽:标记为真的户 ∪ 已提交有效需求的户
hotelSubmittedOrderCount Integer 口径放宽:不再要求标记为真,只看需求是否有效
hotelFlagMismatchOrderCount Integer 新增。标记不为真却已提交有效需求的户数,恒 ≥0
vehicleRequirementCount Integer 有效用车需求条数(不变)
dailyRoomBreakdown List 逐日房间明细(计入户集合本次放宽)
dailyRoomBreakdown[].dayNumber Integer 第几天(不变)
dailyRoomBreakdown[].rooms[].roomCategory String 房型编码(不变)
dailyRoomBreakdown[].rooms[].roomCategoryName String 房型中文名(不变,#7925 引入)
dailyRoomBreakdown[].rooms[].totalRoomCount Integer 该天该房型合计(不变,数值因放宽可能变大)
vehicleSeatSummary List 车型座位合计(不变)
orderSpecialTags List 各户特殊需求标签(不变)

请求示例

GET /v3/admin/order/group-batch/2101506167098511362/requirement-summary
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "activeOrderCount": 3,
    "hotelRequirementCount": 1,
    "hotelNeededOrderCount": 1,
    "hotelSubmittedOrderCount": 1,
    "hotelFlagMismatchOrderCount": 1,
    "vehicleRequirementCount": 0,
    "dailyRoomBreakdown": [
      {"dayNumber": 1, "rooms": [{"roomCategory": "KING", "roomCategoryName": "豪华大床", "totalRoomCount": 2}]}
    ],
    "vehicleSeatSummary": [],
    "orderSpecialTags": []
  },
  "traceId": null,
  "success": true
}

空数据 / 降级响应

全团无有效需求且无标记为真的户时,三个户数均为 0、dailyRoomBreakdown 为 [](不是 null),hotelFlagMismatchOrderCount 为 0,且不调房型字典。房型字典不可用时只有 roomCategoryName 为 null,编码与房间数照常返回,接口不报错。

错误响应

{ "code": 589507, "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)", "data": null, "success": false }
code 触发条件
589507 当前角色没有 group-batch:view(本次不变)
589500 团期不存在(本次不变)
401 未登录(网关拦截)

本次无新增错误码。

业务边界

  • 计入的户:标记为真 或 已提交有效需求(有效 = PENDING_REVIEW / PENDING / PROCESSING / DONE)。
  • 打回态仍不计:退回定制师、退回管理员两种状态不是「有效需求」,不能靠它把户拉进计入集合。
  • 客户自订晚整晚跳过,不进采购分母(不变)。
  • 户范围仍是「在团」口径(含已完成的户),与预检刻意不同(#7316)。
  • hotelFlagMismatchOrderCount 仅用于提示与订正,不要用它去扣减间数——那批户的间数已经正常计入。

2. 整体确认预检 GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check

VO: Result<GroupBatchRequirementCheckRespVO>

使用场景

团期管理员点「确认需求」之前的缺失预检;确认时用同一份判定决定放行哪些户的需求给房务。

入参

本次入参不变。

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ 团期 ID 团期不存在返回 589500

出参

字段结构不变(ready / missing[] / checkedResourceTypes 等一个没动)。变的是取户口径。

字段 类型 说明
ready Boolean 是否可确认(不变)
missing List 缺失清单(结构不变;新增「标记为假但已提交」的户参与判定后,其缺项会如实出现在这里)
checkedResourceTypes List 本次检查的资源类型(不变)

请求示例

GET /v3/admin/order/group-batch/2101506167098511362/requirement/confirm-check
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "groupBatchId": "2101506167098511362",
    "batchStatus": "RECRUITING",
    "batchStatusName": "招募中",
    "ready": false,
    "missing": [],
    "checkedResourceTypes": ["HOTEL", "VEHICLE"]
  },
  "traceId": null,
  "success": true
}

空数据 / 降级响应

无需订房户时 missing 为 [](不是 null),ready 仍按车侧结果给出,行为不变。团内一户都没有时同样返回空清单而非报错。

错误响应

{ "code": 589500, "message": "团期不存在", "data": null, "success": false }
code 触发条件
589500 团期不存在(本次不变)
589507 无团期权限(本次不变)

本次无新增错误码。

业务边界

  • 为什么必须跟着汇总一起放宽:只放宽汇总会变成「间数算进汇总了、确认时却不放行给房务」——需求填了、汇总也算了、房务收不到,比改前更难排查。
  • 放宽后这些户也参与「房型行填齐」「晚数与行程一致」等校验,填不全会如实报缺,这是应有的行为。
  • 打回态的户仍不参与,避免逼管理员对一份正在返工的需求反复确认。

3. 提交住宿需求 PUT /v3/admin/order/{id}/hotel-requirement

VO: Result<HotelRequirementRespVO>

使用场景

定制师逐晚填报住宿需求并提交。

入参

本次入参不变。

字段 位置 类型 必填 约束 说明
id Path Long ✅ 订单 ID 订单不存在返回 582001
days Body List ✅ 逐晚需求 结构不变

出参

本次出参不变,列出以便自包含。

字段 类型 说明
requirementId Long(String) 本次写入的需求 ID(不变)
version Integer 需求版本号(不变)
status String 需求状态,团单为 PENDING_REVIEW、核心单为 PENDING(不变)
isActive Boolean 是否当前生效版本(不变)
branchTaken String 版本分支 INIT_SUBMIT / PENDING_EDIT / DONE_ADJUST(不变)
previousVersion Integer 仅 DONE_ADJUST 分支返回上一版本号(不变)

请求示例

PUT /v3/admin/order/2101506167043985410/hotel-requirement
Authorization: Bearer <token>
Content-Type: application/json

{"days": [{"dayNumber": 1, "segments": [{"roomCount": 2, "candidates": [{"hotelId": "2023714929877450753", "rooms": [{"roomTypeId": "3002000000000000013", "roomCategory": "KING", "roomCount": 2}]}]}]}]}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {"requirementId": "2101558489333784578", "version": 1, "status": "PENDING_REVIEW", "isActive": true, "branchTaken": "INIT_SUBMIT"},
  "traceId": null,
  "success": true
}

空数据 / 降级响应

不适用:本端点要么写入成功返回完整 HotelRequirementRespVO,要么抛业务异常,不存在空响应。响应体本次一个字段都没改,标记纠正是服务端副作用,不体现在返回值里——调用方若要确认标记已纠正,读汇总接口的 hotelFlagMismatchOrderCount。

错误响应

{ "code": 582017, "message": "订单状态不允许提交需求", "data": null, "success": false }
code 触发条件
582017 订单非定制中(本次不变)
582099 团单房型行未填齐(本次不变)
582016 房间数必须大于 0(本次不变)

本次无新增错误码。

业务边界

  • 新增副作用:提交成功后若该单 needs_hotel 不为真,则置 1,与需求写入同一事务——分开提交会留下「需求写进去了、标记没纠正」的中间态,而那正是本单要修的不一致。
  • 单向 0→1:不提供反向置 0。反向意味着「这户不要住宿了」,那是退需求的业务动作,有自己的链路与副作用,不由提交需求顺带做掉。
  • 已为真时不写:避免每次提交都产生一行无意义的行变更。
  • 提交被守卫拒绝时零写入:标记也不动。
  • 为 null 的历史行与为假同等对待,同样置位。

四、契约约束与正确调用方式

  • 前端不需要改代码即可受益:既有字段一个没变,部署后用房汇总直接出数。
  • 若要展示不一致提示,读 hotelFlagMismatchOrderCount:大于 0 说明存在创单时被判定不需要住宿、事后却提了需求的存量户,其间数已照常计入,该字段只用于提示与订正,不要用它去扣减间数。

五、数据库行为

只写外部可观察行为:

动作 外部可观察结果
提交住宿需求且该单此前「不需要住宿」 该单从此被视为需要住宿:其间数进入全团用房汇总、该户参与确认预检、确认时其需求被放行给房务
提交住宿需求且该单本就「需要住宿」 无额外变化(不产生多余的行变更)
提交被守卫拒绝(如订单非定制中) 零变化:需求没写入,「是否需要住宿」也不变
读接口(汇总 / 预检) 只读,无任何写入
  • 纠正与需求写入在同一事务:需求回滚则纠正一并回滚,不会出现「需求没提上去、标记却变了」。
  • 单向:只会从「不需要住宿」变成「需要住宿」,反向不会发生。
  • 无表结构变更、无 Flyway 脚本。

六、边界行为

场景 行为
标记为真 + 已提交 计入,hotelFlagMismatchOrderCount 不 +1
标记为假 + 已提交(有效态) 计入,hotelFlagMismatchOrderCount +1
标记为假 + 需求被打回 不计入,不报不一致
标记为假 + 无任何需求 不计入,不报不一致(真的不需要住宿)
标记为 null(历史行) 与为假同等对待;提交需求时同样置位

六.6、修改前后对比

字段级对比

字段 改前 改后
hotelFlagMismatchOrderCount 无 新增,Integer
hotelNeededOrderCount 仅 needsHotel=true 的户数 标记为真的户 ∪ 已提交有效需求的户
hotelSubmittedOrderCount 需标记为真且已提交 只看需求是否有效
其余既有字段 — 不变(无删除、无改名、无类型变化)
入参 / 路径 / 错误码 — 不变

行为级对比

场景 改前 改后
标记为假、已提交完整需求的户 整户丢弃:间数不进汇总、确认时不放行房务 间数计入、参与预检、确认时放行
汇总与子订单列表是否自洽 列表显示「待审核」、汇总说「0 户需住宿」 两处一致
提交住宿需求后的 needs_hotel 保持创单时的值,永远改不回来 不为真则就地置 1
打回态需求 不计入 不计入(不变)

六.7、影响评估

  • 是否破坏向后兼容: 字段层面兼容(只增不删);数值层面每日房间合计可能变大——这正是本次要修的漏算。
  • 前端是否必须同步上线: 否。
  • 回滚: 回滚本 PR 即可。注意写侧已置位的 needs_hotel 不会随回滚还原,但那些户本就应为 1,保留更正确。

七、不影响范围

  • 仅影响: 上述三个端点的取户口径、一个新增出参、提交需求的标记纠正副作用。
  • 零影响: 用车需求与座位合计、各户特殊需求标签、房务侧订房与分房逻辑、数据库结构(无表变更、无 Flyway)。

八、测试环境已验证

被测版本:hl-order-service-v3 = dev-v3 df66ec357(2026-09-20 15:2x 部署)。构建身份探针:部署后接口开始返回新字段 hotelFlagMismatchOrderCount。 验收团期 jw测试1期(2101506167098511362),在团 3 户。

AC-1 标记为假但已提交 → 计入
     张三 HL20260920105808925(6 晚 12 间 PENDING_REVIEW)needs_hotel 改回 0
     needed=1 submitted=1 mismatch=1
     D1 豪华大床×2 | D2 标间×1+豪华大床×1 | D3 标间×2 | D4 豪华大床×2 | D5 豪华大床×2 | D6 豪华房×1+标间×1
     改前同一数据 dailyRoomBreakdown = []                                   ✓

AC-2 标记为假且无需求(王五/李玉)→ 不计入、不报不一致                        ✓
AC-3 标记为真的既有场景:六天逐日间数与标记为 0 时逐字相同,mismatch=0         ✓
AC-4 mismatch:标记1+已提交→0;标记0+已提交→1;无不一致时为 0 不是 null        ✓

AC-5 写侧自动置位(真调提交接口,非 mock)
     PUT /v3/admin/order/2101507276118626306/hotel-requirement(6 晚)→ 200
     提交前 needs_hotel=0 → 提交后 needs_hotel=1
     汇总立即计入该户,逐日每晚 +1:needed=2 submitted=2 mismatch=1           ✓

AC-6 存量排查(只出数):TEST 上不一致户 21、涉及团期 10
     按状态 PENDING_REVIEW 16 / PENDING 5;改前这 21 户间数一条都没进过汇总    ✓
     生产侧按既有口径不查(无任意 SQL 通道),不作阻塞

AC-7 判权:ROOM_MANAGER / VEHICLE_MANAGER → 589507;
     GROUP_BATCH_MANAGER / SUPER_ADMIN → 200(超管短路放行,故用低权限角色验)  ✓

未做:写侧 WARN 留痕日志未在 TEST 取证(order-v3 日志窗口只有 200 行、SQL 刷屏会冲掉证据),该分支由 4 条单测覆盖;未跑 order-v3 全量单测,四域定向回归 4717 用例全绿。


十、相关文档

  • 工单 #8023
  • 前置口径 #7925(本单放宽的正是该单引入的第一道过滤)

关联 / 联系人

链接

联系人

  • 后端负责人: @jw
  • 前端负责人: @mmg