docs(changelog): 团期核单明细带出/暂存合并 + bizKey 溯源(#8813)
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
- GET/PUT/POST settlement 三端点行为变化:已暂存 tab 持续带出未暂存预览行 - 行出参加 bizKey,暂存入参可透传 sourceType/bizKey - PUT 响应新增 warnMessage/missedCarryOverCount,新错误码 589756/589757 - 前端必须同步上线(否则双显双计)
这个提交包含在:
@@ -0,0 +1,305 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8813"
|
||||
title: "团期核单明细带出/暂存合并:已暂存 tab 也持续带出未暂存预览行,新增 bizKey 溯源"
|
||||
consumer: "admin"
|
||||
author: "yst"
|
||||
change_type: "修改接口"
|
||||
backend_status: "merged"
|
||||
gateway_status: "not_required"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: ""
|
||||
status_note: "后端 PR #8817 已合并 dev-v3(squash 4734715671),含 Flyway 迁移 V20261009_747(8 张 order_group_settlement_* 明细表加 biz_key 列),需部署 order-v3 后生效;前端必须同步改造:进入 tab 整份编辑 lines 数组(含 lineId=null 待带出行),暂存时原样透传 sourceType/bizKey,否则已暂存 tab 会出现旧暂存行与重新带出行双显双计"
|
||||
updated_at: "2026-10-10"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 团期核单明细带出/暂存合并 + bizKey 溯源(管理后台)
|
||||
|
||||
> ⚠️ **修改接口(前端必须同步上线)**:团期核单 8 类 tab 的「带出」语义从「暂存过的 tab 不再带出」改为「**始终合并返回**」——已暂存行照原样显示、未暂存的带出预览行继续带入(lineId=null)。前端交互改为「整份 lines 编辑 + 暂存时透传 sourceType/bizKey」。**新旧前端混跑会出现双显双计**,务必同步上线。
|
||||
|
||||
## 1. 接口背景
|
||||
|
||||
团期核单 8 类费用 tab(住宿/门票/餐食/车辆/导游/摄影师/其他支出/其他收入)里,大量明细行是系统从订单、资源准备、批次成本里**自动带出**的预览行(如各订单的房费、门票费、团车公摊),运营只需确认或微调后暂存。
|
||||
|
||||
旧行为的问题:一旦某个 tab 暂存过,系统就**不再带出**该 tab 的后续预览行——后续新报名的订单费用、新产生的批次成本就「消失」了,运营完全感知不到漏了钱。
|
||||
|
||||
本次(#8813)改为:
|
||||
|
||||
- **带出与暂存合并**:无论何时进入 tab,已暂存的行照常显示;**尚未被暂存覆盖的带出预览行继续带入**(lineId=null、带 sourceType/bizKey 标识),运营一眼看到「还有 N 条带出成本没纳入」。
|
||||
- **bizKey 溯源**:每条行新增 bizKey(来源业务键),暂存时原样回传,后端据此判断「这条暂存行对应哪条带出成本」,已暂存的预览行不再重复带出,防止重复计入。
|
||||
- **漏带提醒**:暂存时如果漏掉了某些带出行,响应里给 warnMessage / missedCarryOverCount 做 WARN 提示(不阻断)。
|
||||
|
||||
## 2. 变更清单
|
||||
|
||||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||||
|---|------|------|------|----------|------|
|
||||
| 1 | 分类 tab 明细查询 | GET | /v3/admin/order/group-batch/{groupBatchId}/settlement/{category} | ⚠️ 行为变化 | **暂存过的 tab 也持续带出未暂存预览行**;行出参加 bizKey;sourceType 正确区分 CARRY_OVER/BATCH_COST/MANUAL |
|
||||
| 2 | 整 tab 暂存 | PUT | /v3/admin/order/group-batch/{groupBatchId}/settlement/{category} | ⚠️ 行为变化 | 入参行可透传 sourceType/bizKey;响应新增 warnMessage/missedCarryOverCount;新增硬拦错误码 589756/589757 |
|
||||
| 3 | 新增单行 | POST | /v3/admin/order/group-batch/{groupBatchId}/settlement/{category}/lines | 修改 | 入参同样可透传 sourceType/bizKey(接受待带出行时使用),同 589756 校验 |
|
||||
|
||||
category 8 值:hotels / activities / meals / vehicles / guide-fees / photographer-fees / other-expenses / other-incomes。
|
||||
|
||||
DDL:8 张 order_group_settlement_* 明细表加 biz_key 列(迁移 V20261009_747),Flyway 部署时自动执行,**前端无需任何动作**。
|
||||
|
||||
## 3. 接口详情
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 服务 | hl-order-service-v3(端口 8086) |
|
||||
| 使用场景 | 管理后台 → 团期详情 → 核单 Tab:8 类费用明细查看/编辑/暂存 |
|
||||
| 认证 | 管理后台登录态(JWT);网关既有路由 /v3/admin/**,无新增网关配置 |
|
||||
| 权限码 | 沿用核单既有权限:group-batch:audit:view(GET)、group-batch:audit:edit(PUT / lines 新增) |
|
||||
| 幂等性 | PUT 整 tab 暂存仍走 main 主行锁 + expectedVersion CAS(过期仍吃 589573);新增单行天然幂等(无去重键) |
|
||||
| 限流 | 无特殊限流 |
|
||||
|
||||
## 4. 接口入参
|
||||
|
||||
### 4.1 路径参数(三个端点共有)
|
||||
|
||||
| 参数 | 位置 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| groupBatchId | Path | Long | 是 | 团期 ID |
|
||||
| category | Path | String | 是 | 费用类别 8 值之一(见 §6) |
|
||||
|
||||
### 4.2 PUT 整 tab 暂存请求体(GroupSettleTabSaveReqVO,仅列变化点)
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| expectedVersion | Number(int) | 是 | 乐观锁版本号,取 GET 响应里的 version;过期返 589573 |
|
||||
| lines | Array | 是 | **整份明细行数组(全量替换语义)**,行结构见 4.3 |
|
||||
|
||||
### 4.3 行结构 GroupSettleLineSaveReqVO(PUT 与 POST lines 共用)
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| lineId | String(Long) | 否 | 已暂存行带原 lineId;**带出预览行(GET 里 lineId=null 的行)暂存时不传**,由后端建档 |
|
||||
| itemName / spec / quantity / unitPrice / totalAmount / remark 等业务字段 | — | 按原契约 | 无变化,沿用 #8714 契约 |
|
||||
| **sourceType** | String | 否 | **新增可透传**:带出预览行暂存时**原样回传** GET 给的值(CARRY_OVER/BATCH_COST);手加行**不传**(后端默认 MANUAL) |
|
||||
| **bizKey** | String | 否 | **新增可透传**:带出预览行暂存时**原样回传** GET 给的 bizKey;手加行不传 |
|
||||
|
||||
> **铁律**:sourceType/bizKey 前端**不解析、不构造、不修改**,只做「GET 拿到什么 → PUT 原样回传什么」的透传。
|
||||
|
||||
## 5. 出参字段
|
||||
|
||||
### 5.1 GET 分类 tab 明细(GroupSettleTabRespVO,仅列变化点)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| status / version / editable / summary 等 | — | 无变化;editable 仍 = status==DRAFT |
|
||||
| lines[] | Array | **行为变化**:现在 = 已暂存行 ∪ 未暂存带出预览行(合并返回,不再互斥) |
|
||||
| lines[].lineId | String(Long) 或 null | 已暂存行=实际行 ID;**带出预览行=null**(前端据此区分并可渲染「待带出」样式) |
|
||||
| lines[].sourceType | String | **现在会正确区分**:CARRY_OVER(订单带出)/ BATCH_COST(批次成本带出)/ MANUAL(手加) |
|
||||
| **lines[].bizKey** | **String 或 null** | **新增**:来源业务键。带出行有值,手加行=null。**前端不解析**,仅透传 |
|
||||
|
||||
金额与 ID 字段一律以 **JSON 字符串**返回(防 JS 精度丢失)。
|
||||
|
||||
bizKey 格式参考(仅供理解,**不需要解析**):
|
||||
|
||||
- 单价型:`D1|驯鹿拉车体验|成人票|59`(slot|名称|规格|单价)
|
||||
- 总额型:`TOTAL:VEHICLE:SHARED:BUS` / `TOTAL:{类别}:L{序号}`
|
||||
|
||||
### 5.2 PUT 暂存响应(GroupSettleTabWriteRespVO,仅列变化点)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| version / lineIds 等既有字段 | — | 无变化 |
|
||||
| **warnMessage** | **String 或 null** | **新增**:暂存漏了某些带出行时的提示文案,如「有 2 条带出成本未纳入本次暂存」;无遗漏时为 null |
|
||||
| **missedCarryOverCount** | **Number(int)** | **新增**:漏带的带出行条数;0 = 无遗漏 |
|
||||
|
||||
> WARN 只是提醒,**暂存本身成功**(HTTP 200)。前端建议 toast 展示 warnMessage,不打断流程。
|
||||
|
||||
## 6. 枚举 / 数据字典
|
||||
|
||||
### 6.1 category(路径段,8 值)
|
||||
|
||||
hotels(住宿)/ activities(门票·游玩)/ meals(餐食)/ vehicles(车辆)/ guide-fees(导游)/ photographer-fees(摄影师)/ other-expenses(其他支出)/ other-incomes(其他收入)。中文名走数据字典 settlement_category。
|
||||
|
||||
### 6.2 sourceType(行来源,3 值)
|
||||
|
||||
| 值 | 含义 | 出现场景 |
|
||||
|---|---|---|
|
||||
| CARRY_OVER | 订单带出(从各子订单费用明细带出) | 带出预览行 / 由带出行暂存落库的行 |
|
||||
| BATCH_COST | 批次成本带出(团级公摊成本,如团车) | 同上 |
|
||||
| MANUAL | 手加行 | 前端手工新增的行(默认,不传即 MANUAL) |
|
||||
|
||||
## 7. 错误码
|
||||
|
||||
| 错误码 | 触发场景 | 前端处理 |
|
||||
|---|---|---|
|
||||
| **589756** | **明细行来源标识与本团带出成本不匹配**:提交的 sourceType/bizKey 不在本 tab 当前带出预览集内(如过期预览行、伪造 bizKey) | 硬拦。提示用户刷新 tab 重新加载最新带出集后再暂存 |
|
||||
| **589757** | **存在重复的来源成本行**:同一次提交里出现两条相同 bizKey 的行 | 硬拦。前端去重逻辑自查(正常整份编辑不会触发) |
|
||||
| 589573 | expectedVersion 过期(并发暂存冲突) | 沿用原处理:刷新重载 |
|
||||
|
||||
## 8. 示例
|
||||
|
||||
### 8.1 典型:tab 已暂存过,新带出预览行继续带入
|
||||
|
||||
GET /v3/admin/order/group-batch/1024/settlement/hotels
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"status": "DRAFT",
|
||||
"editable": true,
|
||||
"version": 3,
|
||||
"lines": [
|
||||
{
|
||||
"lineId": "88001",
|
||||
"sourceType": "CARRY_OVER",
|
||||
"bizKey": "D1|驯鹿拉车体验|成人票|59",
|
||||
"itemName": "驯鹿拉车体验-成人票",
|
||||
"quantity": "10",
|
||||
"unitPrice": "59.00",
|
||||
"totalAmount": "590.00"
|
||||
},
|
||||
{
|
||||
"lineId": "88002",
|
||||
"sourceType": "MANUAL",
|
||||
"bizKey": null,
|
||||
"itemName": "临时加床费",
|
||||
"quantity": "1",
|
||||
"unitPrice": "200.00",
|
||||
"totalAmount": "200.00"
|
||||
},
|
||||
{
|
||||
"lineId": null,
|
||||
"sourceType": "CARRY_OVER",
|
||||
"bizKey": "D2|星空蒙古包|标间|480",
|
||||
"itemName": "星空蒙古包-标间",
|
||||
"quantity": "5",
|
||||
"unitPrice": "480.00",
|
||||
"totalAmount": "2400.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 第 1 条是已暂存的带出行(有 lineId + bizKey);第 2 条是手加行(bizKey=null);第 3 条是**新带出的预览行**(lineId=null),等待运营确认。
|
||||
|
||||
### 8.2 边界:暂存整份提交,带出行透传 sourceType/bizKey,漏带 1 条给 WARN
|
||||
|
||||
PUT /v3/admin/order/group-batch/1024/settlement/hotels
|
||||
|
||||
```json
|
||||
{
|
||||
"expectedVersion": 3,
|
||||
"lines": [
|
||||
{
|
||||
"lineId": "88001",
|
||||
"sourceType": "CARRY_OVER",
|
||||
"bizKey": "D1|驯鹿拉车体验|成人票|59",
|
||||
"itemName": "驯鹿拉车体验-成人票",
|
||||
"quantity": "10",
|
||||
"unitPrice": "59.00",
|
||||
"totalAmount": "590.00"
|
||||
},
|
||||
{
|
||||
"lineId": "88002",
|
||||
"itemName": "临时加床费",
|
||||
"quantity": "1",
|
||||
"unitPrice": "200.00",
|
||||
"totalAmount": "200.00"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
响应(漏了 8.1 里那条 lineId=null 的带出行,**暂存仍成功**):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"version": 4,
|
||||
"warnMessage": "有 1 条带出成本未纳入本次暂存",
|
||||
"missedCarryOverCount": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 手加行(第 2 条)不传 sourceType/bizKey;带出行(第 1 条)原样透传。下次再 GET,那条漏掉的预览行仍会带出(lineId=null),不会丢。
|
||||
|
||||
### 8.3 业务失败:bizKey 不在带出集触发 589756
|
||||
|
||||
暂存时提交了一条 bizKey=D9|不存在的项目|票|1(不在本 tab 当前带出预览集):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 589756,
|
||||
"msg": "明细行来源标识与本团带出成本不匹配"
|
||||
}
|
||||
```
|
||||
|
||||
## 9. 业务边界
|
||||
|
||||
**适用**:
|
||||
|
||||
- 核单 DRAFT 状态下的 8 类 tab 查看/编辑/暂存/单行新增。
|
||||
- 「暂存过但仍想看到新带出成本」的场景——本次核心。
|
||||
|
||||
**不适用**:
|
||||
|
||||
- 核单 CONFIRMED 后:editable=false,带出行不再带入(tab 已锁定),写口全部被既有门禁拦截。
|
||||
- 前端自行拼装 bizKey:bizKey 由后端生成,前端伪造会吃 589756。
|
||||
|
||||
**特殊边界**:
|
||||
|
||||
- 带出预览行**不落库**,只有暂存后才成为正式行;所以 GET 里 lineId=null 的行在「刷新页面」后可能因业务数据变化而增减,属正常。
|
||||
- 同 tab 多次暂存:已暂存的带出行(bizKey 已落库)不会重复带出。
|
||||
|
||||
## 10. 修改前后对比
|
||||
|
||||
### 行为级
|
||||
|
||||
| 场景 | 修改前 | 修改后 |
|
||||
|---|---|---|
|
||||
| tab 已暂存过,再次进入 | **不再带出任何预览行**,新产生的订单费用/批次成本不可见 | **已暂存行 + 未暂存带出预览行合并返回**,新成本持续可见 |
|
||||
| 带出预览行标识 | sourceType 区分不可靠 | sourceType 正确区分 CARRY_OVER/BATCH_COST/MANUAL,且带 **bizKey** 溯源键 |
|
||||
| 暂存漏掉带出行 | 静默漏掉,运营无感知 | 响应给 warnMessage + missedCarryOverCount(WARN 不阻断) |
|
||||
| 伪造/过期 bizKey | 无校验 | 589756 硬拦 |
|
||||
| 同次提交 bizKey 重复 | 无校验 | 589757 硬拦 |
|
||||
|
||||
### 字段级
|
||||
|
||||
| 字段 | 修改前 | 修改后 |
|
||||
|---|---|---|
|
||||
| GET 出参 lines[].bizKey | 无 | **新增**(String,带出行有值,手加行 null) |
|
||||
| PUT/POST 入参 lines[].sourceType / bizKey | 不接收 | **新增可透传**(带出预览行暂存时原样回传) |
|
||||
| PUT 响应 warnMessage / missedCarryOverCount | 无 | **新增** |
|
||||
|
||||
## 11. 影响评估 / 回滚
|
||||
|
||||
**兼容性**:⚠️ **前端必须同步上线,属破坏性行为变化**。
|
||||
|
||||
- 新后端 + 旧前端:已暂存 tab 会同时出现「旧暂存行(bizKey=null)+ 重新带出的同类预览行」,**双显双计**,金额虚高。
|
||||
- 新前端 + 旧后端:bizKey 无处可取,退化为旧行为(可接受但不解决问题)。
|
||||
|
||||
**前端改造要点**:
|
||||
|
||||
1. 进入 tab 拿到的**完整 lines 数组(含 lineId=null 待带出行)整份编辑**,不再区分「带出区/暂存区」两个数据源。
|
||||
2. 暂存时把带出预览行的 sourceType/bizKey **原样透传**回去,整份提交。
|
||||
3. 渲染上可用 lineId==null 标「待带出」样式;用 missedCarryOverCount>0 toast warnMessage。
|
||||
4. 收到 589756 提示刷新重载(多半是预览集已变)。
|
||||
|
||||
**回滚方案**:后端回滚本 PR 即恢复旧行为(biz_key 列保留无害);前端若已上线透传逻辑,旧后端会忽略多余字段,不报错。建议前后端同窗口发布。
|
||||
|
||||
## 12. 注意事项
|
||||
|
||||
- bizKey 前端**不解析、不构造、不修改**,纯透传。格式见 §5.1 仅作理解参考。
|
||||
- 金额/ID 一律字符串处理。
|
||||
- editable 判定未变:仍 = status==DRAFT。
|
||||
- 部署依赖:Flyway 迁移 V20261009_747 随 order-v3 部署自动执行,**联调前先确认测试服已部署本 PR 之后的构建**。
|
||||
|
||||
## 13. 关联 / 联系人
|
||||
|
||||
- Issue: https://git.1814.love/wx/HL/issues/8813
|
||||
- PR: https://git.1814.love/wx/HL/pulls/8817
|
||||
- Commit: https://git.1814.love/wx/HL/commit/4734715671
|
||||
- 后端负责人:yst(腰苏图)
|
||||
- 前置契约:#8714 团期核单重做 8 类 tab(本仓 changelogs-v2/2026-10/04_8714_团期核单重做8类tab明细+公摊拆账-修改接口-管理后台.md)
|
||||
在新工单中引用
屏蔽一个用户