changelog(7149): 按 CHANGELOG_TEMPLATE 重排章节(门禁)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01XYL5S9SsBtkg7aGyFAbrrQ
这个提交包含在:
API Changelog Bot
2026-09-06 16:08:18 +08:00
共同撰写人 Claude Fable 5.1
父节点 c5c69d10aa
当前提交 c1d7fed7b6
@@ -3,7 +3,7 @@ schema: "hl-changelog/v2"
ticket: "7149"
title: "团期子订单支付后即可提房车需求、物资准备起冻结、团单房型与间数必填"
consumer: "admin"
author: "wx(AI)"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
@@ -12,7 +12,7 @@ frontend_owner: "mmg"
frontend_ref: ""
target_release: ""
verified_at: "2026-09-06"
status_note: "后端已合 dev-v3 并部署测试服、网关实测通过;前端需改团期子订单提需求弹窗:房型大类必填+两个新错误码展示+招募中即显示提需求入口"
status_note: "后端已合 dev-v3 并部署测试服、网关实测通过;前端需改团期子订单提需求弹窗:房型大类必填+两个新错误码展示+招募中即显示提需求入口。"
updated_at: "2026-09-06"
base: "dev-v3"
---
@@ -29,149 +29,253 @@ base: "dev-v3"
团期子订单定制师的需求操作权限、冻结时机与校验规则同时调整:
1. **支付后即可提需求**:团期子订单(product_batch_id 非空)在定制师端已支付(orderStatus=CUSTOMIZING)后,团期处于招募中(RECRUITING)或资源准备中(RESOURCE_PREPARING)即可提交/修改房车需求,无需等待团期成团。
2. **物资准备起冻结**:团期进入物料准备中(MATERIAL_PREPARING)及之后(待出发/旅行中/复审/已结算)后,定制师**不得再提交或修改房车需求**。新增错误码 **589536**;唯一例外:若最新版需求被团期管理员打回(REJECTED_TO_CONSULTANT),该户该资源仍可重提一次。
3. **房型与间数必填**:团期子订单的每个非自订晚(customerSelfBooked 非 true)的每段,房型大类(roomCategory)与房间数(roomCount)必填且大于等于1。新增错误码 **582099**;核心订单无此约束。
1. **支付后即可提需求**:团期子订单(`product_batch_id` 非空)在定制师端已支付(`orderStatus=CUSTOMIZING`)后,团期处于招募中(`RECRUITING`)或资源准备中(`RESOURCE_PREPARING`)即可提交/修改房车需求,无需等待团期成团。前端需在招募中即显示提需求入口。
2. **物资准备起冻结**:团期进入物料准备中(`MATERIAL_PREPARING`)及之后后,定制师不得再提交或修改房车需求。新增错误码 **589536**;唯一例外:最新版需求被打回可重提一次。前端需在物料准备中后置灰入口或弹提示。
3. **房型与间数必填**:团期子订单的每个非自订晚的每段,房型大类(`roomCategory`)与房间数(`roomCount`)必填且≥1。新增错误码 **582099**;核心订单无此约束。前端需改房型大类为必填。
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 提交/修改房型需求 | PUT | `/v3/admin/order/{id}/hotel-requirement` | 行为与守卫修改 | 团期子订单新增权限闸门+房型间数必填校验 |
| 2 | 调整订单统一提交 | POST | `/v3/admin/order/{id}/adjustment/submit` | 行为与守卫修改 | hotelRequirement与vehicleRequirement走同一闸门 |
| 3 | 提交/修改用车需求 | PUT | `/v3/admin/order/{id}/vehicle-requirement` | 行为与守卫修改 | 团期子订单新增权限闸门 |
| 4 | 团期汇总查询 | GET | `/v3/admin/order/group-batch/{groupBatchId}/requirement-summary` | 复用不改 | 响应roomCategory不再出现未知 |
## 变更接口
| 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|
| 提交修改房型需求 | PUT | /v3/admin/order/orderId/hotel-requirement | 行为与守卫修改 | 团期子订单新增权限闸门、房型间数必填校验 |
| 调整订单统一提交 | POST | /v3/admin/order/orderId/adjustment/submit | 行为与守卫修改 | hotelRequirement、vehicleRequirement 走同一闸门 |
| 提交修改用车需求 | PUT | /v3/admin/order/orderId/vehicle-requirement | 行为与守卫修改 | 团期子订单新增权限闸门 |
| 团期汇总查询 | GET | /v3/admin/order/group-batch/batchId/requirement-summary | 复用不改 | 响应 roomCategory 不再出现「未知」 |
(同上)
## 接口详情
## 三、接口详情
### 1. 提交修改房型需求 PUT /v3/admin/order/orderId/hotel-requirement
### 1. 提交/修改房型需求 `PUT /v3/admin/order/{id}/hotel-requirement`
**VO**: HotelRequirementReqVO 转 HotelRequirementRespVO
**替代状态**: Deprecated 兼容期;新入口为 POST /v3/admin/order/orderId/adjustment/submit 中的 updates.hotelRequirement。
**VO**: HotelRequirementReqVO转HotelRequirementRespVO
#### 使用场景
定制师提交修改调整房型需求;后端按是否存在 active 行与当前状态自动三分支:无 active 转 INIT_SUBMIT、PENDING 转 PENDING_EDIT、DONE 转 DONE_ADJUST。
定制师提交/修改/调整房型需求。后端按是否存在active行与当前状态自动三分支:无active→INIT_SUBMIT、PENDING→PENDING_EDIT、DONE→DONE_ADJUST。本端点为@Deprecated兼容期。
#### 团期子订单的权限守卫(新增)
#### 入参
**允许提交条件**:
- 订单是团期子订单(product_batch_id 非空)
- 订单已支付(orderStatus=CUSTOMIZING)
- 团期状态为 RECRUITING 或 RESOURCE_PREPARING
- 返回 code=200,data.status 为对应状态
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | 是 | 正整数 | 订单ID |
| days | Body | Array | 是 | 长度等于tripNights | 每晚用房安排 |
| days[].dayNumber | Body | Integer | 是 | 1到tripNights | 第几晚 |
| days[].customerSelfBooked | Body | Boolean | 否 | true/false/null | 客户自订标记 |
| days[].segments | Body | Array | 条件必填 | 非自订晚≥1段 | 分住段列表 |
| days[].segments[].roomCategory | Body | String | 条件必填 | 字典room_category;团期必填 | 房型大类 |
| days[].segments[].roomCount | Body | Integer | 条件必填 | 大于0;团期必填 | 房间数 |
| days[].segments[].candidates | Body | Array | 是 | ≥1家 | 候选酒店列表 |
| specialTags | Body | Array | 否 | 字典值 | 特殊诉求标签 |
| remark | Body | String | 否 | 最长500字 | 备注 |
**拒绝条件**:
- 团期状态为 MATERIAL_PREPARING 及之后→code=589536、消息「团期已进入物资准备,需求已冻结,请联系团期管理员」
- 例外:最新版需求被打回(REJECTED_TO_CONSULTANT)时可重提一次
- 团期状态为 CANCELLED 或不存在→code=589501
- 核心订单(product_batch_id 为空)不受本守卫
#### 出参
#### 房型与间数必填校验(新增,仅团期子订单)
**触发**:PUT /v3/admin/order/orderId/hotel-requirement 或 POST /v3/admin/order/orderId/adjustment/submit 的 updates.hotelRequirement
**校验口径**:
- 逐晚判断:非自订晚(customerSelfBooked 非 true)的每个 segment
- 逐段判断:取首个候选 candidates[0] 的房型行
- 新结构(candidates[0].rooms 非空):逐行判 roomCategory 非空且 roomCount 大于 0
- 旧结构(无 rooms):按段级 roomCategory 加段级 roomCount 合成单行判
**拒绝响应**(新错误码 582099):返回消息「团期订单第 N 晚第 M 段需填写房型大类与房间数」,其中 N 为日期号,M 为段号。
### 2. 调整订单统一提交 POST /v3/admin/order/orderId/adjustment/submit
**VO**: AdjustmentSubmitReqVO 转 AdjustmentSubmitRespVO
**权限守卫**(新增):
- 房、车需求提交通过同一闸门:团期 RECRUITING 或 RESOURCE_PREPARING 允许,MATERIAL_PREPARING 及之后冻结(589536)
- 房型间数必填:同 PUT /hotel-requirement 的 582099 校验
### 3. 提交修改用车需求 PUT /v3/admin/order/orderId/vehicle-requirement
**VO**: VehicleRequirementReqVO 转 VehicleRequirementRespVO
**权限守卫**(新增):
- **允许**:团期 RECRUITING 或 RESOURCE_PREPARING,已支付子订单可提
- **拒绝**:团期 MATERIAL_PREPARING 及之后→code=589536;团期 CANCELLED 或不存在→code=589501
## 契约约束与调用对照
1. **房型间数必填(582099)**:应用范围是团期子订单(product_batch_id 非空)的非自订晚;核心订单房型仍选填。
2. **冻结与例外(589536)**:冻结触发为团期进入 MATERIAL_PREPARING 及之后;例外为最新版需求被打回(status=REJECTED_TO_CONSULTANT),允许重提一次;重提后再改仍返 589536。
3. **错误响应总览**:
| 错误码 | 场景 | 说明 |
| 字段 | 类型 | 说明 |
|---|---|---|
| 200 | 成功 | 新版本持久化 |
| 589536 | 冻结 | 团期 MATERIAL_PREPARING 及之后,非打回例外户 |
| 589501 | 团期不存在或已取消 | 团期状态完全不允许操作 |
| 582099 | 房型间数缺失 | 团期子订单非自订晚缺 roomCategory 或 roomCount |
| data.requirementId | String | 需求行ID |
| data.version | Integer | 版本号 |
| data.status | String | 需求状态 |
| data.submittedAt | String | 提交时间 |
## 数据库行为
#### 请求示例
- 无表结构变更
- 提交成功时 order_hotel_requirement 新版本 status=PENDING_REVIEW、version 递增
- 冻结拒绝时零副作用:不写版本、不写状态、不修改任何表
提交房型需求,第1晚TWIN房2间,第2晚自订。应答会返回requirementId和version。
## 边界行为
#### 响应示例
- **团单不再接受「加晚次空白占位」段**:核心订单允许先提交全空的候选/段占位(`isBlankHotelCandidate` 豁免),团期子订单的非自订晚一律按缺房型拒绝(582099「第 N 晚第 M 段」);前端团单每晚要么填齐 `rooms[]`(roomCategory + roomCount),要么标 `customerSelfBooked=true`。
- **文案「物资准备」= 团期状态芯片「物料准备中」(MATERIAL_PREPARING)**:589536 文案沿用代码里的「物资准备」叫法,与状态枚举 desc「物料准备中」同义,前端直接展示 `message` 即可,不必映射。
成功返回code=200,data包含requirementId、version、status=PENDING_REVIEW。
- **自订晚处理**:customerSelfBooked=true 的晚允许 segments 为空,不受房型间数必填约束
- **打回例外**:被打回后可重提一次,重提时进入 PENDING_REVIEW 状态;重提后再改仍返 589536
- **旧客户端兼容**:rooms 为空时回退到段级 roomCategory 加 roomCount
- **团期状态枚举**:RECRUITING 或 RESOURCE_PREPARING 允许,MATERIAL_PREPARING 及之后冻结,CANCELLED 拒绝
#### 错误响应
## 不影响范围
冻结场景返回code=589536,消息「团期已进入物资准备,需求已冻结,请联系团期管理员」。房型缺失返回code=582099,消息「团期订单第X晚第Y段需填写房型大类与房间数」。
- 核心订单(product_batch_id 为空)房型仍选填
- 其他接口(提房务、车务、配房、配车、抢单等)逻辑不变
- Flyway 无迁移脚本;DB 表结构无变更
#### 业务边界
- 权限守卫:允许RECRUITING/RESOURCE_PREPARING,拒绝MATERIAL_PREPARING及之后(589536)、CANCELLED(589501)。
- 房型间数必填:仅团期子订单非自订晚,缺失返582099,DB零副作用。
- 自订晚customerSelfBooked=true允许segments为空,不受约束。
- 打回例外:被打回后可重提一次,重提后再改仍返589536。
### 2. 调整订单统一提交 `POST /v3/admin/order/{id}/adjustment/submit`
**VO**: AdjustmentSubmitReqVO转AdjustmentSubmitRespVO
#### 使用场景
前端内存收集改动后一次性提交,后端单事务原子应用。房、车需求通过updates.hotelRequirement和updates.vehicleRequirement传入,走同一权限守卫。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | 是 | 正整数 | 订单ID |
| updates.hotelRequirement | Body | Object | 否 | 完整新版本 | 房需求(days/specialTags/remark) |
| updates.vehicleRequirement | Body | Object | 否 | 完整新版本 | 车需求(fleet/specialTags/remark) |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| data.success | Boolean | true表示提交成功 |
#### 请求示例
包含updates.hotelRequirement和updates.vehicleRequirement两个可选字段,其结构同对应的两个直接提交接口。
#### 响应示例
成功返回code=200,data.success=true。
#### 错误响应
冻结返回code=589536;房型缺失返回code=582099。
#### 业务边界
- 房、车改动走同一闸门:RECRUITING/RESOURCE_PREPARING允许,MATERIAL_PREPARING及之后冻结。
- 房型间数必填校验同PUT /hotel-requirement。
- 单事务原子应用。
### 3. 提交/修改用车需求 `PUT /v3/admin/order/{id}/vehicle-requirement`
**VO**: VehicleRequirementReqVO转VehicleRequirementRespVO
#### 使用场景
定制师提交/修改/调整用车需求。后端按是否存在active行与当前状态自动三分支。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| id | Path | Long | 是 | 正整数 | 订单ID |
| fleet | Body | Array | 是 | 至少1项 | 车辆类型与需求行 |
| fleet[].vehicleType | Body | String | 是 | SUV/MPV/大巴/轿车 | 车型大类 |
| fleet[].seats | Body | Integer | 是 | 大于0 | 每辆座位数 |
| fleet[].count | Body | Integer | 是 | 大于0 | 该类车数量 |
| specialTags | Body | Array | 否 | 字典vehicle_special_demand | 特殊诉求标签 |
| remark | Body | String | 否 | 最长500字 | 备注 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| data.requirementId | String | 需求ID |
| data.version | Integer | 版本号 |
| data.status | String | 需求状态 |
| data.submittedAt | String | 提交时间 |
#### 请求示例
提交MPV车2辆,座位数7,包含wifi特殊诉求。
#### 响应示例
成功返回code=200,data包含requirementId、version、status=PENDING_REVIEW。
#### 错误响应
冻结返回code=589536;团期不存在返回code=589501。
#### 业务边界
- 权限守卫同房需求:允许RECRUITING/RESOURCE_PREPARING,拒绝MATERIAL_PREPARING(589536)/CANCELLED(589501)。
- 房、车需求用同一闸门判。
## 四、契约约束与正确调用方式
### 正确 payload 对照
团期子订单第1晚填房型(TWIN 2间),第2晚自订:应答返回200和PENDING_REVIEW状态。
### 错误 payload 对照
第2晚缺房型大类:返回582099;物料准备中提交:返回589536;空白占位段(仅团单):返回582099。
## 五、数据库行为
- 无表结构变更。
- 提交成功时order_hotel_requirement新版本status=PENDING_REVIEW、version++。
- 冻结拒绝时零副作用。
## 六、边界行为
- **自订晚处理**:customerSelfBooked=true允许segments为空,不受房型必填约束;不计入配房分母。
- **打回例外与重提限制**:被打回后可重提一次,重提后再改仍返589536;被打回配房行释放库存。
- **旧客户端兼容**:rooms数组为空时回退段级roomCategory+roomCount;房型必填校验对新旧结构同样适用。
- **团期状态枚举**:RECRUITING/RESOURCE_PREPARING允许,MATERIAL_PREPARING及之后冻结,CANCELLED拒绝。
## 六.5、枚举 / 数据字典
| 字段 | 值 | 中文 |
|---|---|---|
| roomCategory | STANDARD/SINGLE/TWIN/QUEEN/KING/SUITE/FAMILY/YURT/SPECIAL | 房型大类 |
| GroupBatchStatus | RECRUITING | 招募中 |
| GroupBatchStatus | RESOURCE_PREPARING | 资源准备中 |
| GroupBatchStatus | MATERIAL_PREPARING | 物料准备中 |
| GroupBatchStatus | PENDING_DEPARTURE等 | 已出发或更后 |
| GroupBatchStatus | CANCELLED | 已取消 |
## 六.6、修改前后对比
### 字段级对比
无字段增删;roomCategory和roomCount既有字段,仅约束条件变。
### 行为级对比
| 行为 | 修改前 | 修改后 |
|---|---|---|
| 团期子订单提需求权限 | 成团后 | 招募中或资源准备中 |
| 物料准备中操作 | 允许 | 冻结(589536) |
| 房型与间数 | 选填 | 必填(582099) |
## 六.7、影响评估
- **破坏向后兼容**:是;权限、冻结时机、校验规则均变。
- **前端必须同步上线**:是。
- **前端workaround清理点**:删除「等待成团」逻辑;删除「物料准备中允许」分支;房型改必填;直接展示589536和582099。
## 七、不影响范围
- 核心订单房型仍选填。
- 其他接口逻辑不变。
- DB表结构无变更。
## 八、测试环境已验证
**环境**:TEST,api.test.1814.love:9443,2026-09-06 15:44,admin/1001
**网关实测**:招募中提房型→200,PENDING_REVIEW;缺房型大类→582099;资源准备中可提→200;物料准备中冻结→589536;被打回户可重提→200,version=2;重提后再改→589536;用车同样冻结→589536;自订晚不受约束→200。
**单测**:BUILD SUCCESS 396全绿。
**部署**:a52365278已合dev-v3并部署。
## 验证证据
**环境**:TEST 服务器,2026-09-06 15:44,登录 admin/1001
上述测试环境已验证的8个场景与单测全绿。
**测试覆盖**:
- 招募中子订单提房型需求→code=200, status=PENDING_REVIEW 检查通过
- 房型缺失→code=582099,消息提示具体日期和段号 检查通过
- 旧结构房型间数缺失→code=582099 检查通过
- 资源准备中可提→code=200, status=PENDING_REVIEW 检查通过
- 物料准备中冻结→code=589536,消息「团期已进入物资准备,需求已冻结」检查通过
- 被打回户在冻结期可重提一次→code=200, version=2 检查通过
- 重提后再改仍冻结→code=589536 检查通过
- 用车需求同样冻结→code=589536 检查通过
- 自订晚不受约束→code=200 检查通过
## 十、相关文档
**单测覆盖**:
- RequirementServiceTest:244 用例 检查通过
- OrderTodoServiceTest:15 用例 检查通过
- RequirementGroupBatchErrorCodeRangeTest:3 用例 检查通过
- ArchTest:5 用例 检查通过
- BUILD SUCCESS:396 用例全绿 检查通过
**部署**:提交 a52365278 合 dev-v3,测试服已部署,网关实测通过
## 相关文档与链接
- Issue #7149:https://git.1814.love:8443/wx/HL/issues/7149
- PR #7177:https://git.1814.love:8443/wx/HL/pulls/7177
- 实现:提交 a52365278
- [Issue #7149](https://git.1814.love:8443/wx/HL/issues/7149)
- [PR #7177](https://git.1814.love:8443/wx/HL/pulls/7177)
- 团期房务方案:docs/group/团期房务实现方案-v1.0.html
- 团期接口文档:docs/group/团期模块接口文档-v2.0.html
## 前端动作与当前状态
## 关联 / 联系人
**需要前端修改**(hl-ui,mmg 负责):
### 链接
1. 房型大类改必填:团期子订单提需求弹窗中房型大类字段标必填
2. 两个新错误码展示:589536 与 582099 直接展示后端 message 文案
3. 招募中即显示提需求入口:不再等待成团
4. 物料准备中冻结提示:入口置灰或提示「已冻结」
- **Issue**: [#7149](https://git.1814.love:8443/wx/HL/issues/7149)
- **PR**: [#7177](https://git.1814.love:8443/wx/HL/pulls/7177)
- **Merge commit**: [a52365278](https://git.1814.love:8443/wx/HL/commit/a52365278)
**当前状态**:待前端处理
### 联系人
- **后端**: @wx
- **前端**: @mmg