docs(changelog): order-v3 全团需求汇总逐日房间补酒店维度与住宿日期(#8030)
changelog-filename-gate / validate (push) Failing after 2s

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
这个提交包含在:
jw
2026-09-20 17:07:34 +08:00
共同撰写人 Claude Opus 5
父节点 96ac790821
当前提交 af00e6fa30
@@ -0,0 +1,248 @@
---
schema: "hl-changelog/v2"
ticket: "8030"
title: "全团需求汇总逐日房间补酒店维度与住宿日期"
consumer: "admin"
author: "jw(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "not_required"
frontend_status: "pending"
frontend_owner: "mmg"
frontend_ref: ""
target_release: ""
verified_at: "2026-09-20"
status_note: "全团需求汇总 GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary 的 dailyRoomBreakdown 纯增两项:stayDate(该晚住宿日期 = 团期出发日 + dayNumber - 1,团期无出发日时为 null)与 hotels[](该晚按酒店分组的用房,含 hotelId / hotelName / totalRoomCount / rooms[])。原有 rooms[](不分酒店的全天合计)与其余字段一个没动。这样团期「查看需求」页的「用房 · 汇总」表(Day N | 酒店 | 房型 | 所需间数)一个接口就能画完,不必逐户调订单调整快照去拼酒店,也不必等房务建完订房计划——后者在成团前根本没有数据。口径:与 rooms 同一次遍历的两个视角,任一天 Σhotels[].totalRoomCount == Σrooms[].totalRoomCount;每段只取首方案候选(候选是房控择一,累加全部会翻倍);取不到酒店的段归 hotelId=null 一条且恒排末位,间数不丢;酒店名优先取需求里落库的快照,缺失的按 ID 一次批量补,资源服务不可用时名称为 null、间数照常。"
updated_at: "2026-09-20"
base: "dev-v3"
---
# order-v3: 全团需求汇总逐日房间补酒店维度与住宿日期
> **服务**: hl-order-service-v3 (端口 8086)
> **PR**: [#8040](https://git.1814.love:8443/wx/HL/pulls/8040)(主体)、[#8041](https://git.1814.love:8443/wx/HL/pulls/8041)(验收补丁:按酒店分组那份补房型中文名)
> **Issue**: [#8030](https://git.1814.love:8443/wx/HL/issues/8030)
> **日期**: 2026-09-20
> **影响范围**: 管理后台「团期订单 → 查看需求」页的「用房 · 汇总」表
---
## ⚠️ 关键变化
- **纯增两项**:`dailyRoomBreakdown[].stayDate`、`dailyRoomBreakdown[].hotels[]`。既有字段一个没删没改,入参与路径不变。
- **一个接口画完整张表**:此前「酒店」这一列只能逐户调 `GET /v3/admin/order/{orderId}/adjustment/snapshot` 去拼,或等房务建完订房计划(`room-plans`,成团前为空)。
- **两个视角、同一批间数**:`hotels[]` 与 `rooms[]` 是同一次遍历的两个视角,任一天间数总和必然相等。
- **不改任何口径**:计入哪些户、哪些需求算数,全部沿用 #7925 / #8023 的既有判定。
---
## 一、背景
原型「用房 · 汇总」要的是「Day N | 酒店 | 房型 | 所需间数」,而汇总此前只给房型与间数,酒店这一列没有数据源:
| 想要的列 | 改前只能这么拿 | 问题 |
|---|---|---|
| 间数 + 房型 | `requirement-summary` | ✅ 有 |
| 酒店 | 逐户 `adjustment/snapshot` | N 户调 N 次,且那是为「订单调整」设计的重接口 |
| 酒店(房务实际订房) | `room-plans` | **要房务认领并建计划之后才有数据**,成团前为空 |
| 住宿日期 | 无 | 只有 `dayNumber` |
TEST 实证(团期 `jw测试1期`,招募中):`room-plans` 返回 `days: []`、`progress: NOT_STARTED` —— 运营恰恰要在成团前按这张表向酒店报数。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 全团需求汇总 | GET | `/v3/admin/order/group-batch/{groupBatchId}/requirement-summary` | 修改 | `dailyRoomBreakdown[]` 纯增 `stayDate` 与 `hotels[]` |
---
## 三、接口详情
### 1. 全团需求汇总 `GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary`
**VO**: `Result<GroupRequirementSummaryRespVO>`
#### 使用场景
团期详情「查看需求」页的「用房 · 汇总」表:逐日列出住哪家酒店、什么房型、要几间,运营据此向酒店报数。
#### 入参
本次入参**不变**。
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| groupBatchId | Path | Long | ✅ | 团期 ID | 团期不存在返回 589500 |
#### 出参
| 字段 | 类型 | 说明 |
|------|------|------|
| dailyRoomBreakdown[].dayNumber | Integer | 第几天(不变) |
| dailyRoomBreakdown[].stayDate | String(yyyy-MM-dd) | **新增**。该晚住宿日期 = 团期出发日 + dayNumber − 1;团期无出发日时为 `null`(不推算) |
| dailyRoomBreakdown[].rooms[] | List | 该天各房型合计,**不分酒店**(不变) |
| dailyRoomBreakdown[].hotels[] | List | **新增**。该天按酒店分组的用房 |
| dailyRoomBreakdown[].hotels[].hotelId | String | 酒店 ID(字符串序列化防 JS 精度丢失);取不到酒店时为 `null` |
| dailyRoomBreakdown[].hotels[].hotelName | String | 酒店名;资源服务不可用时为 `null` |
| dailyRoomBreakdown[].hotels[].totalRoomCount | Integer | 该天该酒店合计间数 |
| dailyRoomBreakdown[].hotels[].rooms[] | List | 该天该酒店各房型合计(结构同上面的 `rooms[]`) |
| 其余既有字段 | — | 不变(无删除、无改名、无类型变化) |
#### 请求示例
```http
GET /v3/admin/order/group-batch/2101506167098511362/requirement-summary
Authorization: Bearer <token>
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"activeOrderCount": 3,
"hotelNeededOrderCount": 2,
"hotelSubmittedOrderCount": 2,
"hotelFlagMismatchOrderCount": 1,
"dailyRoomBreakdown": [
{
"dayNumber": 1,
"stayDate": "2026-09-27",
"rooms": [{"roomCategory": "KING", "roomCategoryName": "豪华大床", "totalRoomCount": 3}],
"hotels": [
{
"hotelId": "2023714929877450753",
"hotelName": "呼伦贝尔香格里拉大酒店",
"totalRoomCount": 3,
"rooms": [{"roomCategory": "KING", "roomCategoryName": "豪华大床", "totalRoomCount": 3}]
}
]
}
],
"vehicleSeatSummary": [],
"orderSpecialTags": []
},
"traceId": null,
"success": true
}
```
#### 空数据 / 降级响应
- 全团无计入需求时 `dailyRoomBreakdown` 为 `[]`(不是 null),不调房型字典、不调资源服务。
- 某天全部段都取不到酒店时,`hotels[]` 只有一条 `hotelId: null` 的记录,间数照常。
- 资源服务不可用时只有 `hotelName` 为 `null`,`hotelId`、间数与分组照常返回,接口不报错。
#### 错误响应
```json
{ "code": 589507, "message": "无操作权限(当前角色未授予团期权限,或该团期不在您名下)", "data": null, "success": false }
```
| code | 触发条件 |
|------|----------|
| 589507 | 当前角色没有 `group-batch:view`(本次不变) |
| 589500 | 团期不存在(本次不变) |
| 401 | 未登录(网关拦截) |
本次新增内部错误码 589574(资源服务住宿名称补全降级),**只在服务端降级日志里出现,不会传播给前端**。
#### 业务边界
- **间数不变量**:任一天 `Σ hotels[].totalRoomCount == Σ rooms[].totalRoomCount`。两者是同一次遍历的两个视角,不是两套统计。
- **只取首方案**:一段有多个候选酒店时只计 `candidates[0]`。候选是房控择一、不是都要,累加全部会让采购分母翻倍。
- **取不到酒店的段**(没有候选、或候选未填酒店)归到 `hotelId: null` 一条,**不丢间数**;该条恒排在**最后**,即使它间数最多。
- **排序**:其余酒店按间数降序,同数按 hotelId 升序(稳定)。
- **酒店名来源**:优先取需求里落库的快照;快照缺的按 ID 一次批量补(不逐个查)。酒店改名后快照会旧,以补齐结果为准。
- **计入口径不变**:哪些户、哪些需求算数完全沿用 #7925 / #8023;客户自订晚仍整晚跳过。
---
## 四、契约约束与正确调用方式
- 画「用房 · 汇总」表用 `hotels[]`;要「这一天一共几间」用 `rooms[]`。**不要**把 `hotels[]` 里的间数再跨酒店累加去当全天合计——直接读 `rooms[]` 即可,两者本就相等。
- `hotelId` 是**字符串**,不要用 JS 的 Number 解析。
- `hotelName` 可能为 `null`(资源服务降级 / 该酒店已删),前端按「未知酒店」展示即可,**不要**因此隐藏整行——间数仍然有效。
- `stayDate` 可能为 `null`(团期未排出发日),此时按 `Day N` 展示。
---
## 六、边界行为
| 场景 | 行为 |
|------|------|
| 多户订同一家酒店 | 合并为一条,间数相加 |
| 同一晚多户订不同酒店 | `hotels[]` 出多条,按间数降序 |
| 一段有多个候选酒店 | 只计首方案,不重复计数 |
| 段未填酒店 / hotelId 脏值 | 归 `hotelId: null` 一条并排末位,间数不丢 |
| 客户自订晚 | 整晚跳过(不变) |
| 团期无出发日 | `stayDate` 为 null,不推算 |
| 资源服务不可用 | `hotelName` 为 null,其余照常 |
---
## 六.6、修改前后对比
### 字段级对比
| 字段 | 改前 | 改后 |
|------|------|------|
| `dailyRoomBreakdown[].stayDate` | 无 | 新增,String(yyyy-MM-dd),可为 null |
| `dailyRoomBreakdown[].hotels[]` | 无 | 新增,List |
| `dailyRoomBreakdown[].rooms[]` | — | 不变 |
| 其余既有字段 / 入参 / 路径 / 错误码 | — | 不变 |
### 行为级对比
| 场景 | 改前 | 改后 |
|------|------|------|
| 画「用房 · 汇总」表 | 逐户调 `adjustment/snapshot` 拼酒店,或等房务建订房计划 | 一个接口出数 |
| 成团前查逐日酒店 | 无数据源(`room-plans` 为空) | 直接从各户已提交需求汇总 |
| 逐日间数与房型 | 已有 | 逐字不变 |
## 六.7、影响评估
- **是否破坏向后兼容**: 是纯增字段,完全兼容;既有 `rooms[]` 数值逐字不变。
- **前端是否必须同步上线**: 否。不接入则页面保持现状。
- **回滚**: 回滚本 PR 即可,只读接口、无数据变更。
---
## 七、不影响范围
- **仅影响**: 本接口 `dailyRoomBreakdown[]` 的两个新增字段。
- **零影响**: 计入户口径与三个户数、用车座位合计、各户特殊需求标签、整体确认预检、房务侧订房与分房、`room-plans`、`adjustment/snapshot`、数据库结构(只读接口,无表变更、无 Flyway)。
---
## 八、测试环境已验证
```
待部署 TEST 后回填实测结果(工单 #8030 AC-1~AC-11)
```
---
## 十、相关文档
- 工单 [#8030](https://git.1814.love:8443/wx/HL/issues/8030)
- 计入口径前置:[#7925](https://git.1814.love:8443/wx/HL/issues/7925)、[#8023](https://git.1814.love:8443/wx/HL/issues/8023)
---
## 关联 / 联系人
### 链接
- **Issue**: [#8030](https://git.1814.love:8443/wx/HL/issues/8030)
- **PR**: [#8040](https://git.1814.love:8443/wx/HL/pulls/8040)、[#8041](https://git.1814.love:8443/wx/HL/pulls/8041)
### 联系人
- **后端负责人**: @jw
- **前端负责人**: @mmg