文件
hl-api-changelog/changelogs-v2/2026-10/10_8813_团期核单带出合并-修改接口-管理后台.md
T
yaosutu aa11cd2610
changelog-filename-gate / validate (push) Failing after 2s
docs(changelog): 团期核单明细带出/暂存合并 + bizKey 溯源(#8813)
- GET/PUT/POST settlement 三端点行为变化:已暂存 tab 持续带出未暂存预览行
- 行出参加 bizKey,暂存入参可透传 sourceType/bizKey
- PUT 响应新增 warnMessage/missedCarryOverCount,新错误码 589756/589757
- 前端必须同步上线(否则双显双计)
2026-10-10 12:44:09 +08:00

14 KiB
原始文件 Blame 文件历史

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 无处可取,退化为旧行为(可接受但不解决问题)。

前端改造要点:

  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. 关联 / 联系人