changelog-filename-gate / validate (push) Failing after 1s
88caa74 房务接口审计批次:#8385 订房计划守卫/#8386 住宿驳回加门+删车务口/#8387 旧房间分配三口下线/#8388 回执认领校验+读门/#8389 家庭维度写口下线/#8390 16 读端点补门+菜单撤授。前端按钮后端字段驱动+错误码拦截器透 message+被删端点零调用/入口仅房务角色页,6 条均 not_required;#8387/#8389 后端已标,余 4 条翻 not_required,owner/ref 留空,status_note 引号内追充实证。
374 行
15 KiB
Markdown
374 行
15 KiB
Markdown
---
|
||
schema: "hl-changelog/v2"
|
||
ticket: "8385"
|
||
title: "团期订房计划建守卫:超管未认领团上禁建(808612),释放文案改为可操作指引"
|
||
consumer: "admin"
|
||
author: "wx(GIT)"
|
||
change_type: "修改接口"
|
||
backend_status: "deployed"
|
||
gateway_status: "verified"
|
||
frontend_status: "not_required"
|
||
frontend_owner: ""
|
||
frontend_ref: ""
|
||
target_release: ""
|
||
verified_at: ""
|
||
status_note: "超管在未被房务整团认领的团期上新建订房计划时返回 808612(复用已有码);释放端点的 808660 文案改为可操作的指引(删除计划、联系超管接管)。后端改动已合入 dev-v3 并部署测试服,808612 新守卫与 808660 新文案均已网关实测。前端实证(mmg 2026-09-27):room-plans 写口错误码拦截器透 message,808612/808660 常量已存在新文案自动上屏;超管无未认领团直接排房入口(看板仅 isMine 走团级接管),零改动 not_required。"
|
||
updated_at: "2026-09-26"
|
||
base: "dev-v3"
|
||
---
|
||
|
||
# order-v3:团期订房计划守卫与释放指引改进(管理后台)
|
||
|
||
**服务**: hl-order-service-v3
|
||
**PR**: #8395
|
||
**Issue**: #8385
|
||
|
||
---
|
||
|
||
## ⚠️ 关键变化
|
||
|
||
1. **新增入口守卫**:超管(SUPER_ADMIN)在**未被房务认领的团期**上调用 `POST /v3/admin/house/group-batches/{groupBatchId}/room-plans` 时,返回 **808612**「该团期尚未被房务整团认领」,不落库。
|
||
- 背景:超管本可在无人认领的团上直接建计划,导致"团没人管、但计划和库存都在"的状态。释放时房务因为 808660 无法释放,只剩逐条删计划这一条路。
|
||
- 约束:超管要在团上排房,必须先 `POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/takeover` 指派给某个房务,再建计划。
|
||
|
||
2. **改进释放文案**:端点 `POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/release` 的错误码 808660 文案改为:
|
||
「该团仍有 {0} 条未取消的订房计划,无法释放:请先逐条删除订房计划后再释放;如需更换认领房务请联系超管接管」
|
||
- 改前文案提到的「走接管」对房务不可用(接管只有超管能做)。改后提供两条可行出口:删除计划(房务自助)/ 联系超管接管(超管权限)。
|
||
|
||
---
|
||
|
||
## 一、背景
|
||
|
||
团期整团认领的唯一真实指针是 `order_group_batch.house_claimer_id`。超管出于"人离职、团转手"的清理需要被允许越过认领校验,但在一个**没人认领、也不需要清理**的团上直接建计划,不属于这类处置。
|
||
|
||
释放时的 808660 守卫堵住了"有计划+无认领人"的释放口,文案则指向一个房务无法执行的操作(接管),导致房务被无谓地卡住。
|
||
|
||
---
|
||
|
||
## 二、变更接口清单
|
||
|
||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||
|---|------|------|------|----------|------|
|
||
| 1 | 提交订房计划 | POST | `/v3/admin/house/group-batches/{groupBatchId}/room-plans` | 新增入口守卫 | 超管未认领团上返回 808612 |
|
||
| 2 | 释放认领 | POST | `/v3/admin/order/grab-pool/group-batches/{groupBatchId}/release` | 错误码文案改进 | 808660 文案改为可操作指引 |
|
||
|
||
网关无改动(既有 `/v3/admin/house/` 与 `/v3/admin/order/` 前缀均可达);返回码、触发条件、已认领团的行为全部不变。
|
||
|
||
---
|
||
|
||
## 三、接口详情
|
||
|
||
### 1. 提交订房计划 `POST /v3/admin/house/group-batches/{groupBatchId}/room-plans`
|
||
|
||
**VO**: `GroupBatchRoomPlanSaveReqVO → Result<List<GroupBatchRoomPlanRespVO>>`
|
||
|
||
#### 使用场景
|
||
|
||
房务或超管在团期上提交多条订房计划(房型、房数、价格、结算方式、库存扣减等)。超管在未认领的团上调用时新增拒绝,改后只能通过先 takeover 指派给房务的方式排房。
|
||
|
||
#### 入参字段表
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||
|------|------|------|------|------|------|
|
||
| groupBatchId | Path | Long | 是 | — | 团期 ID |
|
||
| items | Body | List | 是 | ≤200 条 | 订房计划行 |
|
||
| items[].stayDate | Body | LocalDate | 是 | 格式 `yyyy-MM-dd` | 入住日期 |
|
||
| items[].hotelId | Body | Long | 是 | — | 酒店 ID |
|
||
| items[].roomTypeId | Body | Long | 是 | — | 房型 ID |
|
||
| items[].roomCount | Body | Integer | 是 | ≥1 | 房间数 |
|
||
| items[].roomCategory | Body | String | 否 | ≤32 | 房型大类 code;服务端以 resource 权威值覆盖,仅用于前端回显 |
|
||
| items[].protoPrice | Body | BigDecimal | 否 | ≥0 | 协议价快照;不传按「日历价 → 酒店协议价」兜底 |
|
||
| items[].settlementPrice | Body | BigDecimal | 否 | ≥0 | 结算价快照;不传按「日历价 → 协议价」兜底 |
|
||
| items[].settleType | Body | String | 否 | `cash` \| `sign` \| `company` | 结算方式;不传取酒店资源配置 |
|
||
| items[].deductInventory | Body | Boolean | 否 | 默认 true | 是否扣库存 |
|
||
| items[].remark | Body | String | 否 | ≤512 | 备注 |
|
||
| items[].version | Body | Integer | 否 | — | 乐观锁版本;本端点(批量新建)不校验,只有单行修改端点必填并校验 |
|
||
| items[].replaceReason | Body | String | 否 | ≤256 | 替换原因;本端点不使用,仅单行修改端点在语义为"删旧建新"时使用 |
|
||
|
||
#### 出参字段表
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| planId | String | 计划行 ID(雪花 ID,序列化为字符串) |
|
||
| groupBatchId | String | 团期 ID(雪花 ID,序列化为字符串) |
|
||
| stayDate | LocalDate | 入住日期 |
|
||
| hotelId / hotelName | String / String | 酒店 ID(序列化为字符串)及名称 |
|
||
| roomTypeId / roomTypeName | String / String | 房型 ID(序列化为字符串)及名称 |
|
||
| roomCount | Integer | 房间数 |
|
||
| protoPrice | String | 协议价快照,可为 null(BigDecimal,序列化为字符串) |
|
||
| settlementPrice | String | 结算价快照,可为 null(BigDecimal,序列化为字符串) |
|
||
| settleType | String | 结算方式快照,可为 null |
|
||
| planStatus | String | 状态码(PENDING / CONFIRMED) |
|
||
| version | Integer | 乐观锁版本号 |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
POST /v3/admin/house/group-batches/2099918391610314754/room-plans HTTP/1.1
|
||
Host: api.test.1814.love:9443
|
||
Authorization: Bearer <admin token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"items": [
|
||
{
|
||
"stayDate": "2026-10-01",
|
||
"hotelId": 1001,
|
||
"roomTypeId": 5001,
|
||
"roomCount": 2,
|
||
"settlementPrice": 450.00,
|
||
"deductInventory": true,
|
||
"remark": "标准间"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
**成功(已认领团)**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"success": true,
|
||
"data": [
|
||
{
|
||
"planId": "2103794613192208385",
|
||
"groupBatchId": "2099918391610314754",
|
||
"stayDate": "2026-10-01",
|
||
"hotelId": "1001",
|
||
"hotelName": "丽思卡尔顿",
|
||
"roomTypeId": "5001",
|
||
"roomTypeName": "豪华标间",
|
||
"roomCount": 2,
|
||
"settlementPrice": "450.00",
|
||
"planStatus": "PENDING",
|
||
"version": 1,
|
||
"createTime": "2026-09-26 14:30:00"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
**失败(未认领团,超管)**:
|
||
|
||
```json
|
||
{
|
||
"code": 808612,
|
||
"message": "该团期尚未被房务整团认领",
|
||
"success": false,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 空数据 / 降级响应
|
||
|
||
- 参数校验失败(日期格式错、房间数 ≤0):HTTP 200,`code=400`,message 含具体字段文案;不落库。
|
||
|
||
#### 错误响应
|
||
|
||
```json
|
||
{
|
||
"code": 808612,
|
||
"message": "该团期尚未被房务整团认领",
|
||
"success": false,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**其他错误码**:
|
||
- **808090**:未登录或非房务角色,无权操作。
|
||
- **808091**:房务组长为只读监督角色,无权执行该操作(HOUSE_KEEPER_LEAD)。
|
||
- **808613**:该团期由其他房务认领,无权操作。
|
||
- **808600**:团期当前阶段不允许修改订房计划(订房计划仅在配置阶段可改)。
|
||
- **808614**:该入住日在酒店的该房型上已有订房计划,请改用修改单行。
|
||
- **808611**:团期出发日或结束日缺失,无法录入订房计划。
|
||
- **808602**:入住日不在团期出行区间内。
|
||
- **808603**:订房间数必须大于 0。
|
||
- **808691**:无法确定房型大类(取权威房型数据失败),请稍后重试。
|
||
- **808112**:房型不属于该酒店。
|
||
- **100502**:3 秒幂等窗口内重复提交,「订房计划提交处理中,请勿重复提交」。
|
||
|
||
#### 业务边界
|
||
|
||
- **整团认领**:认领人本人或超管可提交;非认领房务提交返回 808613;团未认领(`house_claimer_id IS NULL`)时所有人(含超管)返回 808612。
|
||
- **超管排房出口**:超管要在未认领的团上排房,必须先 `POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/takeover` 指派给房务,再来提交计划。
|
||
- **库存扣减**:`deductInventory=true` 时,CONFIRMED 状态的计划会扣掉 `resource_hotel_room_inventory` 对应房型该日的可用房数;PENDING 阶段不扣。
|
||
- **日期范围**:入住日期必须在团期的出发日期与结束日期之间。
|
||
|
||
---
|
||
|
||
### 2. 释放认领 `POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/release`
|
||
|
||
**VO**: `HouseGroupReleaseReqVO → Result<Void>`
|
||
|
||
#### 使用场景
|
||
|
||
房务释放所有团期认领,团回到抢单池状态(`house_claimer_id → NULL`)。房务有订房计划待处理时返回 808660,文案告知删除计划或联系超管接管两条出口。
|
||
|
||
#### 入参字段表
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||
|------|------|------|------|------|------|
|
||
| groupBatchId | Path | Long | 是 | — | 团期 ID |
|
||
| reason | Body | String | 否 | ≤200 字 | 释放原因;超管必填且不少于 10 字 |
|
||
|
||
#### 出参字段表
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| — | null | 成功返回 null |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
POST /v3/admin/order/grab-pool/group-batches/2099918391610314754/release HTTP/1.1
|
||
Host: api.test.1814.love:9443
|
||
Authorization: Bearer <room_manager token>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"reason": "已完成配房"
|
||
}
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
**成功**:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"success": true,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**失败(有计划待删)**:
|
||
|
||
```json
|
||
{
|
||
"code": 808660,
|
||
"message": "该团仍有 4 条未取消的订房计划,无法释放:请先逐条删除订房计划后再释放;如需更换认领房务请联系超管接管",
|
||
"success": false,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 空数据 / 降级响应
|
||
|
||
不适用。
|
||
|
||
#### 错误响应
|
||
|
||
```json
|
||
{
|
||
"code": 808660,
|
||
"message": "该团仍有 4 条未取消的订房计划,无法释放:请先逐条删除订房计划后再释放;如需更换认领房务请联系超管接管",
|
||
"success": false,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
**其他错误码**:
|
||
- **808655**:该团期不属于当前房务,无法释放;非认领人释放时触发(超管不受此限),CAS 并发失败(读到时归本人、提交时已被超管释放/接管)也报此码。
|
||
- **808656**:该团期尚未被认领,无需释放。
|
||
- **808657**:超管操作原因长度不足 10 字(房务释放时 reason 可为空)。
|
||
- **808090**:未登录或非房务角色,无权操作。
|
||
- **808091**:房务组长为只读监督角色,无权执行该操作(HOUSE_KEEPER_LEAD)。
|
||
|
||
#### 业务边界
|
||
|
||
- **释放前置**:须先删光全部未取消的订房计划(PENDING + CONFIRMED)才能释放;所有角色(含超管)受 808660 约束,release 本身不碰计划行。
|
||
- **幂等**:幂等键按团(`groupBatchId`),窗口 5 秒;窗口内重复提交返回 100502「整团释放处理中,请勿重复提交」。
|
||
|
||
---
|
||
|
||
## 四、契约约束与正确调用方式
|
||
|
||
| 场景 | 调用方法 | 说明 |
|
||
|------|---------|------|
|
||
| ✅ 超管先排房再指派 | 先 `POST /v3/admin/order/grab-pool/group-batches/{id}/takeover` 指派给房务 → 再 `POST .../room-plans` 提交 | takeover 让团被指定房务认领,之后超管仍可在上面操作 |
|
||
| ✅ 房务提交计划 | `POST /v3/admin/house/group-batches/{id}/room-plans` | 认领的房务可随时提交,RESOURCE_PREPARING 阶段有效 |
|
||
| ✅ 房务释放有计划 | 先 `DELETE /v3/admin/house/group-batches/{id}/room-plans/{planId}` 逐条删 → 再 `POST .../release` | 删除由 `HouseGroupBatchClaimGuard` 控制,认领人可删(含他人建的),释放成功返回 200 |
|
||
| ❌ 超管在未认领团直接建计划 | — | 返回 808612,需先 takeover 指派 |
|
||
| ❌ 有计划待删时释放 | — | 返回 808660,不释放;先删后释 |
|
||
|
||
---
|
||
|
||
## 五、数据库行为
|
||
|
||
无表结构变更、无 Flyway 迁移。
|
||
|
||
---
|
||
|
||
## 六、边界行为
|
||
|
||
| 场景 | 行为 |
|
||
|---|---|
|
||
| 超管 POST room-plans on 未认领团 | 返回 808612,`group_batch_room_plan` 零新增 |
|
||
| 超管 takeover 后 POST room-plans | 返回 200,计划行正常落库 |
|
||
| 房务释放、仍有 PENDING 计划 | 返回 808660,计数含 PENDING |
|
||
| 房务删掉全部计划、再释放 | 返回 200,团回到池里 |
|
||
| 超管释放、仍有计划 | 同样返回 808660(不分角色) |
|
||
|
||
## 六.6、修改前后对比
|
||
|
||
| 维度 | 改前 | 改后 |
|
||
|---|---|---|
|
||
| 超管在未认领团上 POST room-plans | 返回 200,计划落库,团仍无主 | 返回 808612,不落库 |
|
||
| 释放时有计划、808660 文案 | 「无法释放(请先处理订房计划或走接管)」 | 「无法释放:请先逐条删除订房计划后再释放;如需更换认领房务请联系超管接管」 |
|
||
|
||
## 六.7、影响评估
|
||
|
||
- **兼容性**:hl-ui 在 `origin/v2.1` 上房务页面无调用 `takeover`(该接口仍在,超管直接用也可以);超管排房流程可能需要调整为"先指派再排"。
|
||
- **前端要动的**:房务页面若有"直接排房"的超管入口,需提示"未认领团先指派再排";释放时若遇到 808660,按改后文案提示房务删除计划。
|
||
- **数据影响**:无;本单仅加守卫,不改历史数据。
|
||
- **其它服务**:product-v2、fleet、user-service 无改动。
|
||
|
||
---
|
||
|
||
## 七、不影响范围
|
||
|
||
- 已认领团的超管操作(确认、分房、delete 等)全部不动。
|
||
- 更新/删除/确认计划的守卫不动(仍走 `assertWritableByCurrentUser`,超管仍可清理)。
|
||
- 其他团期相关接口(认领、接管、整团确认等)无改动。
|
||
|
||
---
|
||
|
||
## 八、测试环境已验证
|
||
|
||
部署:测试环境 order-v3 `1f65d7894`(含 e2313790b)。网关 `api.test.1814.love:9443`。
|
||
|
||
| # | 场景 | 实测结果 |
|
||
|---|---|---|
|
||
| 1 | 超管 POST 未认领团(RESOURCE_PREPARING) | code 808612,计划行零新增 |
|
||
| 2 | 该团由超管 takeover 给某房务后,超管再 POST | code 200 |
|
||
| 3 | 超管 DELETE 上一步新增的计划行 | code 200,`releasedLogId=null` |
|
||
| 4 | 该房务 release | code 200,团回到无主 |
|
||
| 5 | 另一认领房务逐条 DELETE 自己团的 4 条 PENDING 计划 | 全部 200(`releasedLogId=null`) |
|
||
| 6 | 上一步之后 release | code 200 |
|
||
| 7 | 超管对他人认领团的存量计划行 DELETE(62 行) | 全部 200 |
|
||
| 8 | 认领房务在团上挂 1 条 PENDING 计划时 release | code 808660,message「该团仍有 1 条未取消的订房计划,无法释放:请先逐条删除订房计划后再释放;如需更换认领房务请联系超管接管」,与源码逐字一致 |
|
||
| 9 | 删掉该计划后再 release | code 200,团回到无主 |
|
||
|
||
---
|
||
|
||
## 十、相关文档
|
||
|
||
- Issue:https://git.1814.love/wx/HL/issues/8385
|
||
- PR:https://git.1814.love/wx/HL/pulls/8395
|
||
- takeover API:`POST /v3/admin/order/grab-pool/group-batches/{groupBatchId}/takeover`
|
||
- 同批单号:#8386、#8387、#8388、#8389、#8390(房务接口审计批次)
|
||
|
||
---
|
||
|
||
## 关联 / 联系人
|
||
|
||
### 联系人
|
||
|
||
- **后端负责人**: @wx
|