文件
hl-api-changelog/changelogs-v2/2026-09/21_8045_团期详情返回整团待收unpaidAmount-修改接口-管理后台.md
T
2026-09-21 15:13:53 +08:00

16 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 8045 团期详情返回整团待收 unpaidAmount admin jw(GIT) 修改接口 deployed verified verified mmg e680cf10c2b8c0377ea89d21ab13eea1e740f429 v2.1 2026-09-21 团期详情端点(A2)新增响应字段 unpaidAmount(整团待收),值 = max(0, receivableAmount − receivedAmount),恒非 null 恒非负,字符串型金额。此前该端点已同时返回 receivableAmount 与 receivedAmount,但没有待收字段,前端只能自己做减法——而本页子订单项的 balanceAmount 是另一套算法(扣退款、取消单归 0),前端自算会在同一屏里产生第二套口径,故由后端给出。【前端交付 2026-09-21 mmg:BatchHero 金额区补「待收」直显 detail.unpaidAmount(warning 色,缺失兜底 —,不自算),NTooltip 标注「退款不回减,权威待收以财务 tab 明细/合计为准」;FinanceTab 早已展示 totals/items unpaidAmount 零改动;BatchHero 8 例全过,hl-admin v2.1 e680cf10。】列表页(A1)早已有同名字段,本次是把详情页补齐,两处同源同公式。⚠️ 两点必须读:① 本字段按「毛累计已付」算,发生过退款的团偏小;逐户扣退款的权威待收在财务 tab 的 items/totals,不是财务 tab 的顶层 unpaidAmount(顶层与本字段同源同公式,数值一致)——同页展示两者时请在 UI 上区分标注(实测见「八」)。② 不要把它与子订单项的 balanceAmount 混用。本页既有四个金额字段(receivableAmount / receivedAmount / totalReceivable / totalReceived)的值、名称、形态逐字未变,纯增量。 2026-09-21 dev-v3

order-v3: 团期详情返回整团待收 unpaidAmount

服务: hl-order-service-v3 (端口 8086) PR: #8101 Issue: #8045 日期: 2026-09-21 影响范围: 管理后台「团期详情」页顶部金额区(列表点团期进去的那一页)


⚠️ 关键变化

  • 纯增量:既有字段一个都没改,只多返回一个 unpaidAmount。不接入的前端不受影响。
  • 不要再自己拿 receivableAmount − receivedAmount —— 后端已给出这个值,且做了解析保护(负数不透出)。
  • 不要与本页子订单项的 balanceAmount 混用:balanceAmount 是 per-order「应收 − 已退 − 已付」(扣退款、取消单归 0),与本字段同名不同义。#7066 曾专门花一节向前端解释过这个坑,这里再强调一次。
  • 🔴 有退款的团,本字段会偏大:本字段用的是「毛累计已付」(退款不回减),财务 tab 的逐户明细与合计(items[].unpaidAmount / totals.unpaidAmount)是逐户扣退款的。注意是「明细与合计」,不是财务 tab 的顶层 unpaidAmount —— 财务 tab 顶层的 unpaidAmount 与本字段同源同公式,数值一致(实测见第八节)。若把本字段与财务 tab 的合计放在同一屏,两者会差一个「累计已退」的量,请在 UI 上区分标注,权威待收以财务 tab 的逐户明细/合计为准。

一、背景

#7535 那一批统一了团期金额字段命名,同时给列表页(A1 分页项 GroupBatchPageItemRespVO)加了 unpaidAmount,但对详情页(A2)只做了 totalReceivable/totalReceived → receivableAmount/receivedAmount 的命名统一,漏了待收字段。

于是出现「列表页有待收、点进详情页反而没有」的观感缺口:运营要一眼看到「这个团还差多少钱没收」,只能心算,或退回列表页看。

需求来源:前端 2026-09-20《前端待后端交付清单》第 3 项,原文标注「无工单,待排期」;本单为该事项排期。前端明确拒绝自算,理由是「口径会漂移」——这个担心成立,见上一节。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 团期详情(A2) GET /v3/admin/order/group-batch/:id 修改 响应新增 unpaidAmount(整团待收)

财务 tab 端点 GET /v3/admin/order/group-batch/:id/finance 本次一行未改,列在本节仅为对照口径。


三、接口详情

1. 团期详情 GET /v3/admin/order/group-batch/:id

VO: Result<GroupBatchDetailRespVO>

使用场景

管理后台「团期详情」页主数据。进入该页时调用一次,页面顶部的整团应收 / 已收 / 待收 三格都读本响应。

入参

字段 位置 类型 必填 约束 说明
groupBatchId Path String(雪花 ID) ✅ 团期 ID 不存在或已软删返回 589500

出参 Result<GroupBatchDetailRespVO>

本次只新增 1 个字段,其余字段一律不动、不改名、不改类型。

字段 类型 说明
receivableAmount String(金额) 整团应收(Σ 在团子订单应付总额)。不变
receivedAmount String(金额) 整团已收(Σ 毛累计已付,退款不回减)。不变
unpaidAmount String(金额) 【新增】 整团待收 = max(0, receivableAmount − receivedAmount)。恒非 null、恒 ≥ 0
totalReceivable String(金额) 已废弃,与 receivableAmount 逐字同值。不变(只标记不删)
totalReceived String(金额) 已废弃,与 receivedAmount 逐字同值。不变(只标记不删)

金额一律是字符串(如 "12000.00"),不是 JSON 数字,不要当数字解析。

请求示例

GET /v3/admin/order/group-batch/2101908228566908930

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "groupBatchId": "2101908228566908930",
    "receivableAmount": "4000.00",
    "receivedAmount": "2000.00",
    "unpaidAmount": "2000.00",
    "totalReceivable": "4000.00",
    "totalReceived": "2000.00"
  },
  "success": true
}

(仅列相关字段,其余字段保持原样。)

空数据 / 降级响应

无在团子订单的空团,三个金额同为 "0"(注意不是 "0.00",与列表页 A1 的行为一致,前端自行格式化):

{
  "code": 200,
  "data": {
    "receivableAmount": "0",
    "receivedAmount": "0",
    "unpaidAmount": "0"
  },
  "success": true
}

错误响应

团期不存在或已软删:

{
  "code": 589500,
  "message": "团期不存在",
  "data": null,
  "success": false
}

无查看权:

{
  "code": 589507,
  "message": "无权限访问该团期",
  "data": null,
  "success": false
}
码 触发
589500 groupBatchId 不存在或已软删
589507 调用方无团期查看权;定制师读不属于自己的团期

鉴权失败在本项目是 HTTP 200 + body code=401,不要只看 HTTP 状态码。

业务边界

  • 本字段是纯内存计算,不新增查询、不新增 Feign 调用;响应变慢与它无关。
  • 不是权限变更:A2 走一般查看权(PERMISSION_VIEW),本字段不扩大任何信息暴露面——它是由同一响应里已经返回的 receivableAmount 与 receivedAmount 相减得到的,信息增量为零。
  • 口径:receivedAmount 是毛累计已付、退款不回减,所以发生过退款的团本字段偏小(应收没变、已付也没被退款冲减,差额仍然是「待收」)。
  • 标度:沿用同一行 receivableAmount / receivedAmount 的原始标度,不做二次收敛。同一行三个金额标度一致。
  • 负值保护:已收多于应收(退款 / 多收留下的历史脏数据)时返回 "0",不会出现负号。

四、契约约束与正确调用方式

  • 不要自己算:直接读 unpaidAmount,不要写 receivableAmount - receivedAmount。
  • 不要用 balanceAmount 顶替:那是子订单项的 per-order 口径(应收 − 已退 − 已付,取消单归 0),与本字段同名不同义。
  • 财务 tab 的对照口径要说清是哪一个:
    • 财务 tab 顶层 unpaidAmount —— 与本字段同源同公式,数值一致(不是逐户扣退款的)。
    • 财务 tab items[].unpaidAmount / totals.unpaidAmount —— 逐户扣退款的权威口径。有退款的团,它与本字段会差一个「累计已退」。
  • 三个金额都是字符串,"0" 与 "0.00" 都可能出现(空团是前者),比较时请按数值比较而不是字符串相等。

六、边界行为

场景 行为
正常有在团子订单 unpaidAmount = 应收 − 已收(两位小数)
无在团子订单(空团) 三个金额同为 "0",非 null
已收 > 应收(多收 / 退款脏数据) unpaidAmount 返回 "0",不透负数。TEST 实测见第八节
发生过退款的团 本字段按毛已付算,比财务 tab 的逐户合计偏大;与财务 tab 顶层一致
团期不存在 / 已软删 589500
无查看权 HTTP 200 + body code=589507
老前端不读新字段 纯增量,无影响

六.6、修改前后对比

字段级对比

字段 改前 改后
unpaidAmount 不存在(响应体里没有这个 key) "12000.00"(字符串型金额)
receivableAmount "48000.00" "48000.00"(逐字未变)
receivedAmount "36000.00" "36000.00"(逐字未变)
totalReceivable "48000.00"(已废弃) "48000.00"(逐字未变,仍只标记不删)
totalReceived "36000.00"(已废弃) "36000.00"(逐字未变)
其余全部字段 — 一个都没动

行为级对比

行为 改前 改后
详情页「待收尾款」从哪来 前端自己拿 receivableAmount − receivedAmount 算 后端返回 unpaidAmount,前端直接读
已收大于应收时 前端自算会拿到负数,得自己处理 后端返回 "0",不透负数
HTTP 状态 / 错误码 / 判权 — 不变
响应耗时 — 不变(新增字段是内存计算,不加查询、不加 Feign)

六.7、影响评估

  • 是否破坏向后兼容: 否。纯增量字段,既有四个金额字段的值 / 名称 / 类型 / JSON 形态逐字未变(TEST 改前改后逐字对照见第八节)。
  • 前端是否必须同步上线: 否。不接入则详情页保持现状(没有待收那一格)。
  • 前端 workaround 清理点: 若前端此前在详情页自己算过待收(receivableAmount - receivedAmount),现在可以撤掉,改读 unpaidAmount。
  • 回滚: 回滚本 PR 即可,只读端点、无数据变更、无表结构变更。

七、不影响范围

  • GET /v3/admin/order/group-batch/:id/finance(财务 tab)一字未改。
  • GET /v3/admin/order/group-batch(A1 列表)一字未改,它的 unpaidAmount 早就存在。
  • 子订单项 balanceAmount(GroupBatchOrderItemRespVO)未动。
  • 判权、错误码、网关路由、事务与锁均未变。
  • 其他微服务(hl-finance / hl-product-service-v2 / hl-user-service 等)未动。
  • 无数据库表结构变更,无 Flyway 迁移。

八、测试环境已验证

TEST 环境(hl-order-service-v3 + hl-gateway 均为 dev-v3 @ c238f38c3,BEHIND 0/N,STATE ok),2026-09-21,走真实网关 https://api.test.1814.love:9443。

构建身份探针(改前 / 改后同端点对照,确认跑的确实是本单代码):

改前(dev-v3 旧字节)GET /v3/admin/order/group-batch/2101908228566908930  → 响应体没有 unpaidAmount 这个 key   ✓
改后(dev-v3 c238f38c3)同 URL                                            → 出现 "unpaidAmount": "2000.00"       ✓
AC-1  金额正确 + 形态:团 2101908228566908930
        receivableAmount "4000.00" / receivedAmount "2000.00" / unpaidAmount "2000.00"
        手算 max(0, 4000.00 − 2000.00) = 2000.00,一致;三个都是 JSON 字符串          ✓
      团 2101906599658618882:应收 "6000.00" / 已收 "0.00" / 待收 "6000.00"           ✓
AC-2  已收 > 应收边界(自造 fixture,见「造数清单」):
        应收 "2000.00" / 已收 "3000.00" → unpaidAmount = "0",无负号,非 null          ✓
AC-3  空团:团 2101250106387726338 无在团子订单
        receivableAmount "0" / receivedAmount "0" / unpaidAmount "0"(同值同形态)     ✓
AC-4  纯增量:四个既有字段改前 → 改后逐字一致(4 个团全部比对,含空团与有退款的团)    ✓
AC-5  注解四层文案(公式 / null 按 0 参与 / 退款不回减 / 权威口径指向财务 tab),
        并由新增的单测钉住,删掉任一层即红                                          ✓
AC-6  「应收减已收」仍只有一处实现:新增行不含 `.subtract(`;实参调既有 calcUnpaid     ✓
AC-7  calcUnpaid 的「只此一处减法」javadoc 已列入 toDetailVO 这条新调用方              ✓
AC-8  精确测试:GroupBatchConverterTest 108 + GroupBatchAliasFieldSerializationTest 7
        + GroupBatchQueryControllerTest 9 = 124 跑 / 0 失败 / 0 错误                   ✓
      变异证明:注释掉 toDetailVO 那一行后恰好这 4 个转换器用例红(108 跑 / 4 失败),
        控制器与序列化类保持绿 —— 新断言不是恒真                                     ✓
AC-9  MapperBoundaryArchTest 门禁:本单零新增违规,门禁红系既有基线
        (干净的 c62907410 上同样 27 跑 / 1 失败,9 处违规全在 payment → refund.mapper,
         见 [#7989](https://git.1814.love:8443/wx/HL/issues/7989),P1,yst 属主)
AC-10 网关实测(上方 URL 与 deploy-status 两行)                                       ✓
AC-11 有退款的团与财务 tab 的口径对照,见下                                            ✓

AC-11 口径对照(团 2099459274966016001,子订单 HL20260914192431793 有一笔 100.00 的成功退款):

取值处 数值 是否扣退款
本单新增的 A2 unpaidAmount "1900.00" 否(毛已付)
财务 tab 顶层 unpaidAmount "1900.00" 否(与本字段同源同公式)
财务 tab totals.unpaidAmount "1800.00" 是(逐户扣退款)
财务 tab items[0].unpaidAmount "1800.00" 是

1900.00 − 1800.00 = 100.00 = 该团那笔退款金额。即:本字段与财务 tab 顶层一致,与财务 tab 的逐户合计差一个「累计已退」——前端要对齐的权威口径是后者。

扫描口径补充:TEST 上 237 个团期,顶层 unpaidAmount 与「应收 − 已收」无一不等(两者同源);顶层与 totals 不等的恰好 1 个,就是上表这个有退款的团。

送测数据(自造,请勿清理):

groupBatchId 名称 用途 现状
2101927290046943234 #8045-AC2多收边界 AC-2「已收 > 应收」边界造数(其子订单 2101927289925308418 的 paid_amount 曾临时置 3000.00,已还原为 0.00) 挂 1 个子订单(PENDING_PAY),班期出发日 2026-12-20

该班期挂着订单,删不掉(BATCH_HAS_ENROLLED_ORDERS),留着不干扰他人:未被可报名谓词 / 选品列表 / order-v3 下单闸采纳。

其他 AC 用的是 TEST 上既有真实团期,未改任何既有数据。


十、相关文档

  • 工单 #8045
  • #7535 团期金额字段命名统一(A1 加了 unpaidAmount,A2 漏了,本单补齐)
  • #7066 解释过「两个 balanceAmount 同名不同义」的那个坑
  • #7989 order-v3 ArchTest 门禁既有基线红(与本单无关,登记在案)

关联 / 联系人

链接

联系人

  • 后端负责人: @jw
  • 前端负责人: @mmg