文件
hl-api-changelog/changelogs-v2/2026-09/23_8231_配导游配摄影物资放开到出行前四态-修改接口-管理后台.md
T
2026-09-23 15:15:48 +08:00

551 行
24 KiB
Markdown
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
---
schema: "hl-changelog/v2"
ticket: "8231"
title: "配导游 / 配摄影 / 物资取消阶段门——出行前四态均可随时配置;取消成团改为放行并回收导摄配置"
consumer: "admin"
author: "jw(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "not_required"
frontend_status: "verified"
frontend_owner: "mmg"
frontend_ref: "e15dd73bd36a1d27374f9206797243f8a5e4326c"
target_release: ""
verified_at: "2026-09-23"
status_note: "jw 2026-09-23 裁决:配导游 / 配摄影 / 物资三项取消节点限制,只要在出行节点之前都可以随时配置。改前配导游 / 配摄影被 assertFormed 拦在招募中(589552),物资被 assertInMaterialStage 限死在 MATERIAL_PREPARING(589520)——而团期要集齐四项 ready(房 / 车 / 导 / 摄)才推得进 MATERIAL_PREPARING,实际「物资配不了」的根因多半是房车没配齐。本次三处写口统一引用新常量 PRE_DEPARTURE_CONFIGURABLE_STATUSES(RECRUITING / RESOURCE_PREPARING / MATERIAL_PREPARING / PENDING_DEPARTURE),出行后与已取消一律拒成新错误码 589598,未建团仍 589553。连带改的是取消成团:放开招募中可配之后,若导摄仍算「已派单资源」,招募中配过人的团一成团就再也取消不了成团(开工前实测:TEST 团期 2099750660965584898 在房车 ready 全 0、已确认子订单 0 的情况下,仅凭导游一项就返 589502)。故按方案 C,导摄两项移出 R10 判定,取消成团改为放行并在同事务内回收导摄配置(order_batch_staff 整期软删 + 各子订单 order_staff_assignment 中 source=GROUP_BATCH 的扇出行软删),房 / 车两项仍照旧阻断。取证阶段另修一处本单引入的回归:招募中清空导摄配置后 ready 位回不到 false(免闸豁免只对已成团成立,needs_* 招募中恒 0),已随 PR #8237 修复。TEST 实测 2026-09-23 12:15~12:25:物资三端点在四态各放行、在 REVIEWING / TRIP_FINISHED / CANCELLED 各返 589598 且零写入;配导摄在四态各落库成功、在三个出行后态返 589598 且零写入;取消成团对仅导摄 dispatched 的样本返 200 并完成回收,对 hotel_ready=1 / vehicle_ready=1 两个样本仍返 589502 且零写入;连续两次取消成团第二次返 589501、不重复回收。前端侧:配导游 / 配摄影按钮本来就不看 batchStatus,零改动;物资 tab 的操作列在 SuppliesPanel.vue 里按 MATERIAL_PREPARING 前置隐藏,后端放开后前端不改则本单无实际效果,交接件见同批 frontend 条目,故 frontend_status 记 pending。 | 2026-09-23 mmg 交付:SuppliesPanel 拆双判据四态放行三写口,配导摄零改动实证,随配套 frontend 条目同 commit"
updated_at: "2026-09-23"
base: "dev-v3"
---
# 团期资源配置: 配导游 / 配摄影 / 物资放开到出行前四态(管理后台)
> **服务**: hl-order-service-v3(端口 8086/8186)
> **PR**: #8234、#8237
> **Issue**: #8231
> **日期**: 2026-09-23
> **影响范围**: 管理后台团期详情页的「配导游 / 配摄影」弹窗、「物资」tab、「取消成团」按钮
---
## ⚠️ 关键变化
本次是**行为变更,不是纯增字段**,三条都与调用方此前的预期不同:
1. **可配窗口扩大**。以前「招募中配不了导摄」「物资只有到了准备物资阶段才配得了」,现在**出行前四态都能配**。
2. **拒绝时的错误码换了**。以前物资拒是 `589520`、导摄拒是 `589552`,现在统一是新码 **`589598`**。按 589520 / 589552 做文案分支的前端要改。
3. **取消成团的阻塞条件收窄了**。以前「已派导游 / 已派摄影」会把取消成团拦住(589502),**现在不会**;作为代价,取消成团成功后会把该团期的导摄配置一并回收,配人列表会变空。
---
## 一、背景
`GroupBatchStatus` 状态机里,「出行之前」= 前四态:
| 允许配置 | 拒绝 |
|---|---|
| `RECRUITING` 招募中 · `RESOURCE_PREPARING` 资源准备中 · `MATERIAL_PREPARING` 物料准备中 · `PENDING_DEPARTURE` 待出发 | `TRAVELLING` 出行中 · `TRIP_FINISHED` 出行完毕 · `REVIEWING` 核单中 · `SETTLED` 已结算 · `CANCELLED` 已取消 |
`CANCELLED` 按拒绝处理:它是终态取消,不属于「出行前」语义。
**物资的实际约束比表面更紧**:团期要先走到 `MATERIAL_PREPARING` 才开窗,而
`RESOURCE_PREPARING → MATERIAL_PREPARING` 的推进条件是四项 ready 齐(房 / 车 / 导 / 摄)+ 合同 / 保险。
即今天「物资配不了」的根因多数是房车没配齐。本次放开后,物资配置不再依赖这条链。
**状态机推进逻辑本身不动**:`MATERIAL_PREPARING` 这个阶段、以及「四项 ready 齐才推进」那条链一律不变。
---
## 二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 保存团期人员配置 | PUT | `/v3/admin/group-batch/{productBatchId}/staff` | 修改接口 | 阶段门从「已成团」放宽到出行前四态;拒绝码 589552 → 589598 |
| 2 | 设置报账人等级 | PUT | `/v3/admin/group-batch/{productBatchId}/staff/{staffId}/reporter-rank` | 修改接口 | 同上,与保存口同窗口 |
| 3 | 新增团期备品行 | POST | `/v3/admin/order/group-batch/{groupBatchId}/supplies` | 修改接口 | 阶段门从 `MATERIAL_PREPARING` 放宽到出行前四态;拒绝码 589520 → 589598 |
| 4 | 调整团期备品数量 | PUT | `/v3/admin/order/group-batch/supplies/{batchSuppliesId}/quantity` | 修改接口 | 同上 |
| 5 | 软删团期备品行 | DELETE | `/v3/admin/order/group-batch/supplies/{batchSuppliesId}` | 修改接口 | 同上 |
| 6 | 取消成团 | POST | `/v3/admin/order/group-batch/{groupBatchId}/cancel-group` | 修改接口 | 导摄两项不再阻断;成功时额外回收导摄配置 |
路径、入参结构、权限码、成功响应结构均零变化;网关无改动。
---
## 三、接口详情
### 1. 保存团期人员配置 `PUT /v3/admin/group-batch/{productBatchId}/staff`
**VO**: `BatchStaffConfigReqVO` → `BatchStaffConfigRespVO`
#### 使用场景
团期详情页「配导游 / 配摄影」弹窗点保存。整期全量覆盖:按 `scopeRoles`(不传即全量)软删旧配置、
写入新配置、异步扇出到各活跃子订单,并按配置结果回填 `guide_ready` / `photographer_ready`。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | path | Long | 是 | 正整数,产品侧排期 ID | 团期所属班期;未建团返 589553 |
| scopeRoles | body | List<String> | 否 | 元素非空 | 限定本次覆盖的角色范围,不传则整期覆盖 |
| staffList | body | List<Item> | 否 | null 按空列表处理 | 传空列表 = 清空覆盖范围内的配置 |
| staffList[].staffId | body | Long | 是 | 须命中候选人员 | 人员 ID |
| staffList[].staffRole | body | String | 是 | 须与人员类型相符,否则 582114 | 角色(GUIDE / LEADER / PHOTOGRAPHER …) |
| staffList[].sortOrder | body | Integer | 否 | — | 展示排序 |
| staffList[].remark | body | String | 否 | — | 备注 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| productBatchId | Long | 回显路径参数 |
| groupBatchId | Long | 团期聚合主键,取守卫阶段那一次既有反查的结果,不额外查库 |
| staffList | List | 保存后的整期最终状态 |
| affectedOrderCount | Integer | 本次扇出触及的活跃子订单数 |
#### 请求示例
```http
PUT /v3/admin/group-batch/2097250420299530242/staff HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <admin token>
Content-Type: application/json
{"staffList":[{"staffId":1002,"staffRole":"GUIDE","sortOrder":0},{"staffId":1003,"staffRole":"PHOTOGRAPHER","sortOrder":1}]}
```
#### 响应示例
```json
{
"code": 200,
"message": "成功",
"data": {
"productBatchId": "2097250420299530242",
"groupBatchId": "2097250563497385985",
"affectedOrderCount": 0,
"staffList": [
{"staffId": 1002, "staffRole": "GUIDE", "staffName": "李雪梅", "reporterRank": "NONE"},
{"staffId": 1003, "staffRole": "PHOTOGRAPHER", "staffName": "王强", "reporterRank": "NONE"}
]
}
}
```
#### 空数据 / 降级响应
`staffList` 传空列表即清空覆盖范围内的配置,返回 200,`staffList` 为空数组、`affectedOrderCount` 为实际扇出订单数。
**清空后 ready 位的回落口径本次有修正**:已成团且该位 `needs_*=false`(成团免闸置位)时保持就绪、不回落;
其余情形(含**招募中**)一律回落为 false。改前招募中清空后 ready 位会卡在 true,与配置行数 0 自相矛盾。
#### 错误响应
```json
{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null}
```
未建团(该班期还没有任何订单,团期行尚未 Lazy 建)仍是另一个码,两者不可合并:
```json
{"code": 589553, "message": "团期尚未创建(该班期还没有任何订单),请先建团并完成成团后再操作", "data": null}
```
#### 业务边界
- 出行前四态(`RECRUITING` / `RESOURCE_PREPARING` / `MATERIAL_PREPARING` / `PENDING_DEPARTURE`)放行
- `TRAVELLING` / `TRIP_FINISHED` / `REVIEWING` / `SETTLED` / `CANCELLED` 返 589598,**被拒时一行都不写**(闸在写库之前)
- 未建团返 589553,且**不会为配置动作提前建团期行**
- 589552「团期尚未成团」不再由本接口抛出,但该码仍被别处(车辆派单、房务)使用,未退役
---
### 2. 设置报账人等级 `PUT /v3/admin/group-batch/{productBatchId}/staff/{staffId}/reporter-rank`
**VO**: `ReporterRank`(枚举入参)
#### 使用场景
团期人员名单里把某个已配人员标为主报账人 / 协助报账人。它与保存口是同构写口——同样写
`order_batch_staff` 并扇出 `order_staff_assignment`,故口径必须与保存口完全一致。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| productBatchId | path | Long | 是 | 正整数 | 产品侧排期 ID |
| staffId | path | Long | 是 | 须命中该团期已配人员 | 人员 ID |
| rank | body | String | 是 | PRIMARY / ASSIST / NONE | 报账人等级 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| data | Void | 成功返回 null,判成败看 `code` |
#### 请求示例
```http
PUT /v3/admin/group-batch/2097250420299530242/staff/1002/reporter-rank HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <admin token>
Content-Type: application/json
{"rank":"PRIMARY"}
```
#### 响应示例
```json
{"code": 200, "message": "成功", "data": null}
```
#### 空数据 / 降级响应
本接口无列表出参,无空数据形态;团期已配人员为空时会先因 staffId 未命中报错,不会静默成功。
#### 错误响应
```json
{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null}
```
#### 业务边界
- 窗口与保存口完全一致,不允许两个方法口径漂移
- 被拒时连「查已派 staff」这一步读都不发生,零写入
- 未建团仍返 589553
---
### 3. 新增团期备品行 `POST /v3/admin/order/group-batch/{groupBatchId}/supplies`
**VO**: `AddSuppliesReqVO`
#### 使用场景
团期详情页「物资」tab 手工录入一行备品(产品侧没有、临时采购的)。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | path | Long | 是 | 正整数,团期聚合主键 | 不存在返 GROUP_BATCH_NOT_FOUND |
| suppliesName | body | String | 否 | 传 suppliesResourceId 时可空 | 备品名称;纯手填时必填 |
| suppliesResourceId | body | Long | 否 | — | 备品库资源 ID,传了则名称取库值 |
| category | body | String | 否 | — | 分类 |
| hasCost | body | Boolean | 否 | — | 是否计费 |
| billingType | body | String | 否 | PER_PERSON / PER_QUANTITY | 计费方式 |
| unitPrice | body | BigDecimal | 否 | — | 单价 |
| quantity | body | Integer | 是 | ≥ 1,否则 589522 | 数量 |
| sortOrder | body | Integer | 否 | 默认 0 | 展示排序 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| data | Long | 新建备品行 ID(`batchSuppliesId`),用于后续改数量 / 软删 |
#### 请求示例
```http
POST /v3/admin/order/group-batch/2099750365778886657/supplies HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <admin token>
Content-Type: application/json
{"suppliesName":"临时采购的雨衣","quantity":1,"sortOrder":999}
```
#### 响应示例
```json
{"code": 200, "message": "成功", "data": "2102611411027066881"}
```
#### 空数据 / 降级响应
本接口是写接口,无空数据形态。创单时由系统固化产品侧备品的 `freezeFromProduct` 路径**不过本阶段门**——
它是首单懒建事务内的系统行为,加门会把建团直接打断,该豁免本次不变。
#### 错误响应
```json
{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null}
```
#### 业务边界
- 出行前四态放行,尤其 `RESOURCE_PREPARING`——改前该态必被 589520 拒
- 出行后与 `CANCELLED` 返 589598,不落库
- 团期不存在返 `GROUP_BATCH_NOT_FOUND`,不是阶段错误
- 数量非法返 589522 参数错误,不是状态错误
---
### 4. 调整团期备品数量 `PUT /v3/admin/order/group-batch/supplies/{batchSuppliesId}/quantity`
**VO**: `AdjustSuppliesQuantityReqVO`
#### 使用场景
物资 tab 行内编辑数量。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| batchSuppliesId | path | Long | 是 | 须命中活跃备品行 | 不存在返 589521 |
| quantity | body | Integer | 是 | ≥ 1,否则 589522 | 新数量 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| data | Void | 成功返回 null |
#### 请求示例
```http
PUT /v3/admin/order/group-batch/supplies/2102611411027066881/quantity HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <admin token>
Content-Type: application/json
{"quantity":5}
```
#### 响应示例
```json
{"code": 200, "message": "成功", "data": null}
```
#### 空数据 / 降级响应
无列表出参,无空数据形态。备品行已被软删时返 589521,不会静默成功。
#### 错误响应
```json
{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null}
```
#### 业务边界
- 阶段门由该备品行反查所属团期后判定,窗口与新增口一致
- **「确认物资之后能不能改」不归本门管**:确认后仍可增删改是有意为之,窗口扩大后该结论不变
- 被拒时数量不变、行不被软删
---
### 5. 软删团期备品行 `DELETE /v3/admin/order/group-batch/supplies/{batchSuppliesId}`
**VO**: `Result<Void>`(无请求体)
#### 使用场景
物资 tab 删除一行备品。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| batchSuppliesId | path | Long | 是 | 须命中活跃备品行 | 不存在返 589521 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| data | Void | 成功返回 null |
#### 请求示例
```http
DELETE /v3/admin/order/group-batch/supplies/2102611411027066881 HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{"code": 200, "message": "成功", "data": null}
```
#### 空数据 / 降级响应
软删是幂等的:对已软删的行再调返 589521「备品行不存在」,不会重复写。
#### 错误响应
```json
{"code": 589598, "message": "出行后不可再配置导游 / 摄影 / 物资", "data": null}
```
#### 业务边界
- 窗口与新增 / 改数量完全一致
- 被拒时行的 `deleted_at` 保持为空
---
### 6. 取消成团 `POST /v3/admin/order/group-batch/{groupBatchId}/cancel-group`
**VO**: `Result<Void>`(无请求体)
#### 使用场景
团期从「资源准备中」退回「招募中」。本次**没有改它的入参或路径**,改的是它的阻塞条件与成功时的副作用。
#### 入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | path | Long | 是 | 正整数,团期聚合主键 | 不存在返 GROUP_BATCH_NOT_FOUND;非 `RESOURCE_PREPARING` 返 589501 |
#### 出参
| 字段 | 类型 | 说明 |
|---|---|---|
| data | Void | 成功返回 null,团期状态已回到 `RECRUITING` |
#### 请求示例
```http
POST /v3/admin/order/group-batch/2099750660965584898/cancel-group HTTP/1.1
Host: api.test.1814.love:9443
Authorization: Bearer <admin token>
```
#### 响应示例
```json
{"code": 200, "message": "成功", "data": null}
```
#### 空数据 / 降级响应
成功时无返回体。该团期没有任何导摄配置时,回收步骤是零行软删的空操作,不影响成功。
#### 错误响应
```json
{"code": 589502, "message": "取消成团被阻塞(有已确认子订单或已派单资源)", "data": null}
```
连续两次调用,第二次因状态已不是 `RESOURCE_PREPARING` 被 CAS 拒:
```json
{"code": 589501, "message": "团期状态不允许当前操作", "data": null}
```
#### 业务边界
- 仍阻塞:有已确认子订单(`PENDING_DEPARTURE` / `TRAVELLING` / `COMPLETED`)、`hotel_ready=true`、
`vehicle_ready=true`(且非整团免车)
- **不再阻塞**:已派导游、已派摄影
- 成功时依次:状态 CAS 回 `RECRUITING` → 四项 ready 与物资确认全部重置 → **回收导摄配置** → 登记配车释放命令
- 回收范围只含 `source=GROUP_BATCH` 的扇出行,子订单自己单独派的人不受影响
- 幂等:第二次调用被 589501 拒,不重复回收
---
## 四、契约约束与正确调用方式
- **判拒绝原因不要再认 589520 / 589552**。这两个码不再由上述五个配置接口抛出(589520 保留占位防号段复用,589552 仍由车辆派单、房务等别处使用)。统一认 **589598**。
- **589598 与 589553 是两件事**,不要合并成一个 toast:前者是「这个团已经出发了,配不了了」,后者是「这个班期还没有任何订单,先去建团」。
- 配导摄成功后,若调用方缓存了 `guide_ready` / `photographer_ready`,需重新拉取团期详情——本次修正了清空时的回落口径。
- 取消成功后,**团期人员名单会变空**,调用方若停在配人弹窗需主动刷新。
---
## 五、数据库行为
- 配导摄保存:整期(或 `scopeRoles` 范围内)软删旧配置行 + 写入新配置行 + 异步扇出到各活跃子订单;随后按配置结果回填团期行的两个 ready 标志
- 物资三口:分别为插入一行、更新一行的数量、软删一行
- 取消成团:状态 CAS 一行 + 重置该团期四项 ready 与物资确认 + 软删该团期全部导摄配置行 + 软删其各子订单中来源为团期扇出的人员分配行,**全部在同一个事务内**,任一步失败整体回滚
- 被阶段门拒绝时零写入:闸在所有写库动作之前
---
## 六、边界行为
- `CANCELLED`(已流团)按拒绝处理,返 589598
- 未建团(团期行尚未 Lazy 建)返 589553,**不会为配置动作提前建行**——否则会出现「零单可配 → 首单落地反而不可配 → 成团后又可配」这种非单调行为
- 创单时固化产品侧备品的系统路径不过阶段门,该豁免不变
- 「确认物资之后仍可增删改」不变
---
## 六.6、修改前后对比
| 维度 | 改前 | 改后 |
|---|---|---|
| 配导摄可配状态 | 已成团各态(招募中被拒) | `RECRUITING` / `RESOURCE_PREPARING` / `MATERIAL_PREPARING` / `PENDING_DEPARTURE` |
| 配导摄拒绝码 | 589552(未成团)/ 589553(未建团) | 589598(已出行 / 已取消)/ 589553(未建团) |
| 物资三口可配状态 | 仅 `MATERIAL_PREPARING` | 同上四态 |
| 物资三口拒绝码 | 589520 | 589598 |
| 取消成团:已派导游 / 摄影 | 返 589502 被阻塞 | 放行,且回收导摄配置 |
| 取消成团:房 / 车 ready | 返 589502 被阻塞 | **不变**,仍返 589502 |
| 招募中清空导摄后的 ready 位 | 卡在 true(与配置行数 0 矛盾) | 回落为 false |
---
## 六.7、影响评估
| 面 | 评估 |
|---|---|
| 管理后台配导摄 | 按钮本来就不看 `batchStatus`,招募中点得下去、只是被后端拒。后端放开后**前端零改动即可生效** |
| 管理后台物资 tab | 操作列按 `MATERIAL_PREPARING` 前置隐藏,**前端不改则本次无实际效果**,交接件见同批 frontend 条目 |
| 已有错误文案分支 | 按 589520 / 589552 做文案的地方需改认 589598 |
| 取消成团 | 可取消的团期变多;成功后人员名单会被清空,属预期 |
| 小程序端 | 不受影响,物资清单在小程序端是只读视图 |
| 状态机 | 不变,`MATERIAL_PREPARING` 阶段与「四项 ready 齐才推进」那条链一律不动 |
---
## 七、不影响范围
- 团期状态机的推进逻辑、四项 ready 的计算口径
- 流团(`disband`):只校验状态白名单,不看 ready 位,本次完全不受影响
- 子订单自己单独派的人员(`order_staff_assignment` 中 source 非 `GROUP_BATCH` 的行):回收不碰它们
- 车辆派单、房务等仍在用 `assertFormed` 的写口:口径不变
- 权限码、路径、入参结构、成功响应结构、网关配置
---
## 八、测试环境已验证
2026-09-23 12:15~12:25,`api.test.1814.love:9443`,分支 `dev-v3`(`fe752f16c`)。
| AC | 内容 | 结果 |
|---|---|---|
| 物资四态放行 | `RECRUITING` / `RESOURCE_PREPARING` / `MATERIAL_PREPARING` / `PENDING_DEPARTURE` 各跑「增 → 改数量 → 删」三端点 | 12 次调用全 200,自造行自删、零残留 |
| 物资出行后拒 | `REVIEWING` / `TRIP_FINISHED` / `CANCELLED` 各跑三端点 | 全返 589598;既有行的 `quantity` 未变、未软删、未新增行 |
| 配导摄四态放行 | 四态各保存「1002 GUIDE + 1003 PHOTOGRAPHER」 | 全 200 且落库;逐个还原为改前配置,四组还原判定全 ✔ |
| 配导摄出行后拒 | `REVIEWING` / `TRIP_FINISHED` / `CANCELLED` | 全返 589598;活跃行与表内总行数逐字未变 |
| 未建团 | 不存在的 `productBatchId` | 返 589553,未被新码吞掉 |
| 取消成团放行 + 回收 | 团期 `2099750660965584898`(`needs_guide=1 & guide_ready=1`,房车 ready 全 0,已确认子订单 0)——同一样本开工前实测返 589502 | 返 200;状态 `RESOURCE_PREPARING → RECRUITING`;`guide_ready` / `photographer_ready` 归 0;配置行与子订单扇出行同时间戳软删 |
| 房车仍阻断 | `hotel_ready=1` 与 `vehicle_ready=1` 两个样本 | 均返 589502;团期行与两张配置表逐字未变 |
| 幂等 | 对同一团期连调两次取消成团 | 第二次返 589501;三处读数与第一次后完全一致,无重复回收 |
本地单测:assignment + groupbatch + house 4103 条、archunit / core / requirement 等 3456 条、其余 26 个包 4621 条,全绿。
取证用到的写操作及还原:新增的备品行均由本次自行软删;配导摄的四个团期均按改前配置逐条还原;
取消成团样本 `2099750660965584898` 已按改前值还原(状态、两个 ready 位、配置行与扇出行的软删标记)。
---
## 十、相关文档
- Issue #8231(含开工前的 AC-6 实测与方案 C 裁决)
- PR #8234(主体)、PR #8237(ready 回落回归修复)
- 被推翻:#7287 T5(`assertFormed`)、#7023 AC-TD-13(物资单一阶段窗口)、wx 2026-09-15「放行但配置行保留」
- 保持不变:#7023 AC-TD-15(确认后仍可改)、#7441 PR-2e(整团免车的 ready 剥离)
---
## 关联 / 联系人
- 后端:jw
- 前端:mmg(物资 tab 显隐条件,见同批 frontend 条目)