diff --git a/changelogs-v2/2026-10/01_8677_团期预支可支取上限改为整团已收-修改接口-管理后台.md b/changelogs-v2/2026-10/01_8677_团期预支可支取上限改为整团已收-修改接口-管理后台.md new file mode 100644 index 00000000..4bb1bf7b --- /dev/null +++ b/changelogs-v2/2026-10/01_8677_团期预支可支取上限改为整团已收-修改接口-管理后台.md @@ -0,0 +1,293 @@ +--- +schema: "hl-changelog/v2" +ticket: "8677" +title: "团期预支可支取上限改为「整团已收(扣已退)− 在途」——GB-ADM-040 advanceAvailable 与 GB-ADM-042 发起上限同步改口径" +consumer: "admin" +author: "jw(GIT)" +change_type: "修改接口" +backend_status: "deployed" +gateway_status: "verified" +frontend_status: "not_required" +frontend_owner: "" +frontend_ref: "" +target_release: "" +verified_at: "" +status_note: "团期预支的可支取上限原为「团期尾款池(Σ 各户 max(0, 应收 − 已付))− 在途」,全额收款的团可支取恒为 0(TEST「11月1日额济纳胡杨林深秋4日游」应收 = 已收 26340.00 → 0.00),部分收款的团反倒能按还没收的钱预支。jw 2026-10-01 定案改为「团期已收池 − 在途」:已收池 = Σ 本团活跃子订单 max(0, 已付 − 已退),CANCELLED 户记 0;硬上限,超额 585004、无放宽通道;普通订单上限不改;部分收款团上限收紧属预期;存量不回溯(在途已超新上限时可支取显示 0.00、只拦新申请)。GB-ADM-040 的 advanceAvailable 与 GB-ADM-042 的发起校验共用同一方法,同时生效。路径、入参、出参字段名与类型零变化,错误码不变;变的是取值口径,属「语义取值」变化,按 jw 2026-09-18 口径推送。已合并 dev-v3(PR #8686,merge commit f4f545148)并部署测试服。hl-ui v2.1 弹窗「剩余可支取」与财务 Tab「可支取余额」都直接显示后端 advanceAvailable,前端零改动,frontend_status 记 not_required。" +updated_at: "2026-10-01" +base: "dev-v3" +--- + +# 团期预支可支取上限改为整团已收(管理后台) + +> **服务**: hl-order-service-v3(端口 8086/8186) + +## 一、接口背景 + +团期「发起团期预支」弹窗里的「剩余可支取」、财务 Tab 的「可支取余额」,以及发起时的超额校验,原先都按**整团还没收的尾款**算上限。 +全额收款的团尾款为 0,于是一分钱都预支不了;只收了一部分的团,反倒能按还没收的钱预支。 + +本次改为只预支已经收到手的钱:上限 = 整团已收(扣已退)− 在途预支。 + +## 二、变更接口清单 + +| # | 接口 | 方法 | 路径 | 变更类型 | 说明 | +|---|---|---|---|---|---| +| 1 | GB-ADM-040 团期财务总览 | GET | `/v3/admin/order/group-batch/{groupBatchId}/finance` | 修改接口 | 出参 `advanceAvailable` 取值口径改为「团期已收池 − 在途」;字段名、类型与其余字段零变化 | +| 2 | GB-ADM-042 发起团期预支 | POST | `/v3/admin/order/group-batch/{groupBatchId}/advance` | 修改接口 | 金额上限改为同一口径;入参、出参、错误码零变化 | + +## 三、接口详情 + +### 1. GB-ADM-040 团期财务总览 `GET /v3/admin/order/group-batch/{groupBatchId}/finance` + +**VO**: `GroupBatchFinanceRespVO` + +#### 使用场景 + +团期详情「财务」Tab 切换即加载:四张金额卡、可支取余额、待审批预支、逐户付款。「发起团期预支」弹窗的「剩余可支取」也直接取本接口的 `advanceAvailable`。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| groupBatchId | path | Long | 是 | 正整数,团期聚合主键 | 团期 ID,不存在返 589501 | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| advanceAvailable | BigDecimal(字符串序列化) | **本次改口径**。可支取余额 = max(0, 团期已收池 − 在途)。团期已收池 = Σ 本团活跃子订单 max(0, 已付 − 已退),CANCELLED 户记 0;在途 = 本团期待审批 + 已通过 + 已付款的预支(团期级 ∪ 子订单级,口径不变)。即发起预支的硬上限 | +| receivedAmount | BigDecimal | 整团已收(既有字段,本次未改)。毛已付,**不扣退款**;有退款时 `advanceAvailable` 的基数会小于它 | +| receivableAmount | BigDecimal | 整团应收(既有字段,本次未改) | +| unpaidAmount | BigDecimal | 整团待收(既有字段,本次未改;**不再**是预支上限的基数) | +| advanceApproved | BigDecimal | 已预支(既有字段,本次未改) | +| advancePending | BigDecimal | 待审批预支(既有字段,本次未改) | + +#### 请求示例 + +```http +GET /v3/admin/order/group-batch/2104839654727618562/finance HTTP/1.1 +Host: api.test.1814.love +Authorization: Bearer +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "receivableAmount": "26340.00", + "receivedAmount": "26340.00", + "unpaidAmount": "0.00", + "advanceApproved": "0.00", + "advancePending": "0.00", + "advanceAvailable": "26340.00" + } +} +``` + +#### 空数据 / 降级响应 + +团里没有活跃子订单、或已收全部被在途占满时,`advanceAvailable` 返回 `"0.00"`,不返回 null、不返回负数。 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "receivableAmount": "0.00", + "receivedAmount": "0.00", + "unpaidAmount": "0.00", + "advanceApproved": "0.00", + "advancePending": "0.00", + "advanceAvailable": "0.00" + } +} +``` + +#### 错误响应 + +```json +{ + "code": 589501, + "message": "团期不存在", + "data": null +} +``` + +| 错误码 | 触发条件 | +|---|---| +| 589501 | groupBatchId 不存在或已软删 | + +#### 业务边界 + +- 展示值与 GB-ADM-042 的发起校验出自同一个方法,弹窗显示多少就能发起多少。 +- 取户与在途同源:活跃子订单集按 `group_batch_id` 一跳圈定,已取消户不计入已收。 +- 部分退款的户按「已付 − 已退」计入;单户已退不少于已付时按 0 计。 +- 存量不回溯:在途已超过新上限的团(存量预支或事后退款),这里显示 `"0.00"`,已有预支记录不变。 + +### 2. GB-ADM-042 发起团期预支 `POST /v3/admin/order/group-batch/{groupBatchId}/advance` + +**VO**: `OrderAdvanceRespVO` + +#### 使用场景 + +团期管理员为本团主报账人申请团期级预支,创建即待审批(SUBMITTED),财务在审批中心审批。本次只改金额上限的口径。 + +#### 入参 + +| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 | +|---|---|---|---|---|---| +| groupBatchId | path | Long | 是 | 正整数 | 团期 ID | +| payeeStaffId | body | Long | 是 | 须为本团主报账人(PRIMARY) | 借款对象,否则 589557 | +| advanceType | body | String | 是 | 数据字典 `advance_type` 内的值 | 借款类型,否则 585006 | +| amount | body | BigDecimal | 是 | ≥ 0.01,且 ≤ 当前 `advanceAvailable` | 预支金额;**上限口径本次改为团期已收池 − 在途**,超出 585004 | +| purpose | body | String | 否 | ≤ 255 字 | 用途说明 | +| voucherUrl | body | String | 否 | ≤ 512 字符 | 凭证文件 URL | + +#### 出参 + +| 字段 | 类型 | 说明 | +|---|---|---| +| id | Long | 预支 ID(既有,本次未改) | +| status | String | 恒为 `SUBMITTED`(既有,本次未改) | +| amount | BigDecimal | 预支金额(既有,本次未改) | +| payeeStaffId / payeeName | Long / String | 领款人(既有,本次未改) | + +#### 请求示例 + +```json +{ + "payeeStaffId": 1009, + "advanceType": "ACCOMMODATION_DEPOSIT", + "amount": "24760.00", + "purpose": "额济纳段酒店押金先行垫付" +} +``` + +#### 响应示例 + +```json +{ + "code": 200, + "message": "成功", + "data": { + "id": "2105531450843668481", + "orderId": null, + "payeeStaffId": "1007", + "payeeName": "白云飞", + "payeeRole": "LEADER", + "advanceType": "ACCOMMODATION_DEPOSIT", + "amount": 24760.0, + "status": "SUBMITTED", + "statusText": "待审批", + "submittedAt": "2026-10-01 13:33:11" + } +} +``` + +#### 空数据 / 降级响应 + +本接口为写接口,无空数据形态;校验不通过时不写库、不占额度,返回下方错误。 + +```json +{ + "code": 585004, + "message": "预支金额超过可用余额上限", + "data": null +} +``` + +#### 错误响应 + +```json +{ + "code": 585004, + "message": "预支金额超过可用余额上限", + "data": null +} +``` + +| 错误码 | 触发条件 | +|---|---| +| 585004 | `amount` 大于当前可支取余额(团期已收池 − 在途);**本次口径变化**,错误码与文案不变 | +| 585003 | `amount` ≤ 0 | +| 589541 | 团期状态不允许发起预支(进入核单后关闭) | +| 589557 | 借款对象不是本团主报账人 | + +#### 业务边界 + +- 上限在 `@Lock4j` 按 groupBatchId 串行的段内计算,读-算-插之间无并发窗口。 +- 硬上限:超额一律 585004,没有放宽通道;审批时不再复核额度(维持现状)。 +- 普通订单的预支上限不随本次改动,仍是「本单待收尾款 − 本单在途」。 +- 部分收款的团上限随之收紧(例:应收 10720、已收 1600 的团,可支取由 9120.00 变为 1600.00)。 + +## 四、契约约束与正确调用方式 + +- 弹窗「剩余可支取」与财务 Tab「可支取余额」继续直接读 `advanceAvailable`,**不要**用 `receivedAmount − advanceApproved − advancePending` 本地推算:`receivedAmount` 不扣退款,且在途还含已付款的预支。 +- 发起前以最新一次 GB-ADM-040 的 `advanceAvailable` 为准;并发发起时以服务端 585004 为准。 + +## 五、数据库行为 + +零数据库变更:不新增表、列或索引。GB-ADM-040 只读;GB-ADM-042 写入行为不变(校验通过后在 `order_advance` 插入一行 `scope=GROUP_BATCH`、`status=SUBMITTED`,并写团期时间线)。 +上限的取数改为只读聚合 `order_main.paid_amount` / `refunded_amount`(按本团活跃子订单一次批量取),不再读应付尾款。 + +## 六、边界行为 + +- 全额收款、无在途:可支取 = 整团已收净额。 +- 已收全部被在途占满,或事后退款使已收低于在途:可支取 `"0.00"`,新申请 585004。 +- 团里一户都不剩:已收为 0,可支取 `"0.00"`。 + +## 六.6、修改前后对比 + +| 项 | 修改前 | 修改后 | +|---|---|---| +| 上限基数 | 团期尾款池 = Σ 各户 max(0, 应收 − 已付) | 团期已收池 = Σ 活跃户 max(0, 已付 − 已退),取消户记 0 | +| 全额收款的团 | 可支取恒为 `0.00` | 可支取 = 整团已收净额 | +| 部分收款的团 | 可支取 = 还没收的尾款 − 在途 | 可支取 = 已收净额 − 在途(收紧) | +| 取户口径 | 按 `product_batch_id` 圈 | 按 `group_batch_id` 一跳(与在途同源) | +| 路径 / 入参 / 出参 / 错误码 | — | 逐字未变 | + +## 六.7、影响评估 + +- **兼容性**:字段名、类型、错误码不变;数值口径变化,前端零改动。 +- **性能**:上限计算由一次按排期圈单改为一次按子订单 ID 批量取单,单团期无 N+1。 +- **回滚**:撤销 PR #8686 的合并提交后重新部署 order-v3,无数据与配置残留。 + +## 七、不影响范围 + +- 普通订单(非团期)的预支上限与订单级预支接口。 +- 已预支 / 待审批两个数、预支记录列表(GB-ADM-043)、核单扣回口径。 +- 网关:路径未变、无新增路由与权限码。 +- 小程序端:本接口仅管理后台使用。 + +## 八、测试环境已验证 + +2026-10-01 13:14–14:59 测试服(`api.test.1814.love`),部署 `dev-v3 @ f4f545148`(order-v3 双实例 8086/8186)。 +每个状态节点都用 SQL 按同一公式独立手算并与 `advanceAvailable` 对照,**29 次对照全部一致**。 + +| 场景 | 读数 / 结果 | +|---|---| +| 部署身份:全额收款团「11月1日额济纳胡杨林深秋4日游」(应收 = 已收 26340.00) | 经网关 8 次 + 直连两实例全是 `"26340.00"`(旧口径为 `"0.00"`) | +| 部分收款团「滇西北冬日三日团·一月廿二期」(应收 10720 / 已收 1600) | `"1600.00"`(旧口径为 9120.00) | +| 自建全额收款团(已收 24760.00) | 可支取 `"24760.00"`;发起 24760.00 → 200 SUBMITTED,可支取变 `"0.00"`;再发起 0.01 → 585004 | +| 自建部分收款团(应收 22080 / 已收 15720) | `"15720.00"`;待审 1200 后 `"14520.00"`;14520.01 → 585004,14520.00 → 200 | +| 部分退款 1840(真实退款链路) | 21880 → `"20040.00"`;再取消一户(已付 7360)→ `"12680.00"` | +| 在途 | 待审 / 已批 / 已付都扣;驳回、撤回不扣 | +| 存量不回溯 | 在途占满后取消一户,可支取仍 `"0.00"`,新申请 585004,已有预支记录逐字段不变 | +| 普通订单 | 上限仍是「本单待收 − 本单在途」:两档已付下超 0.01 都报 585004、等额都成功,与新口径可区分 | + +- 验收造数已全部回收,回读零残留。 +- 单元测试:团期 / 预支整包 + 全部 ArchTest 258 类 4131 例 0 失败;合并提交上复跑定向 32 类 250 例 0 失败。 + +## 十、相关文档 + +- 工单 #8677、PR #8686(merge commit `f4f545148`) +- 团期统一池原设计:#7154(docs/group 接口文档 §0B.4,本次同步改为已收池) +- 团单子订单禁走订单级入口、在途含 PAID:#8384 + +## 关联 / 联系人 + +- 后端:jw +- 前端:不涉及(`frontend_status: not_required`)