文件
hl-api-changelog/changelogs-v2/2026-10/04_8783_团期核单确认门禁订正-修改接口-管理后台.md
2026-10-04 14:39:43 +08:00

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 8783 团期核单确认门禁订正:blocking 非空服务端硬拦 589568 + 负金额改抛 589753 + 零值金额统一 0.00 admin yst 修改接口 merged not_required implemented mmg aef8ddd60341b789429a9dd9432e8a7f56783190 v2.1 2026-10-04 订正 04_8714 团期核单重做 changelog 的契约行为描述:confirm 在 blocking 非空时此前仅 panel 透出前端置灰、服务端 200 放行,现服务端硬拦 589568;行内负金额由此前 400 参数校验改为契约错误码 589753;panel/tab 空集合金额统一序列化为 0.00 两位小数。已合 dev-v3 未部署测试服。前端已交付(2026-10-04):确认核单 catch 增 589568 分支重读 panel 刷新 version 与 blockingOrderIds 置灰态(message 自带未定稿清单拦截器透);负金额输入既有 :min=0 无 400 特判、零值展示走 formatPrice 数值化无 "0" 等值判断,两处天然零适配,提交 aef8ddd60。 2026-10-04 dev-v3

order-v3 groupbatch:团期核单确认门禁订正(管理后台)—— 订正 04_8714

⚠️ 本文是订正 changelog,修订《04_8714_团期核单重做8类tab明细+公摊拆账-修改接口-管理后台.md》中三处契约行为描述。原文件保留不改动;两处描述不一致时以本文为准。接口路径、入参结构、出参结构均无变化,变化只在服务端行为 / 错误码 / 金额序列化格式三处。

1. 接口背景

#8714 团期核单重做落地后,#8783(PR #8784)补齐三处契约缺口:

  1. 确认门禁漏拦:原契约 panel 透出 blockingOrderIds 供前端把确认按钮置灰,但服务端 confirm 端点并未校验——前端绕过置灰直接调 POST …/settlement/panel/confirm 时,团内仍有子订单第 1 层核单未定稿也能 200 确认成功。现服务端补上硬校验,blocking 非空即拒绝。
  2. 负金额错误码不合契约:行内金额/单价/数量为负时,此前由 Bean Validation(@DecimalMin)拦截返通用 400,不属于核单域错误码体系。现删除字段级 @DecimalMin,改在 Service 层 resolveSplits 入口统一校验,按契约抛 589753。
  3. 零值金额格式不统一:panel 各分类合计、户视图已摊成本/收入、tab allocatedTotal 等空集合金额,此前部分路径序列化为 "0"(无小数位),与 tab 两位小数口径不一致。现统一为 "0.00"。

2. 变更清单

# 接口 变更点 类型
1 POST /v3/admin/order/group-batch/{groupBatchId}/settlement/panel/confirm 新增服务端门禁:在团子订单第 1 层核单未全部定稿(blocking 非空)时拒绝确认,抛 589568(此前 200 放行,仅 panel 透出 blockingOrderIds 供前端置灰) 🔧 行为变更
2 PUT …/settlement/{8 个 tab} / POST …/settlement/lines / POST …/settlement/alloc-preview 行内金额/单价/数量为负,由 Bean Validation 400(通用参数错误)改为契约错误码 589753;涉及字段见 §4 ⚠️ 错误码变化
3 GET …/settlement/panel / GET …/settlement/{tab} 空集合金额(分类合计 / 户 allocatedCost/allocatedIncome / tab allocatedTotal 等)序列化由可能为 "0" 统一为 "0.00"(两位小数) 🔧 出参格式统一

路径前缀统一为 /v3/admin/order/group-batch/{groupBatchId}/settlement,下文用 … 代指。接口签名(路径 / 入参字段 / 出参字段)零变化。

3. 接口详情

项 说明
服务 hl-order-service-v3(端口 8086)
路径前缀 /v3/admin/order/group-batch/{groupBatchId}/settlement
使用场景 管理后台 → 团期详情 → 核单 Tab:确认核单、明细行金额录入
认证 管理后台登录态(JWT);网关既有路由 /v3/admin/**,无新增网关配置
权限码 group-batch:audit:allocate(确认核单);group-batch:audit:edit(tab PUT / lines 新增);缺码一律 589507
幂等性 与 04_8714 一致:写口不加 @Idempotent,由 main 主行锁 + expectedVersion CAS 兜底(过期 589573)
限流 无特殊限流

4. 接口入参

入参结构与 04_8714 §4 完全一致,此处只列本次行为变化涉及的字段(GroupSettleLineSaveReqVO 及其 splits[]):

字段 类型 必填 原约束(@DecimalMin,删) 现约束(Service 校验)
budgetAmount number 可空 ≥0,违例 400 为负抛 589753
actualAmount number ✅ ≥0,违例 400 为负抛 589753
unitPrice number 可空 ≥0,违例 400 为负抛 589753(住宿/餐食/其他收入)
ticketUnitPrice number 可空 ≥0,违例 400 为负抛 589753(门票·游玩)
quantity number 可空 ≥0,违例 400 为负抛 589753(餐食/其他收入)
dailyPrice number 可空 ≥0,违例 400 为负抛 589753(车辆)
perDayFee number 可空 ≥0,违例 400 为负抛 589753(导游/摄影师)
splits[].ratio number 可空 ≥0,违例 400 为负抛 589753
splits[].amount number 可空 ≥0,违例 400 为负抛 589753

POST …/settlement/panel/confirm 入参不变:

字段 类型 必填 说明
expectedVersion int ✅ 乐观锁版本(GET panel/tab 返回的 version 原样回传)

5. 出参字段

出参结构与 04_8714 §5 完全一致。唯一变化是零值金额的序列化格式:

字段 原来(空集合时可能) 现在(统一)
panel categories[].actualAmount / allocatedAmount / unallocatedAmount "0" "0.00"
panel households[].allocatedCost / allocatedIncome / grossProfit "0" "0.00"
tab allocatedTotal / actualTotal "0" "0.00"

非零金额不受影响(此前已是两位小数)。金额仍为 JSON 字符串,前端按字符串处理即可;若有对 "0" 的等值判断 / 解析分支需放宽为兼容 "0.00"(建议统一 Number(x) 或字符串比较改为数值比较)。

GET …/settlement/panel 中与本门禁相关的字段(不变,重述便于对照):

字段 类型 说明
readyToAllocate boolean 各户第 1 层核单是否全部定稿;false 时 confirm 必吃 589568
blockingOrderIds string[] 第 1 层核单未定稿的子订单 ID;非空时 confirm 必吃 589568

6. 枚举 / 数据字典

本次无枚举 / 字典变化。

7. 错误码

错误码 文案({0} 为动态定位串) 触发场景 本次变化
589568 整团核单当前状态不允许该操作:{0} ① CONFIRMED 后任何写操作(原有);② 确认核单时在团子订单第 1 层核单未全部定稿——{0} 带未定稿订单号清单,「、」分隔,与 panel 的 blockingOrderIds 一一对应 ⚠️ 新增触发场景②(此前 confirm 不校验,200 放行)
589753 核单拆账入参非法:{0} 金额/单价/数量为负、未知费用类别等入参层非法;{0} 指明具体字段与值 ⚠️ 负金额场景由此前 400 改为 589753(删 @DecimalMin,改 Service 层 resolveSplits 入口校验)

其余错误码(589507 / 589567 / 589571 / 589572 / 589573 / 589750 / 589751 / 589752 / 589754 / 589755)与 04_8714 §7 一致,无变化。

前端适配点:

  • 589568 的 toast / 弹窗需覆盖「确认时 blocking 非空」场景——message 里已带未定稿订单号清单,可直接展示;建议同时刷新 panel 更新 blockingOrderIds。
  • 负金额入参不再走 400 分支,改走 589753 分支;若前端此前对 400 做通用「参数错误」提示,现在会收到带具体字段定位的 589753 message,体验更好。

8. 示例

8.1 典型:确认核单时有子订单第 1 层核单未定稿,被 589568 拒绝

请求:

POST /v3/admin/order/group-batch/1934567890123456789/settlement/panel/confirm
Content-Type: application/json
{ "expectedVersion": 5 }

响应(业务失败,团内订单 HL20261001001、HL20261001003 第 1 层核单未定稿):

{
  "code": 589568,
  "message": "整团核单当前状态不允许该操作:以下订单未完成核单:HL20261001001、HL20261001003"
}

对照:GET …/settlement/panel 此时返回 "readyToAllocate": false、"blockingOrderIds": ["1934567890123450001", "1934567890123450003"]。订正前:同样的请求返回 200 确认成功(服务端不拦);订正后:服务端硬拦,前端置灰只是体验层,不再是唯一防线。

8.2 边界:明细行金额为负,抛 589753(不再是 400)

请求:

PUT /v3/admin/order/group-batch/1934567890123456789/settlement/hotels
Content-Type: application/json
{
  "expectedVersion": 3,
  "lines": [
    {
      "lineId": null,
      "allocMode": "SHARED",
      "allocRule": "PER_HEAD_AVG",
      "actualAmount": -100.00,
      "hotelName": "图嘎营地",
      "roomCount": 5,
      "unitPrice": 380.00
    }
  ]
}

响应:

{
  "code": 589753,
  "message": "核单拆账入参非法:actualAmount 不能为负(-100.00)"
}

订正前:同样请求由 Bean Validation 拦截,返回 HTTP 400 / 通用参数校验错误(不在核单域错误码体系内);订正后:统一走契约错误码 589753,message 带字段名与具体值。splits[].amount / splits[].ratio / dailyPrice / perDayFee 等其余 §4 列出的字段为负时同样抛 589753。

8.3 业务失败:expectedVersion 过期(589573,既有行为不变,供对照)

请求:

POST /v3/admin/order/group-batch/1934567890123456789/settlement/panel/confirm
{ "expectedVersion": 3 }

(库中当前 version 已为 5)

响应:

{
  "code": 589573,
  "message": "整团核单数据已被他人修改(当前版本 5,提交版本 3),请刷新后重试"
}

处理方式不变:重新 GET panel 读回全量(含新 version)再重试,不能本地 version+1。

9. 业务边界

适用:

  • 团期核单确认(panel/confirm)的服务端兜底校验——所有在团子订单第 1 层核单定稿后才允许确认。
  • 明细行金额录入的合法性校验——全部金额/单价/数量/比例字段不允许为负。

不适用:

  • 逐子订单第 1 层核单本身的确认流程(那是子订单核单域的事,本门禁只消费其结果)。
  • 确认后修改:CONFIRMED 不可逆(与 04_8714 一致)。

特殊边界:

  • 置灰 ≠ 防线:panel blockingOrderIds / readyToAllocate 仍正常透出,前端应继续据此置灰确认按钮提升体验;但服务端现在会真拦,前端必须处理 589568 回执(toast message + 刷新 panel),不能假设按钮置灰后用户永远触发不到。
  • 零值金额判断:前端若有 amount === "0" 之类的字符串等值判断,需改为数值比较或兼容 "0.00"。

10. 修改前后对比

行为级对比

行为 原来(04_8714 描述 / 订正前实现) 现在(#8784 订正后)
confirm 时 blocking 非空 服务端不校验,200 放行确认成功;blockingOrderIds 只在 panel 透出供前端置灰 服务端硬拦,抛 589568,message 带未定稿订单号清单(「、」分隔)
行内金额/单价/数量为负 Bean Validation @DecimalMin 拦截,HTTP 400 通用参数错误 Service 层 resolveSplits 入口校验,契约错误码 589753,message 带字段定位
空集合金额序列化 部分路径输出 "0"(无小数位),与 tab 两位小数口径不一致 统一 "0.00"(两位小数)

字段级对比

无字段增删 / 改名 / 类型变化;仅 §4 列出字段的校验位置与错误码变化(@DecimalMin 注解删除,改 Service 校验)。

11. 影响评估 / 回滚

  • 破坏兼容:轻微。接口签名零变化;行为变化三处——① confirm 新增拒绝场景(原先能确认成功的请求现在被拒,属安全收紧,前端需新增 589568 处理分支);② 负金额错误码 400 → 589753(前端若按 400 特判需改判 589753);③ 零值金额 "0" → "0.00"(前端若有字符串等值判断需放宽)。
  • 前端必须同步上线:否(后端已合 dev-v3 未部署测试服;前端适配可在联调窗口内完成)。前端原有「blocking 置灰」逻辑保留,只是不再唯一依赖它。
  • workaround 清理点:若前端此前因服务端不拦而自行做了 confirm 前的 blocking 预校验弹窗,可保留(体验层);若有对负金额 400 的特判文案,改挂 589753。
  • 回滚方案:后端回滚 = revert PR #8784 即可(纯代码改动,无 DDL / 无数据迁移)。

12. 注意事项

  1. 本文优先于 04_8714:两份 changelog 对 confirm 门禁 / 负金额错误码 / 零值金额格式的描述不一致时,以本文为准。04_8714 的其余内容(接口清单 / 出入参结构 / 枚举字典 / 拆账规则 / CAS 语义)继续有效。
  2. 589568 message 可直接展示:未定稿订单号清单已内嵌 message(「、」分隔),前端无需自行查 blockingOrderIds 拼装;但建议同时刷新 panel 让置灰状态与服务端一致。
  3. 负金额提示走 589753:不要再期待 400;message 带字段名与非法值,可直接 toast。
  4. 金额仍按字符串处理:"0.00" 统一后前端解析逻辑应天然兼容,只需清理对 "0" 的硬编码等值判断。

13. 关联 / 联系人