--- schema: "hl-changelog/v2" ticket: "8711" title: "房务转房与退给酒店:招募中放开,源团期阶段栅栏按动作分码(#8711)" consumer: "admin" author: "wx(GIT)" change_type: "修改接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "pending" frontend_owner: "" frontend_ref: "" target_release: "" verified_at: "" status_note: "团期招募中时,「向酒店取消」放开、「转出」保持拒绝。源团期阶段不符时错误码统一用 808327 并随文案标出阶段。列表行新增两字段标示当前行能否转出,前端据此控制转出按钮与提示。" updated_at: "2026-10-02" base: "dev-v3" --- # 房务:转房与取消,招募中场景分权,源团期栅栏细化(管理后台) > **服务**: hl-order-service-v3 > **关联 Issue**: #8711 > **关联 PR**: #8730 > **部署状态**: 测试服验证通过(commit 704ecdd887) > **影响范围**: 房务控制台「退团转房」页面(I-17/I-20/I-21 三端点) --- ## ⚠️ 关键变化 - **I-21 向酒店取消**:源团期招募中时也允许办理(此前返回 808323 拒绝)。 - **I-20 转房**:源团期招募中时被拒,改返新码 **808327**(文案统一为「退团房所在团期当前阶段(招募中)不允许处理」)。 - **I-17 列表**:每行新增 `transferAllowed`(Boolean)与 `transferBlockedReason`(String),指示该行是否允许转出与置灰理由。 --- ## 一、背景 团期成团前处于招募中,此时转房打破户数基线而重新成团,与计划配置窗口冲突。旧流程让两个动作都被拒;本次改为**招募中只放开「取消」、保持拦「转出」**: - **向酒店取消**(全量退团)不改库存配置,只通知酒店降间,允许执行; - **转出**(转给别户/别团)改动源目标两处计划基线,禁止执行。 ## 二、变更接口清单 | # | 接口 | 方法 | 路径 | 变更类型 | 说明 | |---|------|------|------|----------|------| | 1 | 退团转房列表 | GET | `/v3/admin/order/house-console/room-transfers` | 修改接口 | 行新增 `transferAllowed` 与 `transferBlockedReason` 字段(additive) | | 2 | 转出 | POST | `/v3/admin/order/house-console/room-transfers/{id}/transfer` | 修改接口 | 源团期招募中返回 808327;错误码文案含源团期阶段中文 | | 3 | 向酒店取消 | POST | `/v3/admin/order/house-console/room-transfers/{id}/cancel-hotel` | 修改接口 | 源团期招募中放开;不再返回 808323;阶段不符返回 808327 | --- ## 三、接口详情 ### 1. 退团转房列表 `GET /v3/admin/order/house-console/room-transfers` **VO**: `HouseRoomTransferPageRespVO → HouseRoomTransferRespVO` #### 使用场景 房务控制台「退团转房」页面加载列表与汇总。房务查看待处理转房行、其状态与无法转出时的原因。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | pageNo | Query | Integer | ✅ | ≥1 | 页码 | | pageSize | Query | Integer | ✅ | 1~100 | 每页条数 | | status | Query | String | ❌ | PENDING / TRANSFERRED / CANCELLED | 状态筛选;缺省 PENDING | | groupBatchId | Query | Long(string) | ❌ | - | 团期 ID 过滤(来源团期) | | cityName | Query | String | ❌ | - | 城市名称过滤 | | risk | Query | String | ❌ | NORMAL / NEAR / OVERDUE / NO_DEADLINE | 风险过滤 | #### 出参 | 字段 | 类型 | 说明 | |------|------|------| | records | List[HouseRoomTransferRespVO] | 分页行 | | total | Long | 总行数 | | page | Integer | 当前页码 | | pageSize | Integer | 每页条数 | | summary | Object | 待处理汇总(以间为单位) | | summary.pendingRooms | Integer | 待处理总间数 | | summary.overdueRooms | Integer | 已过免费取消期限的间数 | | summary.nearRooms | Integer | 临近期限的间数 | | summary.noDeadlineRooms | Integer | 未设期限的间数 | **行数据关键字段**(HouseRoomTransferRespVO): | 字段 | 类型 | 说明 | |------|------|------| | id | Long(string) | 转房行 ID | | sourceType | String | 来源类型:ORDER(常规单)/ GROUP_BATCH(团期) | | sourceOrderId | Long(string) | 源订单 ID(团期来源时为离团子单) | | sourceGroupBatchId | Long(string) | 源团期 ID(仅团期来源时有值) | | teamNo | String | 源订单团号(常规单来源时取 order_main.team_no;团期来源时为 null) | | sourceBatchNo | String | 源团期批次号(仅团期来源时有值) | | stayDate | Date | 入住日期(yyyy-MM-dd) | | cityName | String | 城市名 | | hotelName | String | 酒店名 | | roomTypeName | String | 房型名 | | roomCount | Integer | 原始间数 | | remainingCount | Integer | 剩余待处理间数 | | status | String | 状态:PENDING(待处理)/ TRANSFERRED(已转出)/ CANCELLED(已取消) | | statusLabel | String | 状态中文 | | cancelDays | Integer | 免费取消提前天数(未设为 null) | | deadlineAt | LocalDateTime | 免费取消截止时刻(未设为 null) | | risk | String | 风险码:NORMAL / NEAR / OVERDUE / NO_DEADLINE(仅 PENDING 有意义) | | riskLabel | String | 风险中文 | | readOnly | Boolean | 是否对当前操作人只读:源单由他人处理,或源团期两个动作都不允许 | | readOnlyReason | String | 只读理由 | | **transferAllowed** | **Boolean** | **✨ 新增:是否可转出(I-20)。PENDING 行仅源团期资源准备中为 true,招募中为 false(仍可向酒店取消),其余阶段为 false。已处理行同样计算但不作展示依据** | | **transferBlockedReason** | **String** | **✨ 新增:转出置灰提示。可转出时为 null;招募中为「所在团期招募中,仅可向酒店取消」;其余不可处理阶段与 readOnlyReason 相同** | #### 请求示例 ```http GET /v3/admin/order/house-console/room-transfers?pageNo=1&pageSize=20&status=PENDING&groupBatchId=2105934717486563329 Authorization: Bearer ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "records": [ { "id": "2105935060039565313", "sourceType": "GROUP_BATCH", "sourceOrderId": "2105934624691712001", "sourceGroupBatchId": "2105934717486563329", "teamNo": null, "sourceBatchNo": "T5-260928-01", "stayDate": "2027-05-12", "cityName": "海拉尔", "hotelName": "阿尔善国际维景度假温泉酒店", "roomTypeName": "高级套房", "roomCount": 2, "remainingCount": 2, "status": "PENDING", "statusLabel": "待处理", "cancelDays": 3, "deadlineAt": "2027-05-11 18:00:00", "risk": "NORMAL", "riskLabel": "正常", "readOnly": false, "readOnlyReason": null, "transferAllowed": false, "transferBlockedReason": "所在团期招募中,仅可向酒店取消" }, { "id": "2105935060047953921", "sourceType": "GROUP_BATCH", "sourceOrderId": "2105934624699100225", "sourceGroupBatchId": "2105934717486563329", "teamNo": null, "sourceBatchNo": "T5-260928-01", "stayDate": "2027-05-13", "cityName": "海拉尔", "hotelName": "阿尔善国际维景度假温泉酒店", "roomTypeName": "标准间", "roomCount": 3, "remainingCount": 2, "status": "PENDING", "statusLabel": "待处理", "cancelDays": null, "deadlineAt": null, "risk": "NO_DEADLINE", "riskLabel": "未设期限", "readOnly": false, "readOnlyReason": null, "transferAllowed": false, "transferBlockedReason": "所在团期招募中,仅可向酒店取消" } ], "total": 3, "page": 1, "pageSize": 20, "summary": { "pendingRooms": 7, "overdueRooms": 0, "nearRooms": 2, "noDeadlineRooms": 5 } }, "success": true } ``` #### 空数据 / 降级响应 当无符合条件的行时,`records` 为空数组,`total=0`;`summary` 按 `status=PENDING` 的全库统计(不受筛选影响)。接口 GET 查询无降级;异常时返回 HTTP 500 + 500001。 #### 错误响应 ```json { "code": 400, "message": "分页参数不合法", "data": null, "success": false } ``` #### 业务边界 - `transferAllowed=false` 时前端应禁用「转出」按钮,显示 `transferBlockedReason` 作置灰提示,但保留「向酒店取消」按钮可用。 - `transferAllowed=true` 时 `transferBlockedReason` 恒为 null;前端可隐藏转出提示。 - `readOnly=true` 时两个按钮都禁用,提示来自 `readOnlyReason`(源单由他人处理);此时 `transferAllowed` 同样为 false 但提示词不同(后者指阶段,前者指权限)。 - 已处理行(status=TRANSFERRED / CANCELLED)虽然 `transferAllowed` 同样计算,但不作展示依据;前端按 `status` 判断是否展示操作区域。 --- ### 2. 转出 `POST /v3/admin/order/house-console/room-transfers/{id}/transfer` **VO**: `HouseRoomTransferSaveReqVO → HouseRoomTransferRespVO` #### 使用场景 房务把待处理的退团房间转给另一张常规订单或另一个团期。只有源团期处于资源准备中时可转,招募中及其他阶段被拒。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | id | Path | Long(string) | ✅ | 存在且 status=PENDING | 转房行 ID | | targetType | Body | String | ✅ | ORDER / GROUP_BATCH | 目标类型(常规单/团期) | | targetOrderId | Body | Long(string) | 条件 | 当 targetType=ORDER 时必填 | 目标订单 ID | | targetRequirementId | Body | Long(string) | 条件 | 当 targetType=ORDER 时必填 | 目标需求 ID | | targetGroupBatchId | Body | Long(string) | 条件 | 当 targetType=GROUP_BATCH 时必填 | 目标团期 ID | | roomCount | Body | Integer | ✅ | ≥1,≤剩余待处理间数 | 转出间数 | | hotelConfirmNo | Body | String | ✅ | - | 酒店确认号 | | proofFileIds | Body | List[String] | ✅ | 非空列表 | 凭证文件 ID 列表 | | remark | Body | String | ❌ | - | 备注 | #### 出参 | 字段 | 类型 | 说明 | |------|------|------| | id | Long(string) | 转房行 ID(与入参相同) | | status | String | 更新后状态:PENDING(部分转出)或 TRANSFERRED(全部转出) | | remainingCount | Integer | 更新后剩余待处理间数 | | targetType | String | 目标类型 | | targetOrderId | Long(string) | 目标订单 ID(可为 null) | | targetTeamNo | String | 目标订单团号(可为 null) | | targetGroupBatchId | Long(string) | 目标团期 ID(可为 null) | | targetBatchNo | String | 目标团期批次号(可为 null) | | handledAt | LocalDateTime | 处理时间 | | handlerName | String | 处理人姓名 | (其余字段同 I-17 出参) #### 请求示例 ```json { "targetType": "GROUP_BATCH", "targetGroupBatchId": "2105928497547640834", "roomCount": 2, "hotelConfirmNo": "HX20270513002", "proofFileIds": ["1007", "1008"], "remark": "退团户要求转给该团期同城" } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "id": "2105935060047953921", "status": "PENDING", "remainingCount": 1, "targetType": "GROUP_BATCH", "targetOrderId": null, "targetGroupBatchId": "2105928497547640834", "targetBatchNo": "T3-260928-01", "handledAt": "2026-10-02 14:30:20", "handlerName": "房务A" }, "success": true } ``` #### 空数据 / 降级响应 无空数据场景(成功返回处理后的行)。无降级;异常时返回 HTTP 500 + 500001。 #### 错误响应 ```json { "code": 808327, "message": "退团房所在团期当前阶段(招募中)不允许处理", "data": null, "success": false } ``` **可能的错误码**: | 错误码 | 含义 | 触发条件 | |--------|------|---------| | 808320 | 转房记录不存在 | 行 ID 不存在或已软删 | | 808321 | 该房间已处理 | 行 status ≠ PENDING,或并发下被先抢 | | 808322 | 目标不可转入 | 不同城市、不同入住日期、无团号、或无转入空房 | | 808323 | 目标团期当前阶段({0})不能转入,仅资源准备中可转入 | 仅 GROUP 目标阶段不符时出现;{0} 为**目标**团期状态中文 | | 808324 | 转出间数超过剩余 {0} 间 | 转出间数 > 源计划剩余间数,或 > 目标缺口 | | 808325 | 请填写酒店确认号并上传凭证 | hotelConfirmNo 或 proofFileIds 缺失 | | 808326 | 只有原单处理人可以处理退团房间 | 操作人不是源单房务处理人 | | 808327 | 退团房所在团期当前阶段({0})不允许处理 | 源团期阶段不符(招募中、物料准备中、已出发等);{0} 为**源**团期状态中文 | #### 业务边界 - 源团期只在「资源准备中」允许转出;「招募中」返回 808327;「物料准备中」或更后期阶段同样返回 808327,文案显示实际阶段中文。 - 目标团期(仅 GROUP_BATCH)只在「资源准备中」允许转入;其他阶段返回 808323,文案显示**目标**阶段中文。 - 目标团期不存在返回 808322(不走 808323)。 - 转出后,如果 remainingCount=0 则行 status 变为 TRANSFERRED;否则保持 PENDING。 - 幂等键为「操作人 + 行 ID + 转出摘要」,3 秒内重复提交相同目标和间数只记一次。 --- ### 3. 向酒店取消 `POST /v3/admin/order/house-console/room-transfers/{id}/cancel-hotel` **VO**: `HouseRoomTransferCancelReqVO → HouseRoomTransferRespVO` #### 使用场景 房务不再转房,直接向酒店通知取消,退款给客户。源团期处于资源准备中或招募中时均允许执行;其他阶段(物料准备中、已出发等)被拒。 #### 入参 | 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | |------|------|------|------|------|------| | id | Path | Long(string) | ✅ | 存在且 status=PENDING | 转房行 ID | | cancelFee | Body | BigDecimal | ✅ | ≥0,精确到 2 位小数 | 取消费用(元;0 表示免费取消) | | proofFileIds | Body | List[String] | ✅ | 非空列表 | 凭证文件 ID 列表(酒店回执) | | remark | Body | String | ❌ | - | 备注 | #### 出参 | 字段 | 类型 | 说明 | |------|------|------| | id | Long(string) | 转房行 ID(与入参相同) | | status | String | 更新后状态:CANCELLED | | cancelReason | String | 取消原因:HOTEL_CANCELLED(人工向酒店取消) | | cancelFee | BigDecimal(string) | 取消费用 | | handledAt | LocalDateTime | 处理时间 | | handlerName | String | 处理人姓名 | (其余字段同 I-17 出参) #### 请求示例 ```json { "cancelFee": "0.00", "proofFileIds": ["1007"], "remark": "酒店同意免费取消,按规则办理退订" } ``` #### 响应示例 ```json { "code": 200, "message": "成功", "data": { "id": "2105935060039565313", "status": "CANCELLED", "cancelReason": "HOTEL_CANCELLED", "cancelFee": "0.00", "handledAt": "2026-10-02 13:45:30", "handlerName": "房务A" }, "success": true } ``` #### 空数据 / 降级响应 无空数据场景(成功返回处理后的行)。无降级;异常时返回 HTTP 500 + 500001。 #### 错误响应 ```json { "code": 808327, "message": "退团房所在团期当前阶段(物料准备中)不允许处理", "data": null, "success": false } ``` **可能的错误码**: | 错误码 | 含义 | 触发条件 | |--------|------|---------| | 808320 | 转房记录不存在 | 行 ID 不存在或已软删 | | 808321 | 该房间已处理 | 行 status ≠ PENDING,或并发下被先抢 | | 808325 | 请填写酒店确认号并上传凭证 | proofFileIds 缺失或为空 | | 808326 | 只有原单处理人可以处理退团房间 | 操作人不是源单房务处理人 | | 808327 | 退团房所在团期当前阶段({0})不允许处理 | 源团期阶段不符(物料准备中、已出发等);{0} 为**源**团期状态中文 | 本接口不返回 808323(无目标概念)。 #### 业务边界 - 源团期在「资源准备中」或「招募中」均允许取消;「物料准备中」、「已出发」等阶段返回 808327。 - 取消成功后,行 status 变为 CANCELLED,cancelReason=HOTEL_CANCELLED。 - 源计划对应间数被软删(plan_deleted_at 标记);如有剩余间数,生成新计划记录「新间数=原间数-取消间数」。 - 幂等键为「操作人 + 行 ID」,3 秒内重复提交只记一次。 - 取消费用为 0 时表示酒店同意免费取消;>0 时表示需客户或预留从团费扣除。 --- ## 四、契约约束与正确调用方式 ### 常规订单来源的行 常规单退团产生的转房行,sourceType=ORDER,sourceOrderId 是离团子单,teamNo 从 order_main 反查。 ### 团期来源的行 团期成团过程中由房务释放的转房行,sourceType=GROUP_BATCH,sourceOrderId 为离团子单(可为 null),teamNo 恒为 null(团期无团号),sourceGroupBatchId + sourceBatchNo 标识来源团期。 ### transferAllowed 与 transferBlockedReason 联用 前端根据 transferAllowed 控制转出按钮: - `true`:按钮可点,transferBlockedReason 为 null,不显示置灰提示; - `false` + `transferBlockedReason="所在团期招募中,仅可向酒店取消"`:转出禁用,显示该提示,保留取消按钮可用; - `false` + `transferBlockedReason` 为其他值(如"物料准备中"等):整行只读,两个按钮都禁用。 ### 源/目标团期阶段判定 - **I-21 向酒店取消**:源团期 `RESOURCE_PREPARING` || `RECRUITING` 放行;其余返回 808327; - **I-20 转出**:仅源团期 `RESOURCE_PREPARING` 放行;其余返回 808327;目标团期(仅 GROUP_BATCH)仅 `RESOURCE_PREPARING` 放行,其余返回 808323; - **I-17 列表**:`transferAllowed` 与 `transferBlockedReason` 由业务侧编排返回(无存储),实时计算。 --- ## 五、数据库行为 - 无新增或删除字段; - 无表结构变更、无 Flyway。源团期阶段判定在服务层完成:源团期 `RECRUITING` 时 I-21 向酒店取消照常写 `house_room_transfer`(状态转 CANCELLED、原因 HOTEL_CANCELLED),I-20 转出在写库前即返回 808327、不落任何行; - I-17 列表行返回的 `transferAllowed` 与 `transferBlockedReason` 由业务侧实时计算,无存储(源团期状态通过 order_group_batch.batch_status 关联查询); - 操作日志(`house_operation_log`)记录处理人、操作类型、摘要,支持二期团期转房审计。 --- ## 六、边界行为 ### 6.1 业务边界 **I-17 列表**: - `transferAllowed=false` 时前端应禁用「转出」按钮,显示 `transferBlockedReason` 作置灰提示,但保留「向酒店取消」按钮可用; - `transferAllowed=true` 时 `transferBlockedReason` 恒为 null;前端可隐藏转出提示; - `readOnly=true` 时两个按钮都禁用,提示来自 `readOnlyReason`(源单由他人处理);此时 `transferAllowed` 同样为 false 但提示词不同; - 已处理行(status=TRANSFERRED / CANCELLED)虽然 `transferAllowed` 同样计算,但不作展示依据;前端按 `status` 判断是否展示操作区域。 **I-20 转出**: - 源团期只在「资源准备中」允许转出;「招募中」返回 808327;「物料准备中」或更后期阶段同样返回 808327,文案显示实际阶段中文; - 目标团期(仅 GROUP_BATCH)只在「资源准备中」允许转入;其他阶段返回 808323,文案显示**目标**阶段中文; - 目标团期不存在返回 808322(不走 808323); - 转出后,如果 remainingCount=0 则行 status 变为 TRANSFERRED;否则保持 PENDING; - 幂等键为「操作人 + 行 ID + 转出摘要」,3 秒内重复提交相同目标和间数只记一次。 **I-21 向酒店取消**: - 源团期在「资源准备中」或「招募中」均允许取消;「物料准备中」、「已出发」等阶段返回 808327; - 取消成功后,行 status 变为 CANCELLED,cancelReason=HOTEL_CANCELLED; - 源计划对应间数被软删(plan_deleted_at 标记);如有剩余间数,生成新计划记录「新间数=原间数-取消间数」; - 幂等键为「操作人 + 行 ID」,3 秒内重复提交只记一次; - 取消费用为 0 时表示酒店同意免费取消;>0 时需客户或从团费扣除; - 本接口不返回 808323(无目标概念)。 ## 六.6、修改前后对比 | 场景 | 修改前 | 修改后 | |------|--------|--------| | I-21 源团期招募中 | 返回 808323「目标团期已确认」(误导) | 放开执行;操作成功 | | I-20 源团期招募中 | 返回 808323「目标团期已确认」 | 返回 808327「源团期阶段…招募中…不允许」(指向源侧) | | I-20 源团期物料准备中 | 返回 808323「已确认」 | 返回 808327 + 源团期实际阶段中文 | | I-17 行字段 | 无转出可行性标记 | 新增 transferAllowed + transferBlockedReason | | 错误码 808323 使用 | 同时用于源、目标阶段不符 | 仅用于 GROUP 目标阶段不符,文案明确含「目标」 | | 错误码 808327 | 无此码 | 新增,用于源团期阶段不符,文案明确含「源」与实际阶段 | ## 六.7、影响评估 **前端**: - 需适配 I-17 行数据新增的两字段:transferAllowed 控制转出按钮状态,transferBlockedReason 作置灰提示文案; - I-20、I-21 错误码文案调整,需更新各 toast/提示的映射(808323 专用于「目标团期阶段」,808327 专用于「源团期阶段」); - 招募中场景下转出被拒(808327)与向酒店取消成功的对比体验,前端按新码分流处理。 **后端**: - 代码层修改集中在 HouseRoomTransferManager 业务判定与 HouseRoomTransferRespVO 返回值构造,无 DB 迁移; - 源团期状态 == 招募中时,I-21 放行、I-20 拦;由 GroupBatchStatus 枚举与 RECRUITING 常量驱动,存存逻辑一致; - 错误文案由 HouseConsoleErrorCode 808323 与 808327 的 `{0}` 占位符承载,无需前端约定新码段。 **回滚**: - PR revert 即可恢复旧逻辑(代码无迁移);新VO字段 transferAllowed / transferBlockedReason 前端如若忽视不显示,旧 UI 仍可用(字段补齐不减少现有消费)。 --- ## 七、不影响范围 - I-18(修改期限)、I-19(候选目标)、I-22(异常检查)三个端点不受影响; - 历史转房行数据不回填新字段(列表行是实时计算,非持久化); - 常规单来源的转房行逻辑无变化(仅团期来源的招募中场景放开); - 其他团期阶段(资源准备中、物料准备中、已出发等)的行为不变。 --- ## 八、测试环境已验证 **部署与验证**: - commit 704ecdd887;部署状态 `STATE=ok`; - 测试端点:network 路由验证 / HTTP 状态码验证 / 业务返回码验证。 **AC-4 通过**:I-21 源团期 RECRUITING 下取消成功 - 前置:T5 团期先 RESOURCE_PREPARING 后成团变 RECRUITING;3 条 PENDING 行; - 请求:`POST /v3/admin/order/house-console/room-transfers/2105935060039565313/cancel-hotel` body `{cancelFee:"0.00", proofFileIds:[1007], ...}`; - 响应:HTTP 200,行 status=CANCELLED。 **AC-5 通过**:I-20 源团期 RECRUITING 下转出返回 808327 - 前置:同上 T5 RECRUITING; - 请求:`POST /v3/admin/order/house-console/room-transfers/2105935060047953921/transfer` 转给常规单; - 响应:HTTP 200 code=808327 msg="退团房所在团期当前阶段(招募中)不允许处理"。 **AC-9 通过**:I-20 目标侧 808323 文案含目标团期阶段 - 前置:源 T5 RESOURCE_PREPARING,目标 T3 RECRUITING; - 请求:`POST .../transfer` targetType=GROUP_BATCH; - 响应:HTTP 200 code=808323 msg="目标团期当前阶段(招募中)不能转入,仅资源准备中可转入"(文案含**目标**); - I-21 同源行同时刻调用返回 200(无目标概念,不返回 808323)。 **AC-10 通过**:列表行字段 - RECRUITING 期间三行:transferAllowed=false,transferBlockedReason="所在团期招募中,仅可向酒店取消"; - 重新成团回 RESOURCE_PREPARING 后:剩余两行 transferAllowed=true,transferBlockedReason=null。 --- ## 十、相关文档 - 后端对接文档:`API-SPEC-HOUSE` v1.1.21 §12.10(I-20 转房)与 §12.11(I-21 取消); - 错误码说明:`HouseConsoleErrorCode` 808320-808327; - VO 定义:`HouseRoomTransferRespVO` / `HouseRoomTransferSaveReqVO` / `HouseRoomTransferCancelReqVO`; - 业务实现:`HouseRoomTransferManager` 与 `HouseRoomTransferQueryManager`。 --- ## 关联 / 联系人 - **后端负责人**: @wx - **Issue**: https://git.1814.love/wx/HL/issues/8711 - **PR**: https://git.1814.love/wx/HL/pulls/8730 - **部署日期**: 2026-10-02 - **测试报告**: `D:/work2/_scratch/0928-house-proto/t20/bug-transfer-orphan/api-test/report.md`