docs(changelog): 退款待办工作台后端接口(stats统计+resubmit重新发起+page列表增强) 管理后台 (#4226)

这个提交包含在:
yaosutu 2026-06-22 17:48:20 +08:00
父节点 b661ff7e89
当前提交 75dea54f2f

查看文件

@ -0,0 +1,219 @@
# 退款待办工作台后端(统计 + 列表增强 + 失败重新发起)
- 端类型:管理后台
- 变更类型新增接口2+ 修改接口1
- 关联 Issue#4226 PR#4245
- 日期2026-06-22
---
## ① 接口背景
订单控制台「退款待办」是财务/管理员的退款审批+监控工作台,按状态分组(待审批 / 退款中 / 失败待处理 / 已完成展示并处理退款申请。本次后端在已有退款申请refund_application能力上补齐三块顶部统计卡片、列表展示字段与搜索增强、失败退款的重新发起。基于现有退款链路审批 → 自动原路退回 → 微信回调 → 对账),无新建主流程。
---
## ② 变更清单
| # | 方法 | 路径 | 类型 |
|---|---|---|---|
| 1 | GET | `/v3/admin/refund/application/stats` | 🆕 新增 |
| 2 | POST | `/v3/admin/refund/record/{refundId}/resubmit` | 🆕 新增 |
| 3 | GET | `/v3/admin/refund/application/page` | ✏️ 修改(出参增字段 + 入参增搜索) |
统一响应包装 `Result<T>``{ code, message, data, traceId, success }``code=200` 为成功。
---
## ③ 接口详情
### 1. 退款待办统计 `GET /v3/admin/refund/application/stats`
返回各状态分组数量+金额 + 本月已退款汇总,供工作台顶部卡片。
### 2. 重新发起退款 `POST /v3/admin/refund/record/{refundId}/resubmit`
对「失败待处理」的退款**记录**重新发起退款。仅 record 状态为 `FAILED`(微信退款执行失败终态)可重发;后端新建一条退款记录 + 新商户退款单号重走微信退款,旧 FAILED 记录保留作审计。
> ⚠️ 维度是**退款记录(refund_record)**,不是退款申请。一个退款申请可能对应多条记录(按支付交易拆,定金+尾款等)。
### 3. 退款申请分页(增强) `GET /v3/admin/refund/application/page`
已有列表接口,本次**出参新增 6 字段、入参新增 3 个搜索条件**。
---
## ④ 入参
### 接口1 stats
无入参。
### 接口2 resubmit
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
| refundId | path | long | 是 | 退款记录 IDFAILED 记录) |
无 body。
### 接口3 page本次新增的搜索字段,其余原有字段不变
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| customerName | string | 否 | 客户名(联系人)模糊搜索(经 OrderService 反查 orderId 过滤) |
| consultantName | string | 否 | 定制师姓名模糊搜索(经 OrderService 反查 orderId 过滤) |
| reasonText | string | 否 | 退款原因模糊搜索 |
> 原有入参不变orderId / orderNo / applicantName / applicantId / status(多选) / auditStatus / createTimeFrom / createTimeTo / refundedAtFrom / refundedAtTo / sortField / sortOrder / pageNo / pageSize。
---
## ⑤ 出参
### 接口1 stats `Result<RefundStatsRespVO>`
| 字段 | 类型 | 说明 |
|---|---|---|
| pendingCount | long | 待审批数 |
| pendingAmount | string | 待审批合计应退金额 |
| refundingCount | long | 退款中数 |
| refundingAmount | string | 退款中合计应退金额 |
| failedCount | long | 失败待处理数 |
| failedAmount | string | 失败待处理合计应退金额 |
| completedCount | long | 已完成数 |
| completedAmount | string | 已完成合计实退金额 |
| currentMonthRefundedAmount | string | 本月已退款金额 |
| currentMonthRefundedCount | long | 本月已退款单数 |
> 金额字段均为**字符串**BigDecimal 序列化,避免精度丢失)。
### 接口2 resubmit `Result<Void>`
成功返回 `{ "code":200, "message":"成功", "data":null, "success":true }`
### 接口3 page 列表项 `RefundApplicationPageItemRespVO` 本次**新增**字段
| 字段 | 类型 | 说明 |
|---|---|---|
| productName | string | 产品名称(经 OrderService 批量填充,可能为空) |
| customerName | string | 客户名(联系人,经 OrderService 批量填充) |
| consultantName | string | 定制师姓名(经 OrderService 批量填充) |
| deduction | string | 扣除金额(派生 = 已付 应退,无扣除时可能为 null |
| refundChannel | string | 退款渠道(当前固定值「原路退回(微信支付)」) |
| reasonDetail | string | 退款原因详情(申请时填写的详细描述) |
> 原有项字段不变applicationId / orderId / orderNo / refundType / reasonText / paidAmount / calculatedAmount / actualAmount / applicantType / applicantId / applicantName / status / statusText / auditStatus / reviewerNameLast / refundRecordCount / refundedAt / createTime / updateTime。
---
## ⑥ 枚举 / 数据字典
**退款申请状态 status / statusText**
| 值 | 含义 |
|---|---|
| PENDING | 待审核 |
| APPROVED | 已通过 |
| REJECTED | 已拒绝 |
| REFUNDING | 退款中 |
| REFUNDED | 已退款 |
| CANCELLED | 已取消 |
| ABNORMAL | 退款异常 |
**统计分组口径**(前端 4 张卡片对应):
- 待审批 = status `PENDING`
- 退款中 = status `APPROVED` + `REFUNDING`
- 失败待处理 = 底下有退款记录 record.status=`FAILED` 的申请
- 已完成 = status `REFUNDED`
- 本月已退款 = `REFUNDED` 且退款完成时间(refundedAt)在当月
---
## ⑦ 错误码
接口2 resubmit段位 530500-530599
| code | message |
|---|---|
| 530501 | 仅 FAILED 终态的退款记录可重新发起 |
| 530502 | 该退款申请已全额退款成功,无需重新发起 |
| 530503 | 超退校验失败:已退¥{0},本次¥{1},已付¥{2} |
| 530504 | 退款记录不存在 |
---
## ⑧ 示例
### 典型:统计
请求:`GET /v3/admin/refund/application/stats`
响应:
```json
{
"code": 200, "message": "成功", "success": true,
"data": {
"pendingCount": 0, "pendingAmount": "0.00",
"refundingCount": 0, "refundingAmount": "0.00",
"failedCount": 0, "failedAmount": "0.00",
"completedCount": 9, "completedAmount": "4610.50",
"currentMonthRefundedAmount": "4610.50", "currentMonthRefundedCount": 9
}
}
```
### 典型:列表(按定制师搜索)
请求:`GET /v3/admin/refund/application/page?pageNo=1&pageSize=10&consultantName=李`
响应(节选一项):
```json
{
"code": 200, "success": true,
"data": { "total": 13, "list": [
{ "applicationId": "...", "orderNo": "...", "status": "REFUNDED", "statusText": "已退款",
"productName": "测试核心产品-单档-固定订金", "customerName": "孙磊", "consultantName": "腰苏图",
"paidAmount": "...", "actualAmount": "...", "deduction": null,
"refundChannel": "原路退回(微信支付)", "reasonDetail": "..." }
] }
}
```
### 异常:重新发起非 FAILED / 不存在的记录
请求:`POST /v3/admin/refund/record/999999999/resubmit`
响应:
```json
{ "code": 530504, "message": "退款记录不存在", "data": null, "success": false }
```
(对非 FAILED 记录返回 530501;已全额成功返回 530502;超退返回 530503
---
## ⑨ 业务边界
- **「重新发起」≠「重新申请」**:重新发起是对已审批通过、但调微信退款执行失败的记录重试(财务工作台);审批被驳回的退款要客户走「重新申请」(小程序新建退款申请),不在本工作台。
- **可重发状态**:仅退款记录 `FAILED` 终态显示「重新发起」;退款中 / 已成功 / 审批驳回不可重发。
- **账户侧失败**:如「原微信账户已注销」,微信只能原路退回,重新发起原路仍会失败——前端可据失败原因提示走线下,不应无限重试。
- 重新发起做了幂等锁(同一记录并发只发一次)+ 超退校验(已退+本次≤已付)。
---
## ⑩ 修改前后对比接口3 page
| | 修改前 | 修改后 |
|---|---|---|
| 列表项字段 | 无产品名/客户/定制师/扣除/渠道/原因详情 | 新增 productName / customerName / consultantName / deduction / refundChannel / reasonDetail |
| 搜索维度 | orderId/orderNo/申请人/状态/机审/时间 | 增加 customerName / consultantName / reasonText |
接口1、2 为纯新增,无对比。
---
## ⑪ 影响评估 / 回滚
- 接口3 为**出参增字段 + 入参增可选搜索**,向后兼容,前端不改也不报错(新字段不读即可)。
- 新增字段经 OrderService 批量填充(防 N+1,不影响原列表性能口径。
- 回滚:前端不调用新接口、不读新字段即可;后端回滚 PR #4245
---
## ⑫ 注意事项
- 金额字段stats 各 amount、deduction、paidAmount/actualAmount 等)均为**字符串**,前端按字符串处理金额,勿用 number 解析以免精度丢失。
- deduction 可能为 `null`(无扣除或已付=应退),前端兜底显示「-」。
- refundChannel 当前固定「原路退回(微信支付)」,后续多渠道再扩展。
- resubmit 是**记录(record)维度**,列表/详情若按申请聚合,重发入口需定位到具体 FAILED 记录。
---
## ⑬ 关联 / 联系人
- Issuehttps://git.1814.love:8443/wx/HL/issues/4226
- PRhttps://git.1814.love:8443/wx/HL/pulls/4245
- 后端负责人:腰苏图
- 已部署测试服并网关实调验证通过stats 返回真实数据 / page 新字段已填充 / resubmit 守卫生效)。