docs(changelog): 订正 04_8714 团期核单确认门禁契约(#8783 PR #8784):confirm blocking 非空服务端硬拦 589568、负金额 400 改抛 589753、零值金额统一 0.00(修改接口·管理后台)
changelog-filename-gate / validate (push) Failing after 1s
changelog-filename-gate / validate (push) Failing after 1s
这个提交包含在:
@@ -0,0 +1,242 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8783"
|
||||
title: "团期核单确认门禁订正:blocking 非空服务端硬拦 589568 + 负金额改抛 589753 + 零值金额统一 0.00"
|
||||
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: "订正 04_8714 团期核单重做 changelog 的契约行为描述:confirm 在 blocking 非空时此前仅 panel 透出前端置灰、服务端 200 放行,现服务端硬拦 589568;行内负金额由此前 400 参数校验改为契约错误码 589753;panel/tab 空集合金额统一序列化为 0.00 两位小数。已合 dev-v3 未部署测试服。"
|
||||
updated_at: "2026-10-04"
|
||||
base: "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
|
||||
|
||||
```json
|
||||
{ "expectedVersion": 5 }
|
||||
```
|
||||
|
||||
响应(业务失败,团内订单 HL20261001001、HL20261001003 第 1 层核单未定稿):
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{
|
||||
"expectedVersion": 3,
|
||||
"lines": [
|
||||
{
|
||||
"lineId": null,
|
||||
"allocMode": "SHARED",
|
||||
"allocRule": "PER_HEAD_AVG",
|
||||
"actualAmount": -100.00,
|
||||
"hotelName": "图嘎营地",
|
||||
"roomCount": 5,
|
||||
"unitPrice": 380.00
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```json
|
||||
{ "expectedVersion": 3 }
|
||||
```
|
||||
|
||||
(库中当前 version 已为 5)
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"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. 关联 / 联系人
|
||||
|
||||
- Issue:https://git.1814.love/wx/HL/issues/8783
|
||||
- PR:https://git.1814.love/wx/HL/pulls/8784
|
||||
- Commit(squash merge):https://git.1814.love/wx/HL/commit/d414d7d00705
|
||||
- 被订正的原 changelog:`changelogs-v2/2026-10/04_8714_团期核单重做8类tab明细+公摊拆账-修改接口-管理后台.md`(同仓同目录)
|
||||
- 后端负责人:@yst
|
||||
在新工单中引用
屏蔽一个用户