- GET/PUT/POST settlement 三端点行为变化:已暂存 tab 持续带出未暂存预览行 - 行出参加 bizKey,暂存入参可透传 sourceType/bizKey - PUT 响应新增 warnMessage/missedCarryOverCount,新错误码 589756/589757 - 前端必须同步上线(否则双显双计)
14 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 8813 | 团期核单明细带出/暂存合并:已暂存 tab 也持续带出未暂存预览行,新增 bizKey 溯源 | admin | yst | 修改接口 | merged | not_required | pending | 后端 PR #8817 已合并 dev-v3(squash 4734715671),含 Flyway 迁移 V20261009_747(8 张 order_group_settlement_* 明细表加 biz_key 列),需部署 order-v3 后生效;前端必须同步改造:进入 tab 整份编辑 lines 数组(含 lineId=null 待带出行),暂存时原样透传 sourceType/bizKey,否则已暂存 tab 会出现旧暂存行与重新带出行双显双计 | 2026-10-10 | 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
{
"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
{
"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 的带出行,暂存仍成功):
{
"code": 0,
"data": {
"version": 4,
"warnMessage": "有 1 条带出成本未纳入本次暂存",
"missedCarryOverCount": 1
}
}
手加行(第 2 条)不传 sourceType/bizKey;带出行(第 1 条)原样透传。下次再 GET,那条漏掉的预览行仍会带出(lineId=null),不会丢。
8.3 业务失败:bizKey 不在带出集触发 589756
暂存时提交了一条 bizKey=D9|不存在的项目|票|1(不在本 tab 当前带出预览集):
{
"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 无处可取,退化为旧行为(可接受但不解决问题)。
前端改造要点:
- 进入 tab 拿到的完整 lines 数组(含 lineId=null 待带出行)整份编辑,不再区分「带出区/暂存区」两个数据源。
- 暂存时把带出预览行的 sourceType/bizKey 原样透传回去,整份提交。
- 渲染上可用 lineId==null 标「待带出」样式;用 missedCarryOverCount>0 toast warnMessage。
- 收到 589756 提示刷新重载(多半是预览集已变)。
回滚方案:后端回滚本 PR 即恢复旧行为(biz_key 列保留无害);前端若已上线透传逻辑,旧后端会忽略多余字段,不报错。建议前后端同窗口发布。
12. 注意事项
- bizKey 前端不解析、不构造、不修改,纯透传。格式见 §5.1 仅作理解参考。
- 金额/ID 一律字符串处理。
- editable 判定未变:仍 = status==DRAFT。
- 部署依赖:Flyway 迁移 V20261009_747 随 order-v3 部署自动执行,联调前先确认测试服已部署本 PR 之后的构建。
13. 关联 / 联系人
- Issue: wx/HL#8813
- PR: wx/HL#8817
- Commit: https://git.1814.love/wx/HL/commit/4734715671
- 后端负责人:yst(腰苏图)
- 前置契约:#8714 团期核单重做 8 类 tab(本仓 changelogs-v2/2026-10/04_8714_团期核单重做8类tab明细+公摊拆账-修改接口-管理后台.md)