changelog-filename-gate / validate (push) Failing after 2s
三份都是既有条目(#8576/#8601 由 da562f3 批次产出,#8577 单独产出),本次逐条对源码与
测试服实测记录核对后订正,不新增条目。
#8576
- frontend_status 由 not_required 改回 pending(ca26be4 批量置位)。依据:hl-ui
origin/v2.1 确有 src/api/fleet/group-dispatch.js 消费 reconfigure / confirm 两个端点,
而全仓 specWarnings 命中数为 0 —— 新字段目前无人渲染,车辆规格提醒对车务不可见。
改判原因已按 FRONTEND_CONSUMPTION_STATUS_GUIDE 要求写进 status_note。
- 两处错误响应示例的 message 是编造的,换成 GroupDispatchAdminErrorCode 的真实模板。
- planVersion 出参类型 Integer/Long 统一为 Long(两张表)。
#8601
- 删掉四处「589535 适用于本端点」的错误断言。实证:RequirementService.java:4749 对
resourceType=VEHICLE 硬编码 hasActiveAssignments=false,该码在车需求打回上结构性不可达。
- 编造的订单 ID 2099459272533323777 换成实测的 2105173274755534850(dispatch)与
2105173313083080706(reject)。
- 错误码集合订正为 809000 / 809007(仅 dispatch)/ 582031 / 582083。
#8577
- 订正一处「POST requirement/confirm 零影响」的错误断言:doConfirm 与 confirm-check 共用
已收窄的 classifyVehicleSubmission,该端点的 809122 触发条件同步收窄。
- 809121 / 809123 的错误响应示例换成测试服实测原文。
- frontend_status 保留 not_required,但把判定依据写进 status_note:三个码一律走拦截器透
message、生产代码无一处按报文匹配、前端也无纯接送机户的规避需要撤除;同时列出五处现已
陈旧的前端注释与一处 mock 报文,供 mmg 顺手清理。
门禁:validate-changelog-frontmatter.mjs --files 三个文件一次通过(PASS: 3 files)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
719 行
41 KiB
Markdown
719 行
41 KiB
Markdown
---
|
||
schema: "hl-changelog/v2"
|
||
ticket: "8577"
|
||
title: "只提交了接送机的户不再被判「未提交用车需求」,809121/809122/809123 触发条件收窄且文案改写"
|
||
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: "PR #8600 已 squash 合并 dev-v3(5b7074e691),hl-order-service-v3 dev-v3 分支已滚测试服。三个端点的请求体、响应体字段与错误码号全部未变,变的是 809121/809122/809123 的触发条件(收窄)与消息文案(去掉「行程」二字)。【frontend_status 取 not_required 的依据,2026-09-30 对 hl-ui origin/v2.1 逐处查证】三个码的展示一律走拦截器透 message,生产代码无一处按报文字符串匹配;纯接送机户在前端也没有任何规避(按钮禁用/提示)需要撤除,故无强制前端动作。⚠️ 但有注释级陈旧需顺手清:src/api/orderV2GroupBatch.js:921,957,958 与 GroupVehicleRequirementEditModal.vue:377,874 仍写着「TRAVEL / 行程用车需求」,三个码现已按 TRAVEL ∪ TRANSFER 判「已提交」;GroupVehicleRequirementSection.spec.js:1000 的 mock 报文同样陈旧(该用例不断言文案,不会红)。"
|
||
updated_at: "2026-09-30"
|
||
base: "dev-v3"
|
||
---
|
||
|
||
# hl-order-service-v3: 只提交了接送机的户不再被判「未提交用车需求」
|
||
|
||
> **存放目录**: `changelogs-v2/2026-09/`
|
||
> **服务**: hl-order-service-v3 (端口 8086)
|
||
> **PR**: #8600
|
||
> **Issue**: #8577
|
||
> **日期**: 2026-09-30
|
||
> **影响范围**: 团期需求管理 Tab 的三个端点(保存正式用车需求 / 自动汇总草稿 / 整体确认预检)里 809121、809122、809123 的触发条件与消息文案
|
||
|
||
---
|
||
|
||
## ⚠️ 关键变化
|
||
|
||
- 🔴 **判据从「有没有提交行程用车(TRAVEL)」收窄为「两类用车需求(TRAVEL / TRANSFER)是不是一条都没有」**。改前:某户只提交了接送机需求,团级保存、自动汇总、确认预检都把它当成「一条都没交」,整团被 809123 / 809121 / 809122 卡住,而这户其实已经明确表达过「只要接送机、不要行程车」,运营**没有任何干净出路**(唯一逃生舱是整团 waive 免车,那会把真需要行程车的户一起免掉)。改后:这户算已提交,三处一律放行。
|
||
- **三个错误码的码值没变、字段没变**,变的是**什么时候抛**(收窄)与**消息文案**(三条都去掉了「行程」二字):
|
||
- `809121` `团期 {0} 有 {1} 户缺少可汇总的行程用车需求…` → `…缺少可汇总的用车需求…`
|
||
- `809122` `该户尚未提交行程用车需求,请先让定制师提交后再整团提交车务` → `该户尚未提交用车需求,…`
|
||
- `809123` `{0}有 {1} 户尚未提交行程用车需求,暂不能保存正式用车需求:{2}` → `…尚未提交用车需求,…`
|
||
- 🔴 **前端凡是对这三条报文做过关键词匹配 / 字符串包含判断的地方必须改**(`行程用车需求` 这个子串在三条里都没了)。正确做法是按 `code` 分支,不要匹配 `message` 文本。
|
||
- 🔴 **809109「逐日覆盖」一个字都没改,仍然只认 TRAVEL**。这是刻意的:本次分离的是「户级提交判定」与「行程覆盖判定」两件事,合并会把墙从 809123 挪到 809109,症状一模一样只是换个码。所以——**只提交接送机的户不再被判未提交,也不要求被任何乘车分组覆盖**;它结构上就在团级乘车分组之外,走逐户派车。
|
||
- `GroupVehicleDraftAggregator` 的缺失原因文案 `未提交行程用车需求` → `未提交用车需求`。它出现在 809121 报文的逐户清单里(`「户标识:原因」`,顿号分隔),前端若展示过这个字符串同样受影响。
|
||
- 「豁免户」`exemptHouseholds` 的语义边界也随之明确:**只提交了接送机的户既不进未提交名单、也不进豁免名单**——豁免解释的是「没提交的户为什么不拦」,而它本来就提交过。
|
||
|
||
---
|
||
|
||
## 一、背景
|
||
|
||
一户在团期里的用车需求有两类活跃行,互不替代:
|
||
|
||
| 类别 | 含义 | 派车路径 |
|
||
|------|------|----------|
|
||
| `TRAVEL` | 团期行程用车 | 汇总进团级乘车分组,整团逐日配车 |
|
||
| `TRANSFER` | 接送机 | 逐户派车,**结构上不进团级乘车分组** |
|
||
|
||
改前的三处判定都只查 `TRAVEL`。于是「只要接送机、不要行程车」这种完全合法的在团户(与 #7972 (A) 对 809114 的定案同源)被读成「什么都没交」。团级保存直接 809123 整份拒绝、自动汇总 809121 整团出不来草稿、确认预检 809122 逐户挂红——**运营改不动、催不动(该户定制师已经交过了)、也绕不过去**。
|
||
|
||
本次把判定拆成两个集合(`travelSubmittedOrderIds` / `anySubmittedOrderIds`),单源仍只有一份,在 `GroupVehicleRequirementService#classifyVehicleSubmission`(原名 `classifyTravelSubmission`),保存、预检、自动汇总三处共用:
|
||
|
||
- **户级「交了没有」** → 用 `anySubmittedOrderIds`(两类任一即算交了)→ 管 809121 / 809122 / 809123;
|
||
- **行程逐日覆盖** → 仍用 `travelSubmittedOrderIds`(只认 TRAVEL)→ 管 809109。
|
||
|
||
---
|
||
|
||
## 二、变更接口清单
|
||
|
||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||
|---|------|------|------|----------|------|
|
||
| 1 | 保存团期正式用车需求(全量替换) | PUT | `/v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement` | 错误码触发条件收窄 + 文案改写 | 809123 不再对「只提交接送机」的户触发;报文去掉「行程」 |
|
||
| 2 | 自动汇总正式用车需求草稿 | GET | `/v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/aggregate-draft` | 错误码触发条件收窄 + 文案改写 | 809121 同上;缺失原因文案同步改写 |
|
||
| 3 | 整体确认需求缺失预检 | GET | `/v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check` | 缺失项触发条件收窄 + 文案改写 | `HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED`(809122)同上 |
|
||
|
||
---
|
||
|
||
## 三、接口详情
|
||
|
||
### 1. 保存团期正式用车需求(全量替换) `PUT /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement`
|
||
|
||
**VO**: `GroupVehicleRequirementSaveReqVO → GroupVehicleRequirementRespVO`
|
||
|
||
#### 使用场景
|
||
|
||
团期需求管理 Tab 的「正式用车需求」编辑弹窗点保存时调用,**整份全量替换**(未出现在本次提交里的分组会被移出当前版本)。权限点 `group-batch:demand:confirm`。本次改动只让 809123 少抛一类情况、并改了它的报文,请求体与响应体一个字段都没动。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||
|------|------|------|------|------|------|
|
||
| `groupBatchId` | Path | Long | ✅ | - | 团期 ID |
|
||
| `version` | Body | Integer | ❌ | 乐观锁 | **首次保存传 null**,后续必须回传上次 GET / PUT 拿到的值;不一致抛 809102 |
|
||
| `remark` | Body | String | ❌ | `@Size(max=500)` | 整份需求备注 |
|
||
| `groups` | Body | Array | ✅ | `@NotNull`(**不是** `@NotEmpty`)、`@Valid` | 全部乘车分组;空数组是合法提交(有需车户时由 809103 拦),整团免车请改走 `waive` 端点 |
|
||
| `groups[].groupId` | Body | Long | ❌ | - | 既有分组主键;**新增分组传 null**。带上它 = 声明「就是库里那一组」,此时 `groupCode` 不得变更(改名抛 809104) |
|
||
| `groups[].groupCode` | Body | String | ✅ | `@NotBlank`,`@Size(max=32)` | 分组键,直接作为车费 `alloc_group` |
|
||
| `groups[].vehicleType` | Body | String | ✅ | `@NotBlank`,`@Size(max=64)` | 车型大类编码,**不是自由文本**;取值权威见 `GET /internal/fleet/vehicle-types/category-names`,不在字典内抛 809119 |
|
||
| `groups[].serviceStartDate` | Body | String(`yyyy-MM-dd`) | ✅ | `@NotNull` | 本组服务开始日 |
|
||
| `groups[].serviceEndDate` | Body | String(`yyyy-MM-dd`) | ✅ | `@NotNull` | 本组服务结束日(须不早于开始日) |
|
||
| `groups[].seats` | Body | Integer | ❌ | `@Min(1)` | 该组单车座位数;**刻意非必填**(存量分组没有该值),与 `count` 必须同填或同空(809118),且须在该车型可选档位内(809124) |
|
||
| `groups[].count` | Body | Integer | ❌ | `@Min(1)` | 该组车辆数量;同上 |
|
||
| `groups[].specialTags` | Body | Array\<String\> | ❌ | 值须在字典 `vehicle_special_demand` 内 | 特殊诉求标签编码数组;含字典外编码整份拒绝(809117) |
|
||
| `groups[].remark` | Body | String | ❌ | `@Size(max=500)` | 该组备注 |
|
||
| `groups[].days` | Body | Array | ✅ | `@NotEmpty`,`@Valid` | 逐日用车人数与成员,**不能用单值人数代替** |
|
||
| `groups[].days[].tripDate` | Body | String(`yyyy-MM-dd`) | ✅ | `@NotNull` | 团期行程日,须落在本组服务日范围内且不缺日(809105 / 809106) |
|
||
| `groups[].days[].headcount` | Body | Integer | ✅ | `@NotNull`,`@Min(1)` | 该组该日**乘车人数**(不是户数);小于当日成员户数抛 809110 |
|
||
| `groups[].days[].memberOrderIds` | Body | Array\<Long\> | ✅ | `@NotEmpty` | 该组该日实际乘车的子订单集合,须全属本团在团户(809107),同一户同一日只能属一个分组(809108) |
|
||
|
||
#### 出参 `Result<GroupVehicleRequirementRespVO>`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `requirementId` | String | 正式用车需求 ID(雪花,字符串) |
|
||
| `groupBatchId` | String | 团期 ID(雪花,字符串) |
|
||
| `status` | String | 需求状态 |
|
||
| `version` | Integer | 乐观锁版本,下次保存必须回传 |
|
||
| `remark` | String | 整份需求备注 |
|
||
| `confirmedBy` | String | 确认人 |
|
||
| `confirmedAt` | String(datetime) | 确认时间 |
|
||
| `planRefreshState` | String | 配车刷新状态(只读投影) |
|
||
| `planRefreshReplayCount` | Integer | 配车刷新重投次数 |
|
||
| `blockedStage` | String | 被卡住的阶段 |
|
||
| `planRefreshStalled` | Boolean | 配车刷新是否已停滞 |
|
||
| `planRefreshStalledReason` | String | 停滞原因 |
|
||
| `planRefreshTimeoutAt` | String(datetime) | 刷新超时时刻 |
|
||
| `planRefreshReplayExhausted` | Boolean | 重投次数是否已用尽 |
|
||
| `groups` | Array | 乘车分组回显 |
|
||
| `groups[].groupId` / `groupCode` / `vehicleType` / `vehicleTypeName` | String | 分组主键(字符串)、分组键、车型大类编码、车型中文名(按归一 key 取) |
|
||
| `groups[].serviceStartDate` / `serviceEndDate` | String(`yyyy-MM-dd`) | 本组服务日范围 |
|
||
| `groups[].seats` / `count` / `totalSeatCount` / `maxHeadcount` / `remainingPassengerSeats` | Integer | 单车座位数 / 车辆数 / 总座位 / 最大日人数 / 剩余可载客座位 |
|
||
| `groups[].specialTags[]` | Array | `code` + `name`(中文名后端下发,前端不自己映射) |
|
||
| `groups[].remark` | String | 该组备注 |
|
||
| `groups[].days[]` | Array | `tripDate` / `headcount` / `memberOrderIds`(字符串数组) / `memberOrderCount` |
|
||
| `exemptHouseholds` | Array | 豁免户(在团需车、两类需求都没有活跃行、但定制师**提交不了**的户);🔴 **只提交了接送机的户不在这里**——它已提交 |
|
||
| `exemptHouseholds[].orderId` | String | 子订单 ID(雪花,字符串) |
|
||
| `exemptHouseholds[].teamNo` | String | 团号 |
|
||
| `exemptHouseholds[].orderNo` | String | 子订单号 |
|
||
| `exemptHouseholds[].reason` | String | `ORDER_NOT_CUSTOMIZING` / `REQUIREMENT_FROZEN` |
|
||
| `exemptHouseholds[].reasonName` | String | 豁免原因中文名(后端下发,前端不自己映射) |
|
||
|
||
#### 请求示例
|
||
|
||
```json
|
||
{
|
||
"version": 3,
|
||
"remark": "9/13 起换大巴",
|
||
"groups": [
|
||
{
|
||
"groupId": null,
|
||
"groupCode": "BUS",
|
||
"vehicleType": "bus",
|
||
"serviceStartDate": "2026-09-12",
|
||
"serviceEndDate": "2026-09-16",
|
||
"seats": 19,
|
||
"count": 1,
|
||
"specialTags": ["CHILD_SEAT"],
|
||
"remark": "含高速费",
|
||
"days": [
|
||
{
|
||
"tripDate": "2026-09-12",
|
||
"headcount": 9,
|
||
"memberOrderIds": [2099459272533323777, 2099459272533323778]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"success": true,
|
||
"data": {
|
||
"requirementId": "2099459272533400001",
|
||
"groupBatchId": "2099459272533000001",
|
||
"status": "DRAFT",
|
||
"version": 4,
|
||
"remark": "9/13 起换大巴",
|
||
"confirmedBy": null,
|
||
"confirmedAt": null,
|
||
"planRefreshState": null,
|
||
"planRefreshStalled": false,
|
||
"groups": [
|
||
{
|
||
"groupId": "1867000000009",
|
||
"groupCode": "BUS",
|
||
"vehicleType": "bus",
|
||
"vehicleTypeName": "大巴客车",
|
||
"serviceStartDate": "2026-09-12",
|
||
"serviceEndDate": "2026-09-16",
|
||
"seats": 19,
|
||
"count": 1,
|
||
"totalSeatCount": 19,
|
||
"maxHeadcount": 9,
|
||
"remainingPassengerSeats": 9,
|
||
"specialTags": [{ "code": "CHILD_SEAT", "name": "儿童座椅" }],
|
||
"remark": "含高速费",
|
||
"days": [
|
||
{
|
||
"tripDate": "2026-09-12",
|
||
"headcount": 9,
|
||
"memberOrderIds": ["2099459272533323777", "2099459272533323778"],
|
||
"memberOrderCount": 2
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"exemptHouseholds": []
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 空数据 / 降级响应
|
||
|
||
该团期**只有接送机户、没有任何行程用车户**时,提交零分组不再被 809123 拦(本次改动的直接效果);若团里确实还有需车户,零分组仍由 809103 拦下。`exemptHouseholds` 为空时是**空数组**不是 `null`:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"success": true,
|
||
"data": {
|
||
"requirementId": "2099459272533400001",
|
||
"groupBatchId": "2099459272533000001",
|
||
"status": "DRAFT",
|
||
"version": 1,
|
||
"groups": [],
|
||
"exemptHouseholds": []
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 错误响应
|
||
|
||
809123(触发条件已收窄、文案已改写;`{0}` 是团期人话标识,`{2}` 按团号列户、无团号回落订单号、都缺时为「某子订单」,顿号分隔;以下为测试服实测原文):
|
||
|
||
```json
|
||
{
|
||
"code": 809123,
|
||
"message": "团期「第22期 8月喀纳斯湖秋色三日游」有 1 户尚未提交用车需求,暂不能保存正式用车需求:26-6538",
|
||
"success": false,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
其余错误码一条都没变:809100 团期尚未形成正式用车需求 / 809101 状态不允许 / 809102 已被他人修改(乐观锁) / 809103 有需车户却零分组 / 809104 分组重复或试图改名 / 809105 逐日行不在本组服务日范围内或重复 / 809106 缺逐日用车人数 / 809107 成员不属于本团期 / 809108 同一户同一日属多个分组 / 809109 该子订单的某日没有被任何乘车分组覆盖(**仍只认 TRAVEL**) / 809110 用车人数小于当日成员户数 / 809111 团期状态不允许编辑 / 809115 已声明整团免车需先 withdraw / 809116 座位不足 / 809117 特殊诉求标签不在字典内 / 809118 座位数与车辆数须同填或同空 / 809119 车型不在车型字典内 / 809120 车型字典暂不可用 / 809124 座位数不在该车型可选档位内。
|
||
|
||
#### 业务边界
|
||
|
||
- **鉴权**:权限点 `group-batch:demand:confirm`(与整体确认、按户打回、受控重开同码——它们动的是同一个 Tab 里的同一份数据);未登录由网关拦截返 401。
|
||
- **全量替换语义**:未出现在本次提交里的分组会被移出当前版本,不是增量补丁。
|
||
- **🔴 判据变化只在户级**:「这户交了没有」看两类任一;「行程逐日覆盖」(809109)仍只看 TRAVEL,没变。
|
||
- **只提交接送机的户**:不再被 809123 拦、**也不要求被任何乘车分组覆盖**,且**不出现在 `exemptHouseholds` 里**。
|
||
- **豁免户不阻断**:`ORDER_NOT_CUSTOMIZING` / `REQUIREMENT_FROZEN` 两类户不进 809123、不参与 809109,但必须在页面上提示出来(后端已逐户带原因下发)。
|
||
- **错误码文案是可变的**:`message` 只用于展示,判定一律按 `code`。
|
||
- **乐观锁只挡同一瞬间的并发写**:挡不住「A 读了 v3 去改、B 也读了 v3 改完先提交」这种跨请求覆盖。
|
||
- **雪花 ID 一律是字符串**(`requirementId` / `groupBatchId` / `memberOrderIds[]` / `exemptHouseholds[].orderId`)。
|
||
|
||
---
|
||
|
||
### 2. 自动汇总正式用车需求草稿 `GET /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/aggregate-draft`
|
||
|
||
**VO**: `无请求体 → GroupVehicleAggregateDraftRespVO`
|
||
|
||
#### 使用场景
|
||
|
||
编辑弹窗点「自动汇总」时调用,按各子订单的活跃 TRAVEL 需求汇总出一份团级草稿,**只读零写入**,返回的 `draft` 可原样 PUT 给上面那个保存端点。权限点与编辑弹窗取数口同码 `group-batch:demand:confirm`。本次改动只让 809121 少抛一类情况并改了它的报文与缺失原因文案。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||
|------|------|------|------|------|------|
|
||
| `groupBatchId` | Path | Long | ✅ | - | 团期 ID |
|
||
|
||
#### 出参 `Result<GroupVehicleAggregateDraftRespVO>`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `groupBatchId` | String | 团期 ID(雪花,字符串) |
|
||
| `currentStatus` | String | 当前正式需求状态 |
|
||
| `draft` | Object | 汇总出的草稿,结构**与保存端点的请求体逐字段相同**,可原样 PUT |
|
||
| `droppedFleetItems` | Array | 多车型户被丢弃的车型项:`orderId` / `teamNo` / `orderNo` / `vehicleType` / `seats` / `count` / `keptVehicleType` / `reason`(`VEHICLE_TYPE_NOT_IN_DICT` 等) |
|
||
| `staleHeadcountOrders` | Array | 冻结人数与实时人数不一致的户:`orderId` / `teamNo` / `orderNo` / `frozenHeadcount` / `liveHeadcount` |
|
||
| `paddedOrderDays` | Array | 为覆盖出发~返回而补进分组的日期:`orderId` / `teamNo` / `orderNo` / `dates[]` |
|
||
| `seatOptionAdjusted` | Array | 座位档被兜底调整的组/户:`groupCode` / `orderId` / `teamNo` / `orderNo` / `vehicleType` / `originalSeats` / `adoptedSeats` / `seatOptions[]` / `reason` |
|
||
| `violations` | Array | 草稿已先跑过与保存同一份逐日校验的结果:`code`(对应 809xxx) / `reason` / `detail` / `groupCode` / `tripDate` / `orderId` / `teamNo` |
|
||
| `exemptHouseholds` | Array | 豁免户(结构同上一个端点);🔴 **只提交了接送机的户不在这里,也不在草稿里** |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
GET /v3/admin/order/group-batch/2099459272533000001/vehicle-requirement/aggregate-draft
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"success": true,
|
||
"data": {
|
||
"groupBatchId": "2099459272533000001",
|
||
"currentStatus": "DRAFT",
|
||
"draft": {
|
||
"version": 3,
|
||
"remark": null,
|
||
"groups": [
|
||
{
|
||
"groupId": null,
|
||
"groupCode": "BUS",
|
||
"vehicleType": "bus",
|
||
"serviceStartDate": "2026-09-12",
|
||
"serviceEndDate": "2026-09-16",
|
||
"seats": 19,
|
||
"count": 1,
|
||
"specialTags": [],
|
||
"remark": null,
|
||
"days": [
|
||
{
|
||
"tripDate": "2026-09-12",
|
||
"headcount": 9,
|
||
"memberOrderIds": [2099459272533323777]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
},
|
||
"droppedFleetItems": [],
|
||
"staleHeadcountOrders": [],
|
||
"paddedOrderDays": [],
|
||
"seatOptionAdjusted": [],
|
||
"violations": [],
|
||
"exemptHouseholds": []
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 空数据 / 降级响应
|
||
|
||
团里只有接送机户、没有任何可汇总的行程用车户时,草稿分组为空数组而**不再抛 809121**(本次改动的直接效果):
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"success": true,
|
||
"data": {
|
||
"groupBatchId": "2099459272533000001",
|
||
"currentStatus": "DRAFT",
|
||
"draft": { "version": null, "remark": null, "groups": [] },
|
||
"droppedFleetItems": [],
|
||
"staleHeadcountOrders": [],
|
||
"paddedOrderDays": [],
|
||
"seatOptionAdjusted": [],
|
||
"violations": [],
|
||
"exemptHouseholds": []
|
||
}
|
||
}
|
||
```
|
||
|
||
车型字典取不到时不静默降级,抛 809120 让运营重试(避免把一整份草稿的车型全判成非法)。
|
||
|
||
#### 错误响应
|
||
|
||
809121(触发条件已收窄、文案已改写;`{0}` 是团期名标识,`{2}` 是「户标识:原因」顿号分隔的清单,原因文案里的 `未提交行程用车需求` 已改为 `未提交用车需求`;以下为测试服实测原文):
|
||
|
||
```json
|
||
{
|
||
"code": 809121,
|
||
"message": "团期 「第22期 8月喀纳斯湖秋色三日游」 有 1 户缺少可汇总的用车需求,暂不能自动汇总:26-6538:未提交用车需求",
|
||
"success": false,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
其余错误码未变:809120 车队车型字典暂不可用 / 809111 团期状态不允许 / 809100 团期尚未形成正式用车需求(视链路)。
|
||
|
||
#### 业务边界
|
||
|
||
- **鉴权**:权限点 `group-batch:demand:confirm`;未登录由网关拦截返 401。
|
||
- **⛔ 本端点零写入**,可安全重复调用;`draft` 是「按现有子订单需求草稿长什么样」,**不保证保存一定能过**——预跑的校验结果在 `violations`。
|
||
- **收窄后的 809121 判据**:需车户「两类用车需求一条都没有」才算信息缺失;只提交接送机的户不算缺少,**也不会出现在草稿里**(团车草稿只汇总 TRAVEL,它本就没有位置)。
|
||
- **缺失原因文案已改**:`未提交行程用车需求` → `未提交用车需求`(另有 `车型均不在车型字典内`、服务日推不出、人数为 0 三类未变)。
|
||
- **诊断字段必须展示**:`droppedFleetItems` / `staleHeadcountOrders` / `paddedOrderDays` / `seatOptionAdjusted` 都是「草稿与用户预期可能不一致」的位置,静默吞掉会让运营看到一份自己没想要的草稿。
|
||
- **雪花 ID 一律是字符串**。
|
||
|
||
---
|
||
|
||
### 3. 整体确认需求缺失预检 `GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check`
|
||
|
||
**VO**: `无请求体 → GroupBatchRequirementCheckRespVO`
|
||
|
||
#### 使用场景
|
||
|
||
「查看需求」Tab 进入时与点「确认」前调用,据 `ready` 置灰确认按钮、据 `missing` / `vehicleMissing` 展示缺哪几户。**只读无副作用**。权限点 `group-batch:demand:confirm`。本次改动只让缺失项 `HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED`(809122)少产出一类情况并改了它的报文。
|
||
|
||
#### 入参
|
||
|
||
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|
||
|------|------|------|------|------|------|
|
||
| `groupBatchId` | Path | Long | ✅ | - | 团期 ID |
|
||
|
||
#### 出参 `Result<GroupBatchRequirementCheckRespVO>`
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `groupBatchId` | String | 团期 ID(雪花,字符串) |
|
||
| `batchStatus` / `batchStatusName` | String | 团期状态编码与中文名 |
|
||
| `ready` | Boolean | 是否可以整体确认(置灰按钮用) |
|
||
| `missing` | Array | 房侧缺失户:`orderId` / `teamNo` / `orderNo` / `customerName` / `consultantId` / `consultantName` / `reason` / `reasonName` / `dayNumber` / `segmentIndex` / `expectedNights` / `actualNights` |
|
||
| `checkedResourceTypes` | Array\<String\> | 恒为 `["HOTEL","VEHICLE"]`;文案已更新为「车侧逐户查**用车需求行**是否提交(#8577 起行程用车与接送机任一有即算已提交)」 |
|
||
| `vehicleWaived` | Boolean | 是否已声明整团免车 |
|
||
| `vehicleMissing` | Array | 车侧缺失项,见下 |
|
||
| `vehicleMissing[].reason` | String | `GROUP_REQUIREMENT_NOT_FOUND` / `GROUP_REQUIREMENT_STATUS_INVALID` / `NO_GROUP` / `GROUP_CODE_INVALID` / `DAY_OUT_OF_GROUP_RANGE` / `DAY_GAP_IN_GROUP_RANGE` / `MEMBER_FOREIGN_ORDER` / `MEMBER_DUPLICATE_DAY` / `ORDER_DAY_UNCOVERED` / `HEADCOUNT_LESS_THAN_MEMBERS` / **`HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED`** / `MEMBER_GROUP_MISMATCH` / `TRANSFER_SERVICE_DATES_NOT_BACKFILLED` / `TRANSFER_WINDOW_INCOMPLETE` |
|
||
| `vehicleMissing[].groupCode` | String | 涉及的乘车分组编码;无分组维度时 null |
|
||
| `vehicleMissing[].tripDate` | String(`yyyy-MM-dd`) | 涉及的日期;无日期维度时 null |
|
||
| `vehicleMissing[].orderId` | String | 涉及的子订单 ID(雪花,字符串);无订单维度时 null |
|
||
| `vehicleMissing[].teamNo` / `orderNo` | String | 团号 / 子订单号快照 |
|
||
| `vehicleMissing[].detail` | String | 人话描述,**与整团确认时抛出的错误报文逐字相同**,可直接展示 |
|
||
| `vehicleExemptHouseholds` | Array | 车侧豁免户(结构同前两个端点);🔴 **只提交了接送机的户不在这里** |
|
||
| `groupVehicleRequirementId` | String | 团级正式用车需求 ID(雪花,字符串) |
|
||
| `groupVehicleRequirementStatus` | String | 团级正式用车需求状态 |
|
||
| `groupVehicleRequirementVersion` | Integer | 团级正式用车需求版本 |
|
||
| `transferSubmitEnabled` | Boolean | 接送机提交灰度开关当前状态 |
|
||
| `transferDeclaredWithoutRequirement` | Array | 声明了接送机却没有活跃 TRANSFER 行的户:`orderId` / `teamNo` / `orderNo` / `customerName` / `consultantId` / `consultantName` / `pickupRequired` / `dropoffRequired` / `pickupRemark` |
|
||
|
||
#### 请求示例
|
||
|
||
```http
|
||
GET /v3/admin/order/group-batch/2099459272533000001/requirement/confirm-check
|
||
```
|
||
|
||
#### 响应示例
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"success": true,
|
||
"data": {
|
||
"groupBatchId": "2099459272533000001",
|
||
"batchStatus": "RESOURCE_PREPARING",
|
||
"batchStatusName": "资源准备中",
|
||
"ready": false,
|
||
"missing": [],
|
||
"checkedResourceTypes": ["HOTEL", "VEHICLE"],
|
||
"vehicleWaived": false,
|
||
"vehicleMissing": [
|
||
{
|
||
"reason": "HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED",
|
||
"groupCode": null,
|
||
"tripDate": null,
|
||
"orderId": "2099459272533323779",
|
||
"teamNo": "26-0482",
|
||
"orderNo": "HL2606010003",
|
||
"detail": "该户尚未提交用车需求,请先让定制师提交后再整团提交车务"
|
||
}
|
||
],
|
||
"vehicleExemptHouseholds": [],
|
||
"groupVehicleRequirementId": "2099459272533400001",
|
||
"groupVehicleRequirementStatus": "DRAFT",
|
||
"groupVehicleRequirementVersion": 4,
|
||
"transferSubmitEnabled": true,
|
||
"transferDeclaredWithoutRequirement": []
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 空数据 / 降级响应
|
||
|
||
全部就绪时 `ready=true`,三个清单都是**空数组**不是 `null`:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "成功",
|
||
"success": true,
|
||
"data": {
|
||
"groupBatchId": "2099459272533000001",
|
||
"batchStatus": "RESOURCE_PREPARING",
|
||
"batchStatusName": "资源准备中",
|
||
"ready": true,
|
||
"missing": [],
|
||
"checkedResourceTypes": ["HOTEL", "VEHICLE"],
|
||
"vehicleWaived": false,
|
||
"vehicleMissing": [],
|
||
"vehicleExemptHouseholds": [],
|
||
"transferDeclaredWithoutRequirement": []
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 错误响应
|
||
|
||
本端点是只读预检,把缺失**列成清单**而不是抛码;仍可能出现的错误只有权限与团期不存在两类:
|
||
|
||
```json
|
||
{
|
||
"code": 403,
|
||
"message": "无权限执行该操作",
|
||
"success": false,
|
||
"data": null
|
||
}
|
||
```
|
||
|
||
#### 业务边界
|
||
|
||
- **鉴权**:权限点 `group-batch:demand:confirm`;未登录由网关拦截返 401。
|
||
- **⛔ 只读无副作用**,可随页面进入反复调用。
|
||
- **它是缺失明细的唯一来源**:整团确认失败时抛出的 589533 只带汇总户数,逐户明细只能从本端点取。
|
||
- **收窄后的 `HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED` 判据**:在团需车户**两类用车需求都没提交**才产出;只提交接送机的户不产出,**也不进 `vehicleExemptHouseholds`**。
|
||
- **`detail` 与错误报文逐字相同**:所以它也跟着改了文案(`行程用车需求` → `用车需求`),前端不要做子串匹配。
|
||
- **`ORDER_DAY_UNCOVERED`(809109)仍只认 TRAVEL**:只提交接送机的户不会因为「没被任何乘车分组覆盖」出现在这里。
|
||
- **`transferDeclaredWithoutRequirement` 里两个 flag 都为 false 是合法组合**:该户的声明落在 `direction` 为空或不在 ARRIVAL/DEPARTURE 两值内的批次上,仍确实声明了接送机,前端照常展示、不要过滤掉。
|
||
- **雪花 ID 一律是字符串**。
|
||
|
||
---
|
||
|
||
## 四、契约约束与正确调用方式
|
||
|
||
> 本节只写后端接受 / 拒绝 payload 的规则,不写 UI 渲染建议。
|
||
|
||
### ✅ 正确 / ❌ 错误 payload 对照(保存端点)
|
||
|
||
| 场景 | payload |
|
||
|------|---------|
|
||
| ✅ 首次保存(无版本) | `{ "version": null, "groups": [ { "groupCode": "BUS", "vehicleType": "bus", "serviceStartDate": "2026-09-12", "serviceEndDate": "2026-09-16", "days": [ { "tripDate": "2026-09-12", "headcount": 9, "memberOrderIds": [2099459272533323777] } ] } ] }` |
|
||
| ✅ 改既有组(带 groupId,groupCode 不变) | `{ "version": 3, "groups": [ { "groupId": 1867000000009, "groupCode": "BUS", ... } ] }` |
|
||
| ✅ 座位与车辆数同空(存量分组) | `{ ..., "seats": null, "count": null }` |
|
||
| ✅ 团里只有接送机户 → 提交零分组 | `{ "version": null, "groups": [] }` → 200(改前该团常因某户「只交了接送机」撞 809123) |
|
||
| ❌ `groups` 传 null | `{ "version": 3, "groups": null }` → 400「乘车分组列表不能为 null(整团免车请改用 waive 端点)」 |
|
||
| ❌ 带 groupId 却改了 groupCode | `{ "groupId": 1867000000009, "groupCode": "BUS2", ... }` → 809104 |
|
||
| ❌ 只填 seats 不填 count | `{ "seats": 19, "count": null }` → 809118 |
|
||
| ❌ 车型填自由文本 | `{ "vehicleType": "35座大巴" }` → 809119 |
|
||
|
||
### 前端必须做的一处改动
|
||
|
||
- 🔴 **凡是对 809121 / 809122 / 809123 的 `message`(或预检 `vehicleMissing[].detail`)做过字符串包含判断的地方,一律改成按 `code` / `reason` 分支**。三条报文里的 `行程用车需求` 已改为 `用车需求`,旧的子串匹配会静默失配(不报错,只是那条分支再也不进)。
|
||
- 其余全部字段、校验规则、请求格式不变,不需要任何别的适配。
|
||
|
||
---
|
||
|
||
## 五、数据库行为
|
||
|
||
只有保存端点(PUT)是写端点,本次改动**没有任何表结构或写入语义变化**——变的是写之前那道户级阻断的判据。
|
||
|
||
| 场景 | 改前 | 改后 |
|
||
|------|------|------|
|
||
| 某户只有活跃 TRANSFER 行,团级 PUT 提交 | 809123 整份拒绝,**零写入** | 正常落库(该户不需要被任何分组覆盖) |
|
||
| 某户两类都没有活跃行且提交得了 | 809123 整份拒绝,零写入 | 未变,仍 809123 零写入 |
|
||
| 某户两类都没有活跃行但提交不了(豁免户) | 不阻断,列入 `exemptHouseholds` | 未变 |
|
||
| 正常提交 | 全量替换:本次未出现的分组移出当前版本、版本号 +1 | 未变 |
|
||
|
||
**失败零写入**:809123 抛在乐观锁比对与分组改名守卫之后、任何写入之前,整份拒绝不留半份数据。
|
||
|
||
自动汇总(GET)与确认预检(GET)两个端点**零写入**,本次未改变这一点。
|
||
|
||
---
|
||
|
||
## 六、边界行为
|
||
|
||
- 未登录 → 401(网关拦截)。
|
||
- 权限点 `group-batch:demand:confirm` 缺失 → 403。
|
||
- 团期尚未形成正式用车需求 → 809100(报文用「该团期」,不带雪花 id)。
|
||
- 正式需求已被他人修改 → 809102,带提交版本与当前版本。
|
||
- 团期已过配置阶段 → 809111。
|
||
- 已声明整团免车又提交分组 → 809115(需先 withdraw 回草稿)。
|
||
- 车队车型字典不可用 → 809120(不静默降级,让运营重试)。
|
||
- 老数据兼容:存量分组没有 `seats` / `count`,编辑时原样回传 null 不会 400;库里被 `V20260924_402` 归一过的车型可正常回显,归一认不出的历史自由文本原样保留,但**再提交一次仍会被 809119 拒**——编辑态请把字典外的当前值显式标出提示重选,不要渲染成空。
|
||
- 推不出服务日的户(`departDate` / `returnDate` 任一为空)跳过 809109 覆盖判定(已知盲区,不是遗漏)。
|
||
|
||
---
|
||
|
||
## 六.5、枚举 / 数据字典
|
||
|
||
### reason(车侧缺失项原因码)
|
||
|
||
**所属字段**: `GroupBatchRequirementCheckRespVO.vehicleMissing[].reason` | **类型**: `String`
|
||
|
||
| 值 | 中文 | 说明 |
|
||
|----|------|------|
|
||
| `GROUP_REQUIREMENT_NOT_FOUND` | 团级正式需求未形成 | 对应 809100 |
|
||
| `GROUP_REQUIREMENT_STATUS_INVALID` | 团级正式需求状态不允许 | 对应 809101 |
|
||
| `NO_GROUP` | 有需车户却零分组 | 对应 809103 |
|
||
| `GROUP_CODE_INVALID` | 分组编码重复或改名 | 对应 809104 |
|
||
| `DAY_OUT_OF_GROUP_RANGE` | 逐日行不在本组服务日范围内 | 对应 809105 |
|
||
| `DAY_GAP_IN_GROUP_RANGE` | 本组服务日范围内缺日 | 对应 809106 |
|
||
| `MEMBER_FOREIGN_ORDER` | 成员不属于本团期 | 对应 809107 |
|
||
| `MEMBER_DUPLICATE_DAY` | 同一户同一日属多个分组 | 对应 809108 |
|
||
| `ORDER_DAY_UNCOVERED` | 该户某日未被任何分组覆盖 | 对应 809109;🔴 **仍只认 TRAVEL,本次未改** |
|
||
| `HEADCOUNT_LESS_THAN_MEMBERS` | 用车人数小于当日成员户数 | 对应 809110 |
|
||
| `HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED` | 该户尚未提交用车需求 | 对应 809122;🔴 **#8577 收窄:行程用车与接送机任一有即不报**。只带 `orderId` / `orderNo`,处置是催该户定制师提交 |
|
||
| `MEMBER_GROUP_MISMATCH` | 该户车型与覆盖它的分组车型不符 | 对应 809125;排在户级未提交之后(交都没交的户没有车型可比) |
|
||
| `TRANSFER_SERVICE_DATES_NOT_BACKFILLED` | 待放行的接送机需求未回填服务日 | 对应 809007,只带 `orderId` |
|
||
| `TRANSFER_WINDOW_INCOMPLETE` | 接送机需求窗没盖住大交通派生日期 | 对应 809126,带 `orderId` / `orderNo` 与首个越窗日期 |
|
||
|
||
### reason(团级用车需求豁免户原因码)
|
||
|
||
**所属字段**: `exemptHouseholds[].reason`、`vehicleExemptHouseholds[].reason` | **类型**: `String`
|
||
|
||
| 值 | 中文 | 说明 |
|
||
|----|------|------|
|
||
| `ORDER_NOT_CUSTOMIZING` | 订单不在定制中 | 定制师提交会被 582017 拒,所以该户不算「没交」 |
|
||
| `REQUIREMENT_FROZEN` | 团期已过资源准备、需求已冻结且该户未被打回 | 定制师提交会被 589536 拒 |
|
||
|
||
🔴 **只提交了接送机的户不属于任何一档**——它已提交,既不进未提交名单也不进豁免名单。
|
||
|
||
### 用车需求类别(判定用,不直接出现在本次三个响应的字段里)
|
||
|
||
| 值 | 中文 | 在本次判定中的角色 |
|
||
|----|------|-------------------|
|
||
| `TRAVEL` | 团期行程用车 | 汇总进团级乘车分组;**809109 逐日覆盖只认它** |
|
||
| `TRANSFER` | 接送机 | 走逐户派车、结构上在团级乘车分组之外;#8577 起它也算「已提交用车需求」,参与 809121 / 809122 / 809123 的判定 |
|
||
|
||
---
|
||
|
||
## 六.6、修改前后对比
|
||
|
||
### 字段级对比
|
||
|
||
| 字段 | 改前 | 改后 |
|
||
|------|------|------|
|
||
| 三个端点的全部请求字段 | — | 未变(一个都没动) |
|
||
| 三个端点的全部响应字段 | — | 未变(无新增、无删除、无改名、无类型变化) |
|
||
| `checkedResourceTypes` 的字段说明文案 | 「车侧逐户查**行程**用车需求行是否提交」 | 「车侧逐户查用车需求行是否提交(#8577 起行程用车与接送机任一有即算已提交)」 |
|
||
| `vehicleMissing[].reason` 的取值集合 | 14 个 | 未变(仍 14 个,只是其中一个的触发条件收窄) |
|
||
| `exemptHouseholds` 的成员判据 | 在团需车 ∧ 无 active TRAVEL ∧ 提交不了 | 在团需车 ∧ **两类都无 active 行** ∧ 提交不了 |
|
||
|
||
### 行为级对比
|
||
|
||
| 行为 | 改前 | 改后 |
|
||
|------|------|------|
|
||
| 某户只提交了接送机,团级 PUT 保存 | 809123 整份拒绝,运营无干净出路 | 正常保存 |
|
||
| 某户只提交了接送机,点自动汇总 | 809121 整团出不来草稿 | 正常出草稿(该户不进草稿,也不进缺失清单) |
|
||
| 某户只提交了接送机,进确认预检 | 该户挂 `HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED`,`ready=false` | 不产出该缺失项 |
|
||
| 某户只提交了接送机,点整体确认(`POST .../requirement/confirm`,真实派车/写库) | 809122 抛出,确认失败、零写入 | 正常确认,该户随团一起派车(前提其余条件都满足) |
|
||
| 某户只提交了接送机,是否要求被乘车分组覆盖 | 会走到 809109 | 不要求(它结构上在团级分组之外) |
|
||
| 809121 报文 | `团期 {0} 有 {1} 户缺少可汇总的**行程**用车需求…` | `…缺少可汇总的用车需求…` |
|
||
| 809122 报文 | `该户尚未提交**行程**用车需求,…` | `该户尚未提交用车需求,…` |
|
||
| 809123 报文 | `{0}有 {1} 户尚未提交**行程**用车需求,…` | `{0}有 {1} 户尚未提交用车需求,…` |
|
||
| 汇总缺失原因文案 | `未提交行程用车需求` | `未提交用车需求` |
|
||
| 809109 逐日覆盖的判据 | 只认 TRAVEL | 未变,仍只认 TRAVEL |
|
||
| 两类都没提交的户 | 三处照旧阻断 | 未变 |
|
||
|
||
---
|
||
|
||
## 六.7、影响评估
|
||
|
||
- **是否破坏向后兼容**: 否(无字段增删改;只是三个错误码少抛一类情况、报文文案改写)
|
||
- **前端是否必须同步上线**: 否;但**若前端对这三条报文做过字符串包含判断,必须改**(改成按 `code` / `reason` 分支),否则那条分支会静默失配
|
||
- **前端 workaround 清理点**: 若为绕开「纯接送机户卡住整团」在页面上加过提示、屏蔽过确认按钮、或引导过运营去整团免车,可以撤掉
|
||
|
||
---
|
||
|
||
## 七、不影响范围
|
||
|
||
- **仅影响**: 团期需求管理 Tab 的三个端点里 809121 / 809122 / 809123 的触发条件与报文文案。
|
||
- **⚠️ `POST .../requirement/confirm`(整体确认,真实派车/写库)不是零影响**:它的响应字段结构、派车/写库机制本身未改一行代码,但它内部同样经 `GroupBatchRequirementService.doConfirm`(`GroupBatchRequirementService.java:562`)调 `loadVehicleSnapshot`,后者第 1240-1241 行直接调用本次收窄后的 `classifyVehicleSubmission` 来判 809122——即它对 809122 的**实际触发条件与 `confirm-check` 端点同步收窄**:纯接送机户此前会在这里被 809122 拦下、零写入(回归用例 `GroupBatchRequirementServiceConfirmVehicleTest#doConfirm_householdWithoutTravelRequirement_throws809122` 钉住的正是「两类都没提交」仍会拦的边界),现在能正常通过、随团一起派车,见六.6 行为级对比。前端若曾据「纯接送机户点确认必失败」写过分支或禁用逻辑,需按该行为级对比同步调整。
|
||
- **零影响**:
|
||
- 809109 逐日覆盖判定(仍只认 TRAVEL)
|
||
- `POST .../requirement/confirm` 的响应字段结构(`GroupBatchRequirementConfirmRespVO` 字段清单未变)与派车 / 写库机制(`doConfirm` 方法体本身未改)
|
||
- 受控重开、整份撤回、整团免车、按户打回四个端点
|
||
- 接送机批量确认 `POST .../requirement/transfer/batch-confirm`
|
||
- 户级用车需求的提交 / 编辑 / 打回链路
|
||
- 车务侧(hl-fleet-service)的配车、派单、就绪判定
|
||
- 历史数据:不做任何迁移,存量团期下次调用时按新判据生效
|
||
|
||
---
|
||
|
||
## 八、测试环境已验证
|
||
|
||
- **代码事实**(对 `origin/dev-v3` 逐一查证):
|
||
- 合并提交 `5b7074e691`(PR #8600 squash 合并进 `dev-v3`),17 文件 / +559 −137。
|
||
- `GroupVehicleRequirementErrorCode` 三条 `IErrorCode.of` 的字面量 diff 已逐字核对(809121 / 809122 / 809123 各去掉「行程」二字),码值与常量名未变。
|
||
- `GroupVehicleDraftAggregator.MISSING_NOT_SUBMITTED` 由 `未提交行程用车需求` 改为 `未提交用车需求`;`Household` record 新增 `boolean transferSubmitted` 位,判缺失处改为 `household.needsVehicle() && !household.transferSubmitted()`。
|
||
- `classifyTravelSubmission` 更名为 `classifyVehicleSubmission`,`VehicleSubmission` 内 `travelSubmittedOrderIds` 与 `anySubmittedOrderIds` 是两个分开的字段——809109 用前者、三码用后者,合并会把墙挪到 809109。
|
||
- 三个端点的 Controller 签名、`@RequestBody` VO、响应 VO 字段清单逐一核对,确认零字段变化。
|
||
- 回归钉在 `GroupVehicleRequirementValidateTest#save_frozenRejectedButTransferSubmitted_noLongerThrows809123` 等用例上(本 PR 新增 / 改写测试 6 个文件、+400 余行)。
|
||
- **部署**:`hl-order-service-v3` 的 `dev-v3` 分支已滚到测试服,三个端点走管理端网关 `/v3/admin/order/**` 既有路由,无新增路由。
|
||
|
||
```
|
||
PUT /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement → 200 ✓(纯接送机户不再触发 809123)
|
||
GET /v3/admin/order/group-batch/{groupBatchId}/vehicle-requirement/aggregate-draft → 200 ✓(纯接送机户不再触发 809121)
|
||
GET /v3/admin/order/group-batch/{groupBatchId}/requirement/confirm-check → 200 ✓(不再产出 HOUSEHOLD_REQUIREMENT_NOT_SUBMITTED)
|
||
```
|
||
|
||
---
|
||
|
||
## 九、相关历史 PR
|
||
|
||
| PR | Issue | 说明 | 是否仍有效 |
|
||
|----|-------|------|------------|
|
||
| — | #7441 | 团期正式用车需求首次落地(809100-809115 段) | ✅ 有效 |
|
||
| — | #8219 | 有户未提交时阻断团级 PUT,新开 809123 与豁免户机制 | ✅ 有效(本单在其基础上收窄判据) |
|
||
| — | #8220 | 自动汇总草稿端点与 809121 | ✅ 有效 |
|
||
| — | #8249 | 预检加户级 809122 | ✅ 有效 |
|
||
| — | #8306 | 报文按团号列户、不出现雪花 id | ✅ 有效 |
|
||
| **本 PR #8600** | **#8577** | 户级提交判定与行程覆盖判定分离,三码收窄 + 文案改写 | ✅ 最新 |
|
||
|
||
---
|
||
|
||
## 十、相关文档
|
||
|
||
- 关联 Issue: [wx/HL#8577](https://git.1814.love:8443/wx/HL/issues/8577)
|
||
- 关联 PR: [wx/HL#8600](https://git.1814.love:8443/wx/HL/pulls/8600)
|
||
|
||
## 关联 / 联系人
|
||
|
||
### 链接
|
||
|
||
- **Issue**: [#8577](https://git.1814.love:8443/wx/HL/issues/8577)
|
||
- **PR**: [#8600](https://git.1814.love:8443/wx/HL/pulls/8600)
|
||
- **Merge commit**: [5b7074e691](https://git.1814.love:8443/wx/HL/commit/5b7074e691)
|
||
|
||
### 联系人
|
||
|
||
- **后端负责人**: @wx
|