--- schema: hl-changelog/v2 ticket: "8735" title: "整团确认订房:无需房户但有残留订房计划改为拒绝,返回 808607" consumer: admin author: wx(GIT) change_type: 修改接口 backend_status: deployed gateway_status: not_required frontend_status: not_required frontend_owner: "" frontend_ref: "" target_release: "" verified_at: "" status_note: "" updated_at: "2026-10-02" base: dev-v3 --- # 整团确认订房:无需房户但有残留订房计划改为拒绝,返回 808607 ## ⚠️ 关键变化 - **改前**:团期需房户数为 0 时,整团确认(`POST .../room-plans/confirm`)直接走「本团无需订房」豁免,返回 200、`emptyDemand=true`、`hotelReady=true`。这一步**不检查**本团是否还有有效订房计划行。最常见的情形是唯一要住酒店的户退团了,他那几晚已订的房还挂在团上。豁免之后,再没有任何环节会检查这些房。 - **改后**:需房户数为 0、**且**本团仍有有效订房计划行时,不再豁免,返回 `808607`(订房与需求不等),零写入。示例文案:`2028-03-05 的 STANDARD 订房 1 间 / 已确认需求 0 间(共 1 项不等,详见预检)`。 - **出路**:对退团产生的转房行办理「退给酒店」(`cancel-hotel`),或删除该团残留的订房计划行。计划行清空后再点整团确认,返回 200、`emptyDemand=true`。 - **不变**: - 需房户数 > 0 时的逐日等量校验; - 全员客人自订(每户每晚都自订)的豁免; - 既无需房户、也无订房计划行的团,照旧 200 放行。 - **字段零变更**:请求、响应结构都没改,只是多了一种会返回 `808607` 的情形。 ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 整团确认订房 | POST | `/v3/admin/house/group-batches/{groupBatchId}/room-plans/confirm` | 错误码触发条件扩展 | 无需房户但仍有订房计划行时返回 808607,不再豁免放行 | ## 三、接口详情 ### 1. 整团确认订房 `POST /v3/admin/house/group-batches/{groupBatchId}/room-plans/confirm` **VO**: `GroupBatchRoomConfirmAllRespVO` #### 使用场景 房务把一个团期每晚的订房计划填好后,点「整团确认」。接口先对整团做一次零写入预检:每个入住日按房型大类核对订房间数与已确认需求是否相等,并检查每晚订房不超过班期最大房间数。预检通过后,逐日确认订房;全部完成后置团期的配房完成标志。 本次只改了一个情形:需房户数为 0 的团,过去一律按「无需订房」放行,现在先看它还有没有订房计划行。 #### 入参 本接口无请求体。 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | groupBatchId | Path | Long | 是 | 团期须存在且处于可确认阶段 | 团期主订单 ID | #### 出参 | 字段 | 类型 | 说明 | |------|------|------| | groupBatchId | Long(序列化为字符串) | 团期主订单 ID | | confirmedDates | `List` | 本次确认的入住日 | | skippedDates | `List` | 本次之前已全部确认、本次跳过的入住日 | | emptyDemand | Boolean | `true` 表示全团无需订房(无需房户且无订房计划行,或每户每晚都自订),已直接置配房完成 | | doneOrderIds | `List`(元素序列化为字符串) | 本次累计被置为配房完成的子订单 | | hotelReady | Boolean | 本次结束后团期的配房完成标志 | | warnings | `List` | 逐日告警的并集,本次未改 | #### 请求示例 ```http POST /v3/admin/house/group-batches/2105995952810815490/room-plans/confirm ``` #### 响应示例 残留订房已经退给酒店、计划行清空之后再确认(测试服实测): ```json { "code": 200, "message": "成功", "data": { "groupBatchId": "2105995952810815490", "confirmedDates": [], "skippedDates": [], "emptyDemand": true, "doneOrderIds": [], "hotelReady": true, "warnings": [] }, "traceId": null, "success": true } ``` #### 空数据 / 降级响应 既无需房户、也无订房计划行的团(例如两户都不需要住宿),返回与上例相同的结构:`emptyDemand=true`、`confirmedDates` 和 `skippedDates` 都为空数组、`hotelReady=true`。这一点与改前一致。 ```json { "code": 200, "message": "成功", "data": { "groupBatchId": "2105996666916270081", "confirmedDates": [], "skippedDates": [], "emptyDemand": true, "doneOrderIds": [], "hotelReady": true, "warnings": [] }, "traceId": null, "success": true } ``` #### 错误响应 需房户为 0、但仍有订房计划行(本次新增的触发情形,测试服实测): ```json { "code": 808607, "message": "2028-03-05 的 STANDARD 订房 1 间 / 已确认需求 0 间(共 1 项不等,详见预检)", "data": null, "traceId": null, "success": false } ``` | code | 文案模板 | 何时出现 | 本次变化 | |------|----------|----------|----------| | 808607 | `{入住日} 的 {房型大类} 订房 {N} 间 / 已确认需求 {M} 间(共 {K} 项不等,详见预检)` | 某入住日订房与已确认需求不等,报第一个有差额的入住日 | **新增情形**:需房户为 0 且有订房计划行。需房户 > 0 时的原有情形不变 | | 808610 | `入住日 {日期} 订房 {N} 间,超过班期最大房间数 {上限}` | 某晚订房超过班期最大房间数,在同一天的等量校验之前检查 | 需房户为 0 的团过去直接豁免、碰不到这条;现在残留订房超上限时会先报它 | | 808631 | `本团仍有 {N} 户住宿需求未填全或未落在团期区间内,不能按「无需订房」置配房完成` | 预检判定「无需订房」后、写库前的复核:期间有户新增了需求 | 不变 | 预检放锁到写库之间存在一个窗口。如果这段时间里有人给这个团新建了订房计划行,写库前的复核同样返回 `808607`,不会放行。其余错误码(如团期阶段不允许确认、无已确认基线)与改前相同,本次没改。 #### 业务边界 - 只拒绝「需房户为 0 且有有效订房计划行」这一种情形。需房户 > 0、全员自订、无需房户且无计划行,这三种情形的行为都与改前相同。 - 拒绝时零写入:不改计划行状态,不置子订单配房完成,也不动团期的 `hotelReady`。 - 想知道差在哪,先调预检 `GET /v3/admin/house/group-batches/{groupBatchId}/room-plans/confirm-check`。在这种团上,它返回 `ready=false`;对应入住日的 `days[].plannedTotal > 0`、`days[].demandedTotal = 0`;`days[].mismatch[]` 逐房型给出 `planned` / `demanded` / `diff`(`diff = 订房 − 需求`,正数表示多订)。 - ⚠️ **不要单凭预检的 `ready=false` 禁用「整团确认」按钮**。对既无需房户、也无计划行的团,预检返回 `ready=false`(`baselineExists=false`、`days=[]`),整团确认却会 200 放行(见上文「空数据」)。这是两接口原有的口径差异,本次未改,测试服已实测。 - 返回 `808607` 时 `data` 为 `null`,错误响应里没有 `confirmedDates` / `skippedDates` 可读。要展示差额,以预检接口为准。 ## 四、契约约束与正确调用方式 1. 点「整团确认」前,可以先调 `confirm-check` 拿到 `days[].mismatch`。对需房户为 0 的团,若某天 `plannedTotal > 0`,就提示房务「该团已无需住宿的户,但仍订有 N 间房,请先退给酒店或删除订房计划」。 2. 收到 `808607` 时,原样展示 `message`,并引导房务回到预检看差额。这次拒绝不需要前端回滚任何状态。 3. 退给酒店走房务控制台已有接口 `POST /v3/admin/order/house-console/room-transfers/{id}/cancel-hotel`,入参 `proofFileIds` / `cancelFee` / `remark`,本次未改。 ## 五、数据库行为 - 拒绝(`808607` / `808610` / `808631`)时零写入:订房计划行、子订单配房完成状态、团期配房完成标志都保持调用前的值。 - 放行时的写入与改前相同:逐日确认订房计划,置子订单与团期的配房完成。 ## 六、边界行为 - 判断「有没有订房计划行」只看有效行。已经退给酒店、被整行收回的计划行不算。测试服实测:两条转房行逐条退给酒店之后,计划行被收回,再确认即 200。 - 预检放锁到写库之间新建的计划行,会在写库前的复核里被拦下(`808607`)。 ## 六.6、修改前后对比 | 情形 | 改前 | 改后 | |------|------|------| | 需房户 0,无订房计划行 | 200,`emptyDemand=true` | 200,`emptyDemand=true`(不变) | | 需房户 0,有订房计划行 | 200,`emptyDemand=true`,残留订房无人检查 | `808607`(超班期上限时 `808610`),零写入 | | 需房户 > 0,订房与需求不等 | `808607` | `808607`(不变) | | 每户每晚都自订 | 200,`emptyDemand=true` | 200,`emptyDemand=true`(不变) | ## 六.7、影响评估 - 前端:只有当前端把「需房户为 0」的团一律当作可确认、并据此提示「确认成功」时才受影响。按上文第四节处理 `808607` 即可;字段零变更,不改不会报错。 - 数据:本次不迁移、不回溯。改前已经按豁免放行、配房完成为真的团,保持原样。 - 房务操作:残留订房必须先退给酒店或删除,才能整团确认。这一步是本次有意加上的。 ## 七、不影响范围 - 预检 `confirm-check` 的字段与判定未改。 - 单日确认、订房计划增删改、转房「退给酒店」等接口未改。 - 无数据库结构变更,无网关路由变更。 ## 八、测试环境已验证 测试服 order-v3 已部署本次提交(`fac70310f7`),2026-10-02 走网关实测,数据均为自建测试团: | 场景 | 结果 | |------|------| | 唯一需房户退团,留下 2 晚订房计划,整团确认 | `808607`「2028-03-05 的 STANDARD 订房 1 间 / 已确认需求 0 间(共 1 项不等,详见预检)」;预检 `ready=false`,两天都是 `plannedTotal=1`、`demandedTotal=0` | | 两户需房、只一户确认了需求,订房 2 间 | `808607`「2028-03-19 的 STANDARD 订房 2 间 / 已确认需求 1 间(共 1 项不等,详见预检)」(原有情形,回归不变) | | 上面第一个团的两条转房行逐条退给酒店之后,再整团确认 | 200,`emptyDemand=true`,`hotelReady=true` | | 两户从未提交住宿需求,无订房计划行 | 200,`emptyDemand=true`,`hotelReady=true`;预检 `ready=false`,`days=[]` | | 一户两晚全部自订、另一户不需住宿 | 200,`emptyDemand=true`,`doneOrderIds` 含自订户子订单 | ## 十、相关文档 - 预检接口:`GET /v3/admin/house/group-batches/{groupBatchId}/room-plans/confirm-check`(响应 `GroupBatchRoomConfirmCheckRespVO`),本次未改。 ## 关联 / 联系人 - 工单:wx/HL#8735 - 后端 PR:wx/HL#8736(已合入 dev-v3) - 后端联系人:wx