docs(changelog): 房务接口审计批次 #8385~#8390 交接件
changelog-filename-gate / validate (push) Failing after 3s

- #8385 团期订房计划建守卫(未认领团 808612)与 808660 释放文案
- #8386 住宿 supplier-reject 加角色门与认领校验,车务 supplier-reject 下线
- #8387 下线订单侧房间分配三口 /v3/admin/order/{id}/room
- #8388 最终确认回执上传加认领校验、列表加读门、808184 带具体原因
- #8389 下线 POST /v3/admin/order/assignments/{assignmentId}/rooms
- #8390 房务 16 个只读端点加角色读门,ADMIN 房务菜单撤授

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
这个提交包含在:
API Changelog Bot
2026-09-26 23:52:47 +08:00
共同撰写人 Claude Opus 5.5
父节点 1a396aece5
当前提交 88caa74d34
共修改 6 个文件,包含 2977 行新增和 0 行删除
@@ -0,0 +1,331 @@
---
schema: "hl-changelog/v2"
ticket: "8386"
title: "住宿需求驳回:加房务角色门与认领人校验;车务驳回接口下线"
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: "住宿需求供应方驳回新增房务角色门(808090/808091)与认领人校验(808110/808116,超管豁免);车务驳回接口删除,调用返回 HTTP 200 + code 404。已在测试环境网关实测各角色分支与已删除端点响应。"
updated_at: "2026-09-26"
base: "dev-v3"
---
# order-v3:住宿需求驳回守卫加固与车务驳回下线(管理后台)
**服务**: hl-order-service-v3
**PR**: #8397
**Issue**: #8386
---
## ⚠️ 关键变化
1. **住宿需求供应方驳回** `POST /v3/admin/order/{id}/hotel-requirement/supplier-reject`:
- 新增房务角色门:`@HouseWriteGuarded`,非房务角色返回 **808090**,房务组长返回 **808091**。
- 新增认领人校验:需求必须被当前操作人认领,否则返回 **808110**(非本人)/ **808116**(未认领,仅超管可驳)。
- 超管可绕过认领限制(跳过本人限制,但仍受角色门约束)。
2. **车务需求供应方驳回** `POST /v3/admin/order/{id}/vehicle-requirement/supplier-reject` **已下线**:
- 端点删除,调用返回 404。
- hl-ui 全部远程 ref 零调用,车务侧无此功能。
---
## 一、背景
### 住宿驳回
API-SPEC §2.8 与 CHANGELOG v6.3.8 均明文「新增房务/超管可用的住宿需求驳回端点」,但实现漏了角色门和认领人校验:
- 任意 ADMIN token 的后台账号(包括车控、定制师)都能驳回任意订单的需求。
- 测试服已实证车控账号(VEHICLE_MANAGER)成功打回住宿需求两次。
- 同类操作(转单、释放、提交配房)都带认领人校验,驳回不带属于遗漏。
- 打回副作用重:需求行终态失活、flow 回退、定制师开返工待办 + 站内信。
### 车务驳回
车务从无"抢单 → 认领"的流程,用车需求也从不写入抢单人:整个车务侧"我的接单"接口(#8373)因此下线。供应方驳回同样是"假接口"——没有实际用途、hl-ui 零调用。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 住宿需求供应方驳回 | POST | `/v3/admin/order/{id}/hotel-requirement/supplier-reject` | 修改接口 | 新增角色门(808090/808091)与认领人校验(808110/808116) |
| 2 | 车务需求供应方驳回 | POST | `/v3/admin/order/{id}/vehicle-requirement/supplier-reject` | 删除接口 | 端点已删除,调用返回 404 |
---
## 三、接口详情
### 1. 住宿需求供应方驳回 `POST /v3/admin/order/{id}/hotel-requirement/supplier-reject`
**VO**: `RejectReqVO → Result<Void>`
#### 使用场景
房务(ROOM_MANAGER)或超管在配房面板「驳回需求」,把已认领的住宿需求打回给定制师,触发返工。仅认领人或超管可操作;非房务角色返回权限错误。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| id | Path | Long | 是 | — | 订单 ID |
| returnRemark | Body | String | 是 | `@NotBlank`,≤500 字 | 驳回原因,不能为空 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| — | null | 成功返回 null |
#### 请求示例
```http
POST /v3/admin/order/770145/hotel-requirement/supplier-reject HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <room_manager token>
Content-Type: application/json
{
"returnRemark": "房型不符,请调整"
}
```
#### 响应示例
**成功**:
```json
{
"code": 200,
"message": "成功",
"success": true,
"data": null
}
```
**失败(非认领人)**:
```json
{
"code": 808110,
"message": "需求不属于当前用户",
"success": false,
"data": null
}
```
**失败(无房务权限)**:
```json
{
"code": 808090,
"message": "未登录或非房务角色,无权操作",
"success": false,
"data": null
}
```
#### 空数据 / 降级响应
- `returnRemark` 缺失或为空白:`@Valid` 校验不通过,HTTP 200 + `code: 400` + 具体字段错误信息(不进入业务逻辑)。
#### 错误响应
```json
{
"code": 400,
"message": "打回/驳回备注不能为空",
"success": false,
"data": null
}
```
**校验顺序**(前一道不过不会走到后一道):写门(808090/808091)→ 参数校验(400)→ 582031(无生效需求行)→ 582083(需求状态不允许此操作)→ 认领人校验(808116/808110,超管豁免)→ 582086(已有生效配房不可驳回)→ 582083(并发 CAS 失败)。
**其他错误码**:
- **808090**:未登录或非房务角色,无权操作。
- **808091**:房务组长为只读监督角色,无权执行该操作。
- **582031**:订单无有效需求行。
- **582083**:需求状态不允许此操作,请检查当前状态(团期订单只放行 PENDING/PROCESSING;非团期订单放行 PENDING/PROCESSING/PENDING_REVIEW;并发 CAS 失败同样报此码)。
- **808116**:订单未抢单, 请先抢单再配房(需求未被认领,非超管不可驳)。
- **808110**:需求不属于当前用户(已被他人认领,非超管不可驳)。
- **582086**:该需求已有配房记录, 不能驳回, 请走替换/修改配房。
#### 业务边界
- **认领限制**:需求 `claimer_id` 必须等于当前操作人,或当前角色为 SUPER_ADMIN。房务组长(house_keeper_lead)无法驳回,返回 808091。
- **超管豁免**:SUPER_ADMIN 绕过认领人限制(不受 808110/808116 约束),但仍受角色门约束(必须先过 `@HouseWriteGuarded`)。
- **副作用**:驳回目标状态按订单类型区分——核心/定制订单需求驳回后进 `REJECTED_TO_CONSULTANT`,团期订单进 `REJECTED_TO_ADMIN`;触发返工待办与站内信。
- **转单后生效**:若需求在驳回前被转单给其他房务,原持有人的驳回请求返回 808110(当前 `claimer_id` 已是新认领人)。
- **已有配房记录不可驳回**:需求已生成生效配房(`hasActiveHotelAssignmentsByOrder` 为真)时返回 582086,须走替换/修改配房而非驳回。
---
### 2. 车务需求供应方驳回 `POST /v3/admin/order/{id}/vehicle-requirement/supplier-reject`
**VO**: `已删除`
**状态:已删除**
#### 使用场景
该接口已删除,不可用。
#### 入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|------|------|------|------|------|------|
| — | — | — | — | — | 已删除 |
#### 出参字段表
| 字段 | 类型 | 说明 |
|------|------|------|
| — | — | 已删除 |
#### 请求示例
```http
POST /v3/admin/order/770145/vehicle-requirement/supplier-reject HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <admin token>
Content-Type: application/json
{}
```
#### 响应示例
HTTP 状态码 **200**(非 404),业务错误码 404:
```json
{
"code": 404,
"message": "接口不存在: POST /v3/admin/order/770145/vehicle-requirement/supplier-reject",
"success": false,
"data": null
}
```
#### 空数据 / 降级响应
不适用(路由已删)。前端应只判 `code`,不依赖 HTTP 状态码。
#### 错误响应
```json
{
"code": 404,
"message": "接口不存在: POST /v3/admin/order/770145/vehicle-requirement/supplier-reject",
"success": false,
"data": null
}
```
#### 业务边界
- 接口已删除,路由不存在;调用返回 HTTP 200 + `code: 404`(不是 HTTP 404),前端只判 `code`。
- hl-ui 全部远程 ref 零调用;测试网关 nginx 日志 2026-09-12~09-26 窗口内该路径 19 次调用全部来自脚本(Python-urllib / curl / 空 UA),零浏览器 UA。
---
## 四、契约约束与正确调用方式
| 场景 | 调用方法 | 说明 |
|------|---------|------|
| ✅ 认领人驳回 | `POST /v3/admin/order/{orderId}/hotel-requirement/supplier-reject` | 该订单的认领房务直接调,返回 200;定制师开返工待办 |
| ✅ 超管代驳 | 同上(SUPER_ADMIN 身份)| 超管跳过认领限制,但仍需房务角色权限 |
| ✅ 订单详情按钮 | 查看 `actions.canRejectRequirement` | enabled 取决于 write 权限 + 认领人判定;false 时显示 disabledReason |
| ❌ 非认领人驳回 | — | 返回 808110,需求 status 不变 |
| ❌ 车务驳回 | — | 端点已删除,返回 HTTP 200 + code 404 |
| ❌ 定制师驳回 | — | 返回 808090 |
---
## 五、数据库行为
无表结构变更、无 Flyway。
---
## 六、边界行为
| 场景 | 行为 |
|---|---|
| 认领人驳回 | 返回 200,需求进 REJECTED_TO_CONSULTANT 或 REJECTED_TO_ADMIN |
| 非认领人驳回 | 返回 808110,需求 status 不变 |
| 未认领需求 + 房务驳回 | 返回 808116,非超管不可驳 |
| 超管驳回未认领 | 返回 200,驳回处理 |
| 转单中驳回(原认领人) | 返回 808110(新认领人接管后视为他人所有) |
| 车务驳回 | 返回 HTTP 200 + code 404,无新增副作用 |
## 六.6、修改前后对比
| 维度 | 改前 | 改后 |
|---|---|---|
| 车控账号调住宿驳回 | 返回 200,需求打回 | 返回 808090,需求 status 不变 |
| 非认领人驳回 | 返回 200,需求打回 | 返回 808110,status 不变 |
| 未认领需求 | 任意房务可驳 | 仅超管可驳,返回 808116 |
| 车务驳回 | 路由存在,可调用 | 路由删除,返回 HTTP 200 + code 404 |
## 六.7、影响评估
- **兼容性**:hl-ui 房务驳回按钮的 `enabled` 判定由 `canRejectRequirement` 决定(已包含写权限与认领人两个维度),驳回失败收 808090/808091/808110/808116 四个新码。
- **前端要动的**:
- 驳回按钮的 disabled 文案区分「无房务权限」(808090/808091)与「非本人认领」(808110)。
- 处理 808116「未认领,仅超管可驳」的提示(普通房务不应遇到,因为按钮本身 disabled)。
- 车务不再有驳回端点,移除 vehicle-requirement/supplier-reject 调用。
- **数据影响**:无;仅加守卫,不改历史。
- **其它服务**:fleet 的 `rejectVehicleRequirementFromFleet` 独立存在,本单不动。
---
## 七、不影响范围
- 团期管理员的 dispatch/reject(走独立 `GroupBatchPermissionGuard`),无改动。
- 转单、释放、提交配房等其他配房写操作,无改动。
- 车务用车需求的其他接口(提交、放行、派单),无改动。
- 整团认领释放等认领链路,无改动。
---
## 八、测试环境已验证
部署:测试环境 order-v3 `1f65d7894`(含 e2313790b)。网关 `api.test.1814.love:9443`。
| # | 场景 | 实测结果 |
|---|---|---|
| 1 | VEHICLE_MANAGER 调住宿 supplier-reject | code 808090,需求状态不变 |
| 2 | house_keeper_lead 调住宿 supplier-reject | code 808091,需求状态不变 |
| 3 | 非认领 ROOM_MANAGER(需求已被他人认领)驳回 | code 808110,需求状态不变 |
| 4 | ROOM_MANAGER 对未认领需求驳回 | code 808116,需求状态不变 |
| 5 | 超管打回 / 认领人打回自己认领的需求 | 成功,核心订单需求进 REJECTED_TO_CONSULTANT |
| 6 | 车务 `POST /v3/admin/order/{id}/vehicle-requirement/supplier-reject` | HTTP 200 + code 404「接口不存在: POST <URL>」 |
调用来源:测试网关 nginx 日志 2026-09-12~09-26 窗口内车务 supplier-reject 共 19 次,全部是脚本(Python-urllib / curl / 空 UA),零浏览器 UA;hl-ui 全部远程 ref 零调用。
---
## 十、相关文档
- Issue:https://git.1814.love/wx/HL/issues/8386
- PR:https://git.1814.love/wx/HL/pulls/8397
- 相关单号:#8373(车务我的接单下线)、#8388(回执认领人校验同口径)
- API-SPEC:`docs/order-v3/api/API-SPEC-HOUSE-V1.1.html` §2.8
---
## 关联 / 联系人
### 联系人
- **后端负责人**: @wx