349 行
18 KiB
Markdown
349 行
18 KiB
Markdown
---
|
||
schema: "hl-changelog/v2"
|
||
ticket: "8330"
|
||
title: "团期整团确认预检新增车侧缺失原因 MEMBER_GROUP_MISMATCH(809125):户级报的车型与覆盖它的乘车分组车型不符时拒绝放行"
|
||
consumer: "admin"
|
||
author: "wx(GIT)"
|
||
change_type: "修改接口"
|
||
backend_status: "deployed"
|
||
gateway_status: "verified"
|
||
frontend_status: "verified"
|
||
frontend_owner: "mmg"
|
||
frontend_ref: "8785efa8c1ae711648be2016781a1fb63dc6a5c5"
|
||
target_release: "v2.1"
|
||
verified_at: "2026-09-24"
|
||
status_note: "PR #8334 squash 合并 dev-v3(39d21cd4f)。部署:hl-order-service-v3 dev-v3 @ 2b4656424(2026-09-24 14:02 滚动部署两实例)。测试服网关实测(groupBatchId=2102981652823302146,生效正式需求 CONFIRMED v4:BUS=[丙]、MPV=[甲,乙];甲已把户级 TRAVEL 需求改成 bus 并放行):GET requirement/confirm-check → ready=false,vehicleMissing 新增一条 reason=MEMBER_GROUP_MISMATCH、orderId=甲、detail=该户报的车型为 bus,但覆盖它的乘车分组(MPV)车型为 mpv,没有车型相符的分组,请重新汇总后保存正式用车需求;同刻 POST requirement/confirm 在原 809109 上先被拒(该团期另有未覆盖户)。改前同一位置 vehicleMissing=[]、ready=true。定向单测 141 绿(CheckVehicleTest 20 / ConfirmVehicleTest 18 / GroupBatchRequirementServiceTest 73 / GroupVehicleRequirementConfirmCheckTest 30)。判据保守 fail-open:户级车型集合为空、分组车型归一失败、无活跃正式需求一律跳过,历史自由文本脏值不会误报。 | 2026-09-24 mmg 交付:实证 RequirementTab vehicleMissing 链路开箱即用(detail 直显+ready 置灰+orderNo 点击定位)零 UI 改动;orderV2GroupBatch.js JSDoc 补 reason 口径;spec 31 例全绿(新增 1 例回归锁)"
|
||
updated_at: "2026-09-24"
|
||
base: "dev-v3"
|
||
---
|
||
|
||
# order-v3 团期需求: 新增 MEMBER_GROUP_MISMATCH(809125)车型-分组一致性预检
|
||
|
||
> **存放目录**: 二期(v3) → `changelogs-v2/2026-09/`
|
||
>
|
||
> **服务**: hl-order-service-v3(团期需求域,groupbatch 包)
|
||
> **PR**: https://git.1814.love/wx/HL/pulls/8334
|
||
> **Issue**: #8330
|
||
> **日期**: 2026-09-24
|
||
> **影响范围**: 管理后台「团期详情 → 查看需求」Tab 的整团确认预检与整团确认
|
||
|
||
---
|
||
|
||
## ⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写)
|
||
|
||
- **新增车侧缺失原因 `MEMBER_GROUP_MISMATCH` 与错误码 809125**:户级 TRAVEL 需求改成另一种车型并放行后,若该户仍落在**车型不符**的分组里,整团确认预检会点名该户,`ready=false`;整团确认也会被拒。
|
||
- **这是「补盲区」而不是「加新规则」**:既有的 809109 只问「该户的每一天有没有落在**某个**分组里」,不问「那个分组是不是这户要的车型」。户改了车型却仍在原分组 `memberOrderIds` 里时,809109 恒通过,一份与户级现状不符的正式需求会被放给车务。
|
||
- **判据保守、fail-open**:只有当「该户报的车型集合」与「覆盖它的分组车型集合」**交集为空**时才报;任一集合为空(没报车型 / 不在任何分组里 / 分组车型归一不出来)一律跳过。历史脏值(自由文本车型、车型列未填的存量分组)不会被误报成不一致。代价是「说不清」的数据继续不报——漏报只是少一道提醒,误报会卡死整团确认。
|
||
- **不自动改数据、不新增状态**:不改 `GroupVehicleCoverage`、不改车辆需求状态机、不回退已配车辆、不动 fleet 侧 `readiness`。处置是把不一致摆给团期管理员,由管理员「重新汇总并保存正式用车需求」收敛。
|
||
- **前端必须展示新 reason**:`vehicleMissing[]` 目前只有 `OrderNo` 与 `orderId`,页面已把 `orderNo` 拼在 `detail` 之前,报文里不再带雪花 id;新 reason 的处置动作已写死在 `detail` 尾句。
|
||
|
||
---
|
||
|
||
## 一、背景(选填)
|
||
|
||
团期需求是「户级提交 → 团期管理员审核放行 → 团级汇总成正式需求 → 车务按正式需求配车」四段结构。户级需求在配置完成后仍会被改(客人换车型、加人加车、临时改行程),这是常态。房务侧对这条路径已有完整回退(`BATCH_ROOM_PLAN_BASELINE_RECONFIRMED` + `hotelReady` 回落 + 逐日 mismatch + 分房 stale),车务侧此前缺这一半:实测把某户由 `mpv 7 座` 改成 `bus 16 座` 并放行后,生效版本仍写着该户在 MPV 组,而 `aggregate-draft` 已把它算进 BUS 组,两份数字互相矛盾却全程零提示,`readiness` 仍 `ready=true`。本单落**方案②**(零 DDL、只做可见性),方案①(新增「过时」标记 + fleet 硬拦 + 配车完成回退)改动面大,留待产品决策。
|
||
|
||
---
|
||
|
||
## 二、变更接口清单
|
||
|
||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||
|---|------|------|------|----------|------|
|
||
| 1 | 整团确认预检 | GET | `/v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check` | 响应新增枚举值 | `vehicleMissing[].reason` 新增 `MEMBER_GROUP_MISMATCH`,对应 809125 |
|
||
| 2 | 整团确认 | POST | `/v3/admin/order/group-batch/{groupBatchId}/requirement/confirm` | 行为变更(同一判据) | 与预检同源,存在该缺失时整团确认被拒(不再静默通过) |
|
||
|
||
---
|
||
|
||
## 三、接口详情
|
||
|
||
### 1. 整团确认预检 `GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check`
|
||
|
||
**VO**: `GroupBatchRequirementCheckRespVO`
|
||
|
||
#### 使用场景
|
||
|
||
团期详情「查看需求」Tab 打开或点「整团确认」前的只读预检。权限 `group-batch:demand:confirm`。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||
|------|------|------|------|------|------|
|
||
| groupBatchId | Path | Long | ✅ | - | 团期聚合主键(不是产品班期 ID) |
|
||
|
||
#### 出参 `Result<GroupBatchRequirementCheckRespVO>`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| ready | Boolean | 是否可整体确认;本次起在「车型-分组不一致」时为 false |
|
||
| vehicleMissing[] | Array | 车侧缺失项;本次新增 `MEMBER_GROUP_MISMATCH` |
|
||
| vehicleMissing[].reason | String | 原因码,取值见「六.5」 |
|
||
| vehicleMissing[].orderId / orderNo | String / String | 涉及的子订单(雪花 ID 按字符串处理) |
|
||
| vehicleMissing[].groupCode / tripDate | String / LocalDate | 本原因这两项恒为 null(分歧在「组选错了」,不在某一天) |
|
||
| vehicleMissing[].detail | String | 人话描述,与整团确认抛出的错误报文逐字相同,可直接展示 |
|
||
| groupVehicleRequirementId / Status / Version | String / String / Integer | 当前生效正式需求的身份,`detail` 里照旧不出现 |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
GET /v3/admin/order/group-batch/2102981652823302146/requirement/confirm-check
|
||
Authorization: Bearer <admin token>
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"data": {
|
||
"groupBatchId": "2102981652823302146",
|
||
"batchStatus": "RESOURCE_PREPARING",
|
||
"batchStatusName": "资源准备中",
|
||
"ready": false,
|
||
"missing": [],
|
||
"checkedResourceTypes": ["HOTEL", "VEHICLE"],
|
||
"vehicleWaived": false,
|
||
"vehicleMissing": [
|
||
{
|
||
"reason": "MEMBER_GROUP_MISMATCH",
|
||
"groupCode": null,
|
||
"tripDate": null,
|
||
"orderId": "2102981652680695809",
|
||
"orderNo": "HL20260924124112051",
|
||
"detail": "该户报的车型为 bus,但覆盖它的乘车分组(MPV)车型为 mpv,没有车型相符的分组,请重新汇总后保存正式用车需求"
|
||
}
|
||
],
|
||
"vehicleExemptHouseholds": [],
|
||
"groupVehicleRequirementId": "2102982327141556225",
|
||
"groupVehicleRequirementStatus": "CONFIRMED",
|
||
"groupVehicleRequirementVersion": 4
|
||
},
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
#### 空数据 / 降级响应
|
||
|
||
- 一切正常时 `vehicleMissing: []`、`ready: true`,接口仍 200。
|
||
- 该户没报车型、不在任何分组里、分组车型归一不出来(自由文本 / 车型列未填)时**跳过本判据**,不报 809125(fail-open)。
|
||
- 团期还没有生效中的正式需求时不报本判据。
|
||
|
||
```json
|
||
{ "code": 200, "message": "成功", "data": { "ready": true, "vehicleMissing": [] }, "success": true }
|
||
```
|
||
|
||
#### 错误响应
|
||
|
||
本端点只读,业务失败以 `result` 包裹在 HTTP 200 内;本单不新增抛错分支。
|
||
|
||
```json
|
||
{ "code": 200, "message": "成功", "data": { "ready": false, "vehicleMissing": [{ "reason": "MEMBER_GROUP_MISMATCH" }] }, "success": true }
|
||
```
|
||
|
||
#### 业务边界
|
||
|
||
- 判据是「该户 `fleet[].vehicleType` 归一后的集合」与「逐日覆盖它的那些分组的 `vehicleType` 集合」**交集为空**;只要有一个分组车型相符就不报。
|
||
- 与 809109 互补且不重叠:809109 管「不在任何分组里」,809125 管「在分组里但组选错了」。
|
||
- 一个户最多报一条(不分天、不分组)。
|
||
- 报文不含雪花 id,由页面用清单行自带的 `orderNo` 定位;`detail` 尾句已写死处置动作。
|
||
|
||
---
|
||
|
||
### 2. 整团确认 `POST /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm`
|
||
|
||
**VO**: `GroupBatchRequirementCheckRespVO`(确认口无请求体,与预检同源判据)
|
||
|
||
#### 使用场景
|
||
|
||
团期管理员点「整团确认」,把各户需求汇总成正式需求并放行给车务。权限同上。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||
|------|------|------|------|------|------|
|
||
| groupBatchId | Path | Long | ✅ | - | 团期聚合主键 |
|
||
|
||
#### 出参 `Result<...>`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| requirementConfirmed | Boolean | 本次是否完成整体确认;被拒时不返回该结构 |
|
||
| vehicleDispatchedOrderIds | Array<String> | 本次被放行的户 |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
POST /v3/admin/order/group-batch/2102981652823302146/requirement/confirm
|
||
Authorization: Bearer <admin token>
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{ "code": 200, "message": "成功", "data": { "requirementConfirmed": true }, "success": true }
|
||
```
|
||
|
||
#### 空数据 / 降级响应
|
||
|
||
确认链路与预检读同一份快照;预检不报 809125 时确认也不会报。
|
||
|
||
```json
|
||
{ "code": 200, "message": "成功", "data": { "requirementConfirmed": false }, "success": true }
|
||
```
|
||
|
||
#### 错误响应
|
||
|
||
```json
|
||
{
|
||
"code": 809125,
|
||
"message": "该户报的车型为 bus,但覆盖它的乘车分组(MPV)车型为 mpv,没有车型相符的分组,请重新汇总后保存正式用车需求",
|
||
"success": false,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 业务边界
|
||
|
||
- 确认按「第一条缺失」抛出,异常顺序为:团级六条 → 户级未提交(809122)→ 接送机未回填(809007)→ **车型不符(809125)**。排在 809122 之后是因为「重新汇总」本身会被未提交户的 809121 挡住,先催未提交的户才有意义。
|
||
- 本原因不改变任何既有场景下「确认抛第一条」抛出的那一码。
|
||
- 整团确认成功后正式需求会被重新汇总保存,管理员再次触发时本原因自然消失(状态收敛)。
|
||
|
||
---
|
||
|
||
## 四、契约约束与正确调用方式(接口类必写)
|
||
|
||
- `reason` 是**稳定的机器可判值**,前端按它分支渲染;`detail` 只用于直接展示,**不要解析 `detail`**。
|
||
- `vehicleMissing` 的顺序即处置顺序:先处理靠前的条目再刷新预检。
|
||
- 页面在 `ready=false` 时不得放开「整团确认」按钮;即便放开,服务端也会以同一判据返回 809125。
|
||
|
||
### ✅ 正确 / ❌ 错误处置对照
|
||
|
||
```text
|
||
✅ ready=false 且含 MEMBER_GROUP_MISMATCH → 走「自动汇总」→ 检查车型分组 → 保存正式用车需求 → 重新预检
|
||
❌ ready=false 却直接点整团确认 → 809125(HTTP 200 业务失败)
|
||
❌ 只改团级分组的 remark / 座位数就再保存 → 分组归属不变,本原因不会消失
|
||
```
|
||
|
||
### 切换状态时的必要动作
|
||
|
||
- 重新汇总并保存后正式需求进入 DRAFT 且 version +1,车务需按新版本重新配车确认(既有语义,未变)。
|
||
|
||
---
|
||
|
||
## 五、数据库行为(涉及写操作时必写)
|
||
|
||
- 无表结构变更、无 Flyway。
|
||
- 本原因的判定发生在**写库之前**:整团确认抛 809125 时零写入(正式需求版本、状态、分组均不变,可回读确认)。
|
||
|
||
---
|
||
|
||
## 六、边界行为
|
||
|
||
- 存量数据不批量重算:历史自由文本车型 / 车型列未填的分组继续不报(fail-open)。
|
||
- 判据只在团级读面(`confirm-check` / `confirm`)生效;车务 `readiness` 与配车行不动。
|
||
- 车主车型与乘车分组都是多值时取集合,任一相交即视为一致。
|
||
|
||
---
|
||
|
||
## 六.5、枚举 / 数据字典(接口出现枚举时必写)
|
||
|
||
| reason | 错误码 | 触发 | 报文 |
|
||
|---|---|---|---|
|
||
| `MEMBER_GROUP_MISMATCH` | 809125 | 该户报的车型与覆盖它的分组车型无交集 | 该户报的车型为 {0},但覆盖它的乘车分组({1})车型为 {2},没有车型相符的分组,请重新汇总后保存正式用车需求 |
|
||
| `ORDER_DAY_UNCOVERED`(不变) | 809109 | 该户某天不在任何分组里 | 该子订单的 {0} 没有被任何乘车分组覆盖 |
|
||
| `HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED`(不变) | 809122 | 户级根本没提交 | 见既有条目 |
|
||
|
||
---
|
||
|
||
## 六.6、修改前后对比(修改/删除类接口必写,新增跳过)
|
||
|
||
### 字段级对比
|
||
|
||
| 字段 | 改前 | 改后 |
|
||
|------|------|------|
|
||
| `confirm-check` 请求/响应字段 | — | 无新增、无删除;`vehicleMissing[].reason` 多一个取值 |
|
||
| `vehicleMissing` 条数 | — | 最多每户多一条 |
|
||
|
||
### 行为级对比
|
||
|
||
| 行为 | 改前 | 改后 |
|
||
|------|------|------|
|
||
| 户改车型并放行、该户仍在旧车型分组里 | 预检 `ready=true`、`vehicleMissing=[]`;整团确认静默通过 | 预检 `ready=false` 并点名该户;整团确认 809125 拒绝 |
|
||
| 户改车型但新车型有相符分组 | 通过 | 通过(不变) |
|
||
| 户没报车型 / 分组车型归一不出来 | 通过 | 通过(fail-open 跳过) |
|
||
| 团级分组与户级完全一致 | 通过 | 通过(不变) |
|
||
|
||
---
|
||
|
||
## 六.7、影响评估(修改/删除类必写)
|
||
|
||
- **是否破坏向后兼容**:响应结构不变,但**同一场景下 `ready` 可能由 true 变 false、`confirm` 可能由 200 变 809125**。凡「户级车型与覆盖分组车型无交集」的团期都会被拒,直到管理员重新汇总保存。
|
||
- **前端是否必须同步上线**:**建议同批**。不同步时新 reason 会以未知值出现在清单里(`detail` 已是完整人话,仍可展示),但页面若只看 `ready` 就足以正确禁用确认按钮。
|
||
- **存量数据影响**:不批量重算、不迁移;只有下一次预检 / 确认才会暴露。
|
||
- **上线风险**:判据 fail-open,历史脏值不会误报;但车型与分组确实不一致的团期会在确认时被拦,需要管理员走一次「重新汇总并保存」。
|
||
|
||
---
|
||
|
||
## 七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
|
||
|
||
- **仅影响**:`GET .../requirement/confirm-check` 的 `ready` / `vehicleMissing`;`POST .../requirement/confirm` 的拒绝条件。
|
||
- **零影响**:
|
||
- 车务 `GET /admin/fleet/group-dispatch/batches/{gb}/readiness`(方案①范围,本单不做)。
|
||
- 配车行、已配车辆、「已配车辆不动」语义。
|
||
- 团级六条既有校验、809116 / 809118 / 809119 / 809120 / 809121 / 809122 / 809007 等其余判据与报文。
|
||
- `GET .../vehicle-requirement`、`aggregate-draft`、`vehicle-households`、`requirement-summary`。
|
||
- 子订单级用车需求与 `GroupVehicleCoverage`。
|
||
- 数据库、网关路由、fleet 服务代码。
|
||
|
||
---
|
||
|
||
## 八、测试环境已验证
|
||
|
||
**部署读数**:`hl-order-service-v3` dev-v3 @ `2b4656424`,2026-09-24 14:02 滚动部署两实例(8086/8186 均 UP)。
|
||
|
||
**网关真实请求与响应**(`https://api.test.1814.love`,`groupBatchId=2102981652823302146`,生效正式需求 CONFIRMED v4:BUS=[丙]、MPV=[甲,乙];甲 `2102981652680695809` 的户级 TRAVEL 需求已改成 `bus 16 座` 并放行):
|
||
|
||
```text
|
||
① GET /v3/admin/order/group-batch/2102981652823302146/requirement/confirm-check
|
||
→ http 200, code=200, ready=false
|
||
vehicleMissing 含一条:
|
||
reason=MEMBER_GROUP_MISMATCH, orderId=2102981652680695809, orderNo=HL20260924124112051
|
||
detail=该户报的车型为 bus,但覆盖它的乘车分组(MPV)车型为 mpv,没有车型相符的分组,请重新汇总后保存正式用车需求 ✓
|
||
|
||
② 同刻 POST .../requirement/confirm → 被既有 809109 先拦(该团期另有一户不在任何分组里),
|
||
说明 809125 已并入同一条缺失链且不改变「确认抛第一条」的既有语义 ✓
|
||
|
||
改前同位置读数(2026-09-24 13:03,同一团期同一数据):ready=true、vehicleMissing=[] ✓
|
||
```
|
||
|
||
**定向测试逐类读数**(`mvn -o -pl hl-order-service-v3 -am test -Dtest='…' -DfailIfNoTests=false -Dhl.surefire.failIfNoTests=false`,4 个类合计 141 绿):
|
||
|
||
| 测试类 | Tests run |
|
||
|---|---|
|
||
| GroupVehicleRequirementConfirmCheckTest | 30 |
|
||
| GroupBatchRequirementServiceTest | 73 |
|
||
| GroupBatchRequirementServiceCheckVehicleTest | 20 |
|
||
| GroupBatchRequirementServiceConfirmVehicleTest | 18 |
|
||
|
||
---
|
||
|
||
## 十、相关文档
|
||
|
||
- 户级未提交(809122)先例:#8249 → `changelogs-v2/2026-09/`
|
||
- 逐日覆盖校验 809109:#8235 → `changelogs-v2/2026-09/`
|
||
- 团级座位档位校验 809124:#8311 → `changelogs-v2/2026-09/24_8311_团期分组座位数改档位下拉与809124校验-修改接口-管理后台.md`
|
||
- 房侧同源回退(对照实现):`BATCH_ROOM_PLAN_BASELINE_RECONFIRMED`
|
||
|
||
---
|
||
|
||
## 关联 / 联系人
|
||
|
||
### 链接
|
||
|
||
- Issue: https://git.1814.love/wx/HL/issues/8330
|
||
- 后端 PR: https://git.1814.love/wx/HL/pulls/8334
|
||
|
||
### 联系人
|
||
|
||
- 后端: wx
|