--- schema: "hl-changelog/v2" ticket: "7149" title: "团期子订单支付后即可提房车需求、物资准备起冻结、团单房型与间数必填" consumer: "admin" author: "wx(GIT)" change_type: "修改接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "pending" frontend_owner: "mmg" frontend_ref: "" target_release: "" verified_at: "2026-09-06" status_note: "后端已合 dev-v3 并部署测试服、网关实测通过;前端需改团期子订单提需求弹窗:房型大类必填、两个新错误码直接展示 message、招募中即显示提需求入口、物料准备中入口置灰。" updated_at: "2026-09-06" base: "dev-v3" --- # 团期模块:子订单支付后即可提房车需求、物资准备起冻结、团单房型与间数必填 > **服务**: `hl-order-service-v3` > **Issue**: #7149 > **PR**: #7177(squash 合入 dev-v3 `a52365278`)、#7184(复审补漏:汇总跳自订晚、团单房数缺失统一 582099) > **日期**: 2026-09-06 > **影响范围**: 管理后台团期子订单详情「住宿安排 / 用车安排」提需求弹窗与「订单调整」提交 ## ⚠️ 关键变化 三条行为改造,请求 / 响应结构一律不变: 1. **支付后即可提需求**:团期子订单(详情里 `groupOrder=true` / `productBatchId` 非空)在客户已支付(`orderStatus=CUSTOMIZING`)后即可提 / 改用房、用车需求,团期处于「招募中 `RECRUITING`」或「资源准备中 `RESOURCE_PREPARING`」都放行,不再等团期成团。改前团期非 `RESOURCE_PREPARING` 一律 589501「团期状态不允许当前操作」。 2. **物资准备起冻结**:团期进入「物料准备中 `MATERIAL_PREPARING`」及之后(`PENDING_DEPARTURE / TRAVELLING / REVIEWING / SETTLED`)提 / 改需求被拒,新错误码 **589536「团期已进入物资准备,需求已冻结,请联系团期管理员」**(文案里的「物资准备」就是状态芯片的「物料准备中」,同义)。唯一例外:该户该资源最新一版需求被团期管理员打回(`REJECTED_TO_CONSULTANT`)时可以重提一次,重提后再改仍 589536。团期 `CANCELLED` / 查不到团期仍 589501。 3. **团单房型大类与房间数必填**:团期子订单每个非自订晚(`customerSelfBooked` 非 `true`)的每段,按段首候选 `candidates[0].rooms[]` 逐行要求 `roomCategory` 非空且 `roomCount ≥ 1`(旧结构无 `rooms[]` 时按段级 `roomCategory` + `roomCount` 判),缺失返回新错误码 **582099「团期订单第{N}晚第{M}段需填写房型大类与房间数」**(M 从 1 起),拒绝时零副作用。核心订单不受影响,房型仍选填。**团单不再接受「加晚次空白占位」段**——每晚要么填齐房型行,要么标 `customerSelfBooked=true`。 前端要做:① 团期子订单提需求弹窗把「房型大类」改必填并提示;② 589536 / 582099 直接展示后端 `message`;③ 团期子订单在招募中即显示「提交房型需求 / 用车需求」入口;进入物料准备中后入口置灰或提示已冻结(被打回的户除外);④ 团单去掉「先提交空白占位」交互。 ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|---|---|---|---|---| | 1 | 提交 / 修改用房需求(兼容期 @Deprecated) | PUT | `/v3/admin/order/{id}/hotel-requirement` | 行为修改 | 团期闸门放宽 + 冻结 + 团单房型间数必填 | | 2 | 订单调整统一提交 | POST | `/v3/admin/order/{id}/adjustment/submit` | 行为修改 | `updates.hotelRequirement` / `updates.vehicleRequirement` 走同一闸门与必填校验 | | 3 | 提交 / 修改用车需求 | PUT | `/v3/admin/order/{id}/vehicle-requirement` | 行为修改 | 团期闸门放宽 + 冻结,不加必填 | ## 三、接口详情 ### 1. 提交 / 修改用房需求 `PUT /v3/admin/order/{id}/hotel-requirement` **VO**: `HotelRequirementReqVO → HotelRequirementRespVO`(`hl-order-service-v3/src/main/java/com/hulalv/order/requirement/controller/admin/vo/`) #### 使用场景 定制师在子订单详情「住宿安排」提交或修改用房需求。后端按当前生效版本自动分支:无生效版本 → `INIT_SUBMIT`(新版本);生效版本为 `PENDING / PENDING_REVIEW` → `PENDING_EDIT`(同版本覆盖);`DONE` 等 → `DONE_ADJUST`(版本 +1)。团期子订单新版本状态恒为 `PENDING_REVIEW`(等团期管理员确认),不进房务抢单池。本端点为兼容期入口(#4515 标 @Deprecated),新客户端走接口 2。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |---|---|---|---|---|---| | `id` | Path | String(Long) | 是 | 订单 ID | 团期子订单 `productBatchId` 非空 | | `days` | Body | Array | 是 | 长度 = `tripNights`,`dayNumber` 1..tripNights 不重复 | 逐晚安排 | | `days[].dayNumber` | Body | Integer | 是 | 1..tripNights | 第几晚 | | `days[].customerSelfBooked` | Body | Boolean | 否 | `true` = 客人自订 | 自订晚不校验房型,`segments` 可空 | | `days[].segments` | Body | Array | 非自订晚 ≥1 | 缺段 582098 | 当晚分住段 | | `days[].segments[].candidates` | Body | Array | 是(≥1) | 候选酒店,房控择一 | `hotelId / hotelName` 可空(无酒店候选) | | `days[].segments[].candidates[].rooms` | Body | Array | 新结构 | 房型行 | 团单按 `candidates[0].rooms` 逐行校验 | | `…rooms[].roomCategory` | Body | String | **团单是** | 字典 `room_category`(STANDARD/SINGLE/TWIN/QUEEN/KING/SUITE/FAMILY/YURT/SPECIAL) | 核心订单选填不变 | | `…rooms[].roomCount` | Body | Integer | **团单是,≥1** | 有行即 >0(582016) | 房数 | | `…rooms[].roomTypeId / roomTypeName / protocolPrice / remark` | Body | Long / String / Decimal / String | 否 | — | 真实房型与快照,可空 | | `days[].segments[].roomCategory / roomCount` | Body | String / Integer | 兼容 | 旧结构无 `rooms[]` 时团单必填 | 段级兼容字段 | | `days[].segments[].budget / remark` | Body | Decimal / String(≤200) | 否 | 预算由后端按协议价覆盖 | — | | `specialTags` | Body | String[] | 否 | 字典 `house_special_demand` | 特殊诉求 | | `remark` | Body | String(≤500) | 否 | — | 备注 | #### 出参 `Result` | 字段 | 类型 | 说明 | |---|---|---| | `data.requirementId` | String | 需求行 ID | | `data.version` | Integer | 版本号(INSERT-only 单调递增) | | `data.isActive` | Boolean | 是否当前生效版本 | | `data.status` | String | 团单恒 `PENDING_REVIEW`;核心为 `PENDING` | | `data.submittedAt` | String | 首提时间 | | `data.claimerId / claimerName / claimedAt` | String / String / String | 团单恒 null(不进抢单池) | | `data.branchTaken` | String | `INIT_SUBMIT / PENDING_EDIT / DONE_ADJUST` | | `data.previousVersion` | Integer | `DONE_ADJUST` 时上一版本号,否则 null | | `data.assignmentDeletedCount` | Integer | `DONE_ADJUST` 时软删配房行数,否则 null | #### 请求示例 ```json { "days": [ { "dayNumber": 1, "segments": [ { "remark": "第1晚", "candidates": [ { "hotelName": "网关实测酒店", "rooms": [ { "roomTypeName": "测试房型", "roomCategory": "KING", "roomCount": 1 } ] } ] } ] }, { "dayNumber": 2, "segments": [ { "remark": "第2晚", "candidates": [ { "hotelName": "网关实测酒店", "rooms": [ { "roomTypeName": "测试房型", "roomCategory": "TWIN", "roomCount": 2 } ] } ] } ] } ], "remark": "#7149 网关实测" } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "success": true, "data": { "requirementId": "2096504560393551873", "version": 1, "isActive": true, "status": "PENDING_REVIEW", "submittedAt": "2026-09-06 15:44:21", "claimerId": null, "claimerName": null, "claimedAt": null, "branchTaken": "INIT_SUBMIT", "previousVersion": null, "assignmentDeletedCount": null } } ``` #### 空数据 / 降级响应 本接口无空列表语义;`days` 为空数组或长度与 `tripNights` 不符返回 582011「天数长度与订单住宿晚数不一致」。第 2 晚 `customerSelfBooked=true` 且无 `segments` 时正常返回 200(自订晚不进房务分母,团单房型校验跳过)。 #### 错误响应 ```json { "code": 582099, "message": "团期订单第2晚第1段需填写房型大类与房间数", "success": false, "data": null } ``` ```json { "code": 589536, "message": "团期已进入物资准备,需求已冻结,请联系团期管理员", "success": false, "data": null } ``` 其它沿用:589501「团期状态不允许当前操作」(团期 `CANCELLED` / 查不到)、582098「第{N}晚缺少用房需求,请填写房间需求或标记为客户自订」、582016「房间数必须大于 0」、582019「候选方案必须至少含 1 个房型行」、582017「订单状态不允许提交需求」(未支付)。HTTP 始终 200,错误在 `code` / `message`。 #### 业务边界 - 团期闸门(房车共用):`RECRUITING / RESOURCE_PREPARING` 放行;`MATERIAL_PREPARING / PENDING_DEPARTURE / TRAVELLING / REVIEWING / SETTLED` 及未知状态 589536;`CANCELLED` / 查不到团期 589501;核心订单不查团期。 - 冻结期例外:该户用房需求最新一版为 `REJECTED_TO_CONSULTANT`(团期管理员打回)时放行重提,新版本回到 `PENDING_REVIEW`;之后再改仍 589536,要再改只能再次被打回。 - 团单房型间数必填按「段首候选 rooms 行」判,与全团需求汇总 `requirement-summary` 同口径;旧结构(无 `rooms[]`)按段级 `roomCategory + roomCount` 合成一行判。 - 校验顺序(PR #7184 起):订单状态(582017)→ 团期闸门(589536 / 589501)→ 晚数匹配(582011)→ 团单房型间数(582099,含房数为空 / 0)→ 通用结构校验(582098 / 582016 / 582019);任一拒绝均在写库之前,无新版本、`room_control_status` 不变。核心订单仍以通用结构校验给码(房数 0 → 582016)。 - 成功后 `order_main.room_control_status=PENDING_REVIEW`(既有行为),团期成团时定制师不再产生「房型需求 · 待提交」待办。 ### 2. 订单调整统一提交 `POST /v3/admin/order/{id}/adjustment/submit` **VO**: `AdjustmentSubmitReqVO → AdjustmentSubmitRespVO`(`hl-order-service-v3/src/main/java/com/hulalv/order/adjustment/controller/admin/vo/`) #### 使用场景 管理端子订单详情「订单调整」一次性提交各子域改动;本次只涉及 `updates.hotelRequirement`(用房需求完整新版本)与 `updates.vehicleRequirement`(用车需求完整新版本),两者与接口 1 / 接口 3 走同一团期闸门与团单房型间数校验。其它子域(人数 / 日期 / 出行人等)本次不变、省略。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |---|---|---|---|---|---| | `id` | Path | String(Long) | 是 | 订单 ID | — | | `updates` | Body | Object | 是 | 至少一个子域非空 | 各子域修改内容 | | `updates.hotelRequirement` | Body | `HotelRequirementBodyVO` | 否 | 结构同接口 1 的 `days / specialTags / remark` | 用房需求完整新版本,团单房型间数必填规则同接口 1 | | `updates.vehicleRequirement` | Body | `VehicleRequirementBodyVO` | 否 | 结构同接口 3 的 `fleet / specialTags / pickupRequired / dropoffRequired / remark` | 用车需求完整新版本 | #### 出参 `Result` | 字段 | 类型 | 说明 | |---|---|---| | `data.success` | Boolean | 提交成功恒 `true` | #### 请求示例 ```json { "updates": { "hotelRequirement": { "days": [ { "dayNumber": 1, "segments": [ { "candidates": [ { "hotelName": "网关实测酒店", "rooms": [ { "roomCategory": "KING", "roomCount": 1 } ] } ] } ] }, { "dayNumber": 2, "segments": [ { "candidates": [ { "hotelName": "网关实测酒店", "rooms": [ { "roomCategory": "TWIN", "roomCount": 1 } ] } ] } ] } ], "remark": "#7149 网关实测 调整入口" } } } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "success": true, "data": { "success": true } } ``` #### 空数据 / 降级响应 `updates` 各子域全空时沿用既有「无有效变更」拒绝;`hotelRequirement` 提交成功但版本号不变(`PENDING_EDIT` 覆盖同版本)属正常,前端以订单详情重新拉取为准。 #### 错误响应 ```json { "code": 589536, "message": "团期已进入物资准备,需求已冻结,请联系团期管理员", "success": false, "data": null } ``` ```json { "code": 582099, "message": "团期订单第2晚第1段需填写房型大类与房间数", "success": false, "data": null } ``` #### 业务边界 - 调整入口绕过「订单须为定制中」的普通提交闸,但**不绕**团期闸门与团单房型间数校验,行为与接口 1 / 3 一致。 - 团期冻结期内该入口同样 589536,被打回户例外同接口 1。 - 拒绝发生在事务内任何写操作之前,其它子域改动一并回滚。 ### 3. 提交 / 修改用车需求 `PUT /v3/admin/order/{id}/vehicle-requirement` **VO**: `VehicleRequirementReqVO → VehicleRequirementRespVO`(`hl-order-service-v3/src/main/java/com/hulalv/order/requirement/controller/admin/vo/`) #### 使用场景 定制师在子订单详情「用车安排」提交或修改用车需求。本次只改团期闸门(放宽 + 冻结 + 打回例外),**不加任何必填**;车型 / 座位联动校验、容量校验、派单展开等既有逻辑不变。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |---|---|---|---|---|---| | `id` | Path | String(Long) | 是 | 订单 ID | — | | `fleet` | Body | Array | 是(≥1) | 缺 582021 | 用车明细 | | `fleet[].vehicleType` | Body | String | 是 | 车务车型大类 key(582022) | 车型大类 | | `fleet[].seats` | Body | Integer | 是 | 该车型可选座位数(582024) | 座位数 | | `fleet[].count` | Body | Integer | 是 | >0(582023) | 车辆数 | | `specialTags` | Body | String[] | 否 | 字典 `vehicle_special_demand`(582025) | 特殊诉求 | | `pickupRequired / dropoffRequired` | Body | Boolean | 否 | — | 接 / 送机 | | `remark` | Body | String | 否 | — | 备注 | #### 出参 `Result` | 字段 | 类型 | 说明 | |---|---|---| | `data.requirementId` | String | 需求行 ID | | `data.version` | Integer | 版本号 | | `data.isActive` | Boolean | 是否当前生效版本 | | `data.status` | String | 团单恒 `PENDING_REVIEW` | | `data.submittedAt` | String | 首提时间 | | `data.branchTaken` | String | `INIT_SUBMIT / PENDING_EDIT / DONE_ADJUST` | #### 请求示例 ```json { "fleet": [ { "vehicleType": "SUV", "seats": 7, "count": 1 } ] } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "success": true, "data": { "requirementId": "2096504700000000001", "version": 1, "isActive": true, "status": "PENDING_REVIEW", "submittedAt": "2026-09-06 15:46:02", "branchTaken": "INIT_SUBMIT" } } ``` #### 空数据 / 降级响应 `fleet` 为空返回 582021「用车需求数组不能为空」;车队车型库不可用返回 582091「车队车型库不可用,无法校验座位数选项」(既有降级,本次不变)。 #### 错误响应 ```json { "code": 589536, "message": "团期已进入物资准备,需求已冻结,请联系团期管理员", "success": false, "data": null } ``` 其它沿用:589501(团期 `CANCELLED` / 查不到)、582022 / 582024 / 582023 / 582025(车型 / 座位 / 数量 / 诉求校验)。 #### 业务边界 - 团期闸门与接口 1 完全一致(同一方法),放行 / 冻结 / 打回例外按**用车需求**自身的最新一版判。 - 车侧不加房型类必填;`fleet` 结构与既有校验不变。 - 成功后 `order_main.vehicle_control_status=PENDING_REVIEW`(既有行为)。 ## 四、契约约束与正确调用方式(接口类必写) ### ✅ 正确 / ❌ 错误 payload 对照 | 场景 | payload 要点 | 结果 | |---|---|---| | ✅ 团单每晚房型行齐全 | `candidates[0].rooms[]` 每行 `roomCategory` + `roomCount ≥ 1` | 200,`status=PENDING_REVIEW` | | ✅ 团单某晚客人自订 | `{ "dayNumber": 2, "customerSelfBooked": true }`,无 `segments` | 200,该晚跳过校验 | | ✅ 旧结构团单 | 无 `rooms[]`,段级 `roomCategory` + `roomCount` 齐全 | 200 | | ❌ 团单房型行缺 `roomCategory` | `rooms: [ { "roomCount": 1 } ]` | 582099 | | ❌ 团单房型行房数为空 / 0 | `rooms: [ { "roomCategory": "KING", "roomCount": 0 } ]` | 582099(PR #7184 起;核心订单仍 582016) | | ❌ 团单旧结构缺段级 `roomCategory` | 段级只有 `roomCount`,候选带 `roomTypeId` | 582099 | | ❌ 团单「加晚次空白占位」段 | 候选与段全空 | 582099(核心订单该形态仍放行) | | ❌ 团期物料准备中提交 / 修改 | 任何合法 payload | 589536(该户最新需求被打回除外) | | ❌ 子订单未支付 | 任何 payload | 582017「订单状态不允许提交需求」 | ### 切换状态时的必要动作 - 团期从招募中推进到物料准备中后,前端应把提需求入口置灰并以 589536 文案提示;管理员打回某户后该户入口恢复一次。 - 团单弹窗保存前在前端做房型大类必填校验,减少 582099 往返;后端仍以 582099 兜底。 ## 五、数据库行为(涉及写操作时必写) - 无表结构变更、无 Flyway。 - 提交成功:`order_hotel_requirement` / `order_vehicle_requirement` 写入新版本(`PENDING_EDIT` 为同版本换行,其它版本 +1),`status=PENDING_REVIEW`;`order_main.room_control_status` / `vehicle_control_status` 回写 `PENDING_REVIEW`(既有行为)。 - 被拒(589536 / 582099 / 589501 / 结构校验):无任何写入。 ## 六、边界行为 - **团单不再接受「加晚次空白占位」段**:核心订单允许先提交全空的候选 / 段占位,团期子订单的非自订晚一律按缺房型拒绝(582099「第 N 晚第 M 段」);团单每晚要么填齐 `rooms[]`,要么标 `customerSelfBooked=true`。 - **文案「物资准备」= 团期状态芯片「物料准备中」(`MATERIAL_PREPARING`)**:589536 文案沿用代码里的「物资准备」叫法,与状态枚举文案同义,前端直接展示 `message` 即可。 - **冻结期打回只给一次重提机会**:重提后最新版变 `PENDING_REVIEW`,再改回到 589536;这是有意设计(改需求须经管理员再次打回)。 - **自订晚**:`customerSelfBooked=true` 的晚不做房型校验;全团汇总 `requirement-summary` 也整晚跳过(PR #7184 复审补漏),残留 `segments/rooms` 不计入采购分母、不再出「未知」桶——前端标记自订后仍建议清空该晚 `segments`,但后端不依赖它。 - **未知团期状态**按冻结处理(fail closed),不会误放行。 - **错误码优先级变化(PR #7184,核心订单也受影响)**:结构校验(582098 / 582016 / 582019 / 582020)从「最先」挪到订单状态(582017)、团期闸门(589536 / 589501)、晚数匹配(582011)、已配房晚改自订(582097)之后;同一请求同时有结构错误和前置错误时,现在先返回前置错误码。前端若按错误码分支提示需按新顺序理解,语义是「更根因的错误优先」。 - **调整入口同口径(PR #7184)**:`adjustment/submit` 对团期子订单同样先做团单房型间数校验,房数为空 / 0 也返回 582099「第 N 晚第 M 段」,不再先出 582016。 - **全团汇总某晚全团自订则无该晚条目**:`dailyRoomBreakdown` 按 dayNumber 升序但不保证连续,前端逐日表按 dayNumber 对齐、不要按下标。 - **子订单详情统计同步(PR #7184)**:订单详情 `hotelRequirementBrief.totalRoomCount / roomTypeSummary` 也不再计入自订晚残留段,与全团汇总一致;该晚仍出现在 `days[]` 里,并**新增响应字段** `hotelRequirementBrief.days[].customerSelfBooked`(Boolean,纯新增不破坏契约)供前端解释「段里有房型行但不计入总数」。 ## 六.5、枚举 / 数据字典(接口出现枚举时必写) ### roomCategory(字典 `room_category`) | 值 | 含义 | |---|---| | STANDARD | 标准间 | | SINGLE | 单人间 | | TWIN | 双床房 | | QUEEN | 大床房 | | KING | 特大床房 | | SUITE | 套房 | | FAMILY | 家庭房 | | YURT | 帐篷 / 毡房 | | SPECIAL | 特色房 | ### 团期状态(`com.hulalv.order.groupbatch.enums.GroupBatchStatus`) | 值 | 芯片文案 | 提 / 改需求 | |---|---|---| | RECRUITING | 招募中 | 放行 | | RESOURCE_PREPARING | 资源准备中 | 放行 | | MATERIAL_PREPARING | 物料准备中 | 589536(打回户例外) | | PENDING_DEPARTURE | 待出发 | 589536(打回户例外) | | TRAVELLING | 出行中 | 589536(打回户例外) | | REVIEWING | 核单中 | 589536(打回户例外) | | SETTLED | 已结算 | 589536(打回户例外) | | CANCELLED | 已取消 | 589501 | ### 需求状态(`com.hulalv.order.requirement.enums.RequirementStatus`,`data.status` / `room_control_status`) | 值 | 含义 | |---|---| | PENDING_REVIEW | 待团期管理员审核(团单提交后) | | REJECTED_TO_CONSULTANT | 已打回定制师(冻结期可重提一次) | | PENDING / PROCESSING / DONE | 核心订单 / 管理员提交房务后的房务侧状态,本次不变 | ## 六.6、修改前后对比(修改/删除类接口必写,新增跳过) ### 字段级对比 请求无字段增删;`rooms[].roomCategory`、`rooms[].roomCount`(及旧结构段级同名字段)由「选填」改为「团期子订单必填」,核心订单不变。响应新增 `GET /v3/admin/order/{id}`(订单详情)`hotelRequirementBrief.days[].customerSelfBooked`(Boolean,PR #7184)。 ### 行为级对比 | 行为 | 修改前 | 修改后 | |---|---|---| | 团期子订单提 / 改需求时机 | 团期须为 `RESOURCE_PREPARING`(成团后),否则 589501 | 支付后即可:`RECRUITING / RESOURCE_PREPARING` 放行 | | 团期物料准备及之后 | 589501 | 589536(新码,文案明确「已冻结」),最新需求被打回的户可重提一次 | | 团单缺房型大类 / 房数 | 放行,全团汇总出现「未知」房型 | 582099 拒绝,零副作用(房数为空 / 0 也是 582099,不再先出 582016;PR #7184) | | 自订晚残留段进入全团汇总 | 计入「未知」桶 | 整晚跳过,不计入(PR #7184) | | 团单空白占位段 | 放行 | 582099 拒绝 | | 用车需求 | 同 589501 闸 | 同新闸门,不加必填 | ## 六.7、影响评估(修改/删除类必写) - 破坏向后兼容:**部分**——请求 / 响应结构不变,但团单缺房型或空白占位段的旧调用会从 200 变 582099,招募中的调用从 589501 变 200,物料准备中从 589501 变 589536。 - 前端是否必须同步上线:**建议同步**——不同步时功能可用但用户会收到 582099 / 589536 提示且入口显示时机不准。 - 前端需清理的分支:「未成团不显示提需求入口」「物料准备中仍允许提交」「团单空白占位先提交」。 ## 七、不影响范围(显式声明, 帮前端/QA 缩小排查面) - 核心订单(`productBatchId` 为空)的提需求、房型选填、抢单池、房务配房全部不变。 - 团期管理员确认 / 打回 / 提交房务(`…/hotel-requirement/reject`、`…/dispatch`、`group-batch/{groupBatchId}/requirement/*`)本次不改;打回后重提的版本号规则不变。 - `GET /v3/admin/order/group-batch/{groupBatchId}/requirement-summary` 结构不变,只是按本次提交的团单不再出现 `roomCategory="未知"` 项(历史数据仍可能出现)。 - 网关路由、权限码、表结构均无改动。 ## 八、测试环境已验证 **环境**:TEST 网关 `https://api.test.1814.love:9443`,order-v3 dev-v3 `a52365278` 两实例 2026-09-06 15:43 滚动部署,登录 `admin`(adminId 1001,SUPER_ADMIN,且为两张测试单的定制师),实测 15:44–15:47。 | 场景 | 请求 | 结果 | |---|---|---| | 招募中(`RECRUITING`)子订单 2096412454488612866 提完整房型 | `PUT …/hotel-requirement` | 200,`status=PENDING_REVIEW` | | 招募中,第 2 晚房型行缺 `roomCategory` | `PUT …/hotel-requirement` | 582099「团期订单第2晚第1段需填写房型大类与房间数」,DB 无新版本 | | 招募中,旧结构段级缺 `roomCategory`(候选带 `roomTypeId`) | `PUT …/hotel-requirement` | 582099,同上 | | 资源准备中完整提交 | `PUT …/hotel-requirement` | 200,`version=1 INIT_SUBMIT PENDING_REVIEW`;`order_main.room_control_status=PENDING_REVIEW` | | 资源准备中经调整入口改需求 | `POST …/adjustment/submit` | 200,`data.success=true`(同版本 `PENDING_EDIT` 换行) | | 第 2 晚 `customerSelfBooked=true` 无段 | `PUT …/hotel-requirement` | 200 | | 团期 2089713777065832450 子订单 2096029450184347649 资源准备中提交 | `PUT …/hotel-requirement` | 200 | | 团期管理员打回该户 | `POST …/hotel-requirement/reject` | 200,需求行 `REJECTED_TO_CONSULTANT`、`is_active=0` | | 团期改为 `MATERIAL_PREPARING` 后被打回户重提 | `PUT …/hotel-requirement` | 200,`version=2 PENDING_REVIEW`(冻结期例外) | | 重提后再改 | `PUT …/hotel-requirement` | 589536「团期已进入物资准备,需求已冻结,请联系团期管理员」 | | 物料准备中经调整入口改需求 | `POST …/adjustment/submit` | 589536 | | 物料准备中提用车需求 | `PUT …/vehicle-requirement` | 589536 | **单测**:`RequirementServiceTest` 244 / `OrderTodoServiceTest` 15 / `RequirementGroupBatchErrorCodeRangeTest` 3 + 5 个 ArchTest(RedLine / MapperBoundary / HouseModuleBoundary / DashboardLayer / LocalCacheVetting)全绿,`BUILD SUCCESS` 396 用例。 ## 十、相关文档 - 团期模块接口文档 `docs/group/团期模块接口文档-v2.0.html` §0C.11.1(提需求时机)/ §0C.11.2(房型间数必填)/ GB-ADM-011: - 团期房务实现方案 `docs/group/团期房务实现方案-v1.0.html` §3.12.1 / §3.12.2 - 后续工单(本次不做):管理员确认 / 打回改造(M1 / M2)、房务团期看板与按日订房、定制师 ↔ 团期管理员站内会话 ## 关联 / 联系人 ### 链接 - Issue: - PR: - 合并提交: `a52365278`(dev-v3) ### 联系人 - 后端:wx - 前端(hl-ui):mmg