PR #2932 / Issue #2930 的 changelog 原推到了 changelogs-v2/, 但按 最新约定一期老前端走 changelogs/ 默认目录, changelogs-v2/ 仅给 v3 项目仓。 本次为 admin 改动应在 changelogs/, 故 git mv 修正路径。 原 commit: e3ca303 (保留, 不 force push)
367 行
13 KiB
Markdown
367 行
13 KiB
Markdown
# [新增接口·管理后台] admin H5 客服代用户发起退款 (#2930)
|
||
|
||
> **PR**: #2932 | **服务**: hl-order-service-v2 | **更新时间**: 2026-05-23 10:30
|
||
|
||
## 1. 接口背景
|
||
|
||
管理后台 H5 客服操作台需要支持定制师/客服代用户发起退款申请。现有小程序端退款接口由用户自助发起,不适用客服代操作场景。
|
||
|
||
本接口允许客服在 H5 操作台手动填写退款金额并代用户提交,后端校验金额不超过订单订金金额,申请人留痕为 ADMIN 类型,创建后仍走主管审批流程。
|
||
|
||
## 2. 变更清单
|
||
|
||
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|
||
|---|------|------|------|----------|------|
|
||
| 1 | 代用户发起退款申请 | POST | /admin/order/refund/apply | 新增 | 客服 H5 代用户提交退款,金额客服手填,不超订金 |
|
||
|
||
## 3. 接口详情
|
||
|
||
### 3.1 代用户发起退款申请
|
||
|
||
- **使用场景**:客服在 H5 操作台查看订单后,代用户发起退款申请
|
||
- **认证**:需要管理后台 JWT(Bearer Token),adminId 由后端从 Token 中提取
|
||
- **幂等性**:是,Header 携带 `Idempotent-Key`(UUID),5 秒内重复提交视为同一请求
|
||
- **限流**:无
|
||
|
||
调用前置步骤:先调 `GET /admin/order/refund/reason/list` 获取退款原因字典,拿到 reasonValue(字典 key)和 reasonText(字典显示文本)后再调本接口。
|
||
|
||
## 4. 接口入参
|
||
|
||
### 4.1 路径参数 / Query 参数
|
||
|
||
无。
|
||
|
||
### 4.2 请求体字段
|
||
|
||
| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|
||
|------|------|------|------|----------|
|
||
| orderId | Long | 是 | 订单 ID | 不能为空 |
|
||
| amount | BigDecimal | 是 | 退款金额 | 最小 0.01,且不能超过订单订金金额 |
|
||
| reasonValue | String | 是 | 退款原因字典值 | 从 /admin/order/refund/reason/list 获取;最长 100 字符 |
|
||
| reasonText | String | 是 | 退款原因文本 | 字典对应的显示文本;最长 500 字符 |
|
||
| reasonDetail | String | 否 | 补充说明 | 最长 2000 字符 |
|
||
|
||
注意:refundType 无需前端传入,后端固定设置为 DEPOSIT(订金退款)。
|
||
|
||
## 5. 出参(响应)
|
||
|
||
### 5.1 响应结构
|
||
|
||
`Result<RefundApplicationVO>`
|
||
|
||
### 5.2 响应字段
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| applicationId | Long | 退款申请 ID |
|
||
| orderId | Long | 订单 ID |
|
||
| orderNo | String | 订单号 |
|
||
| productName | String | 产品名称 |
|
||
| refundType | String | 退款类型,本接口固定返回 DEPOSIT |
|
||
| refundTypeLabel | String | 退款类型标签,固定返回 订金退款 |
|
||
| reasonText | String | 退款原因文本 |
|
||
| reasonDetail | String | 补充说明(可为 null) |
|
||
| paidAmount | BigDecimal | 订单已付金额 |
|
||
| calculatedAmount | BigDecimal | 本次退款金额(即客服填写的 amount) |
|
||
| actualAmount | BigDecimal | 实际退款金额(审批后确认,初始为 null) |
|
||
| status | String | 退款申请状态,创建后固定返回 PENDING |
|
||
| statusLabel | String | 退款状态标签,创建后固定返回 待审核 |
|
||
| applicantType | String | 申请人类型,固定返回 ADMIN |
|
||
| applicantId | Long | 申请人管理员 ID |
|
||
| applicantName | String | 申请人姓名 |
|
||
| createTime | String (ISO 8601) | 申请创建时间 |
|
||
| updateTime | String (ISO 8601) | 最后更新时间 |
|
||
| reviewAdminId | Long | 审批人 ID(创建时为 null,审批后填充) |
|
||
| reviewAdminName | String | 审批人姓名(创建时为 null) |
|
||
| reviewRemark | String | 审批备注(创建时为 null) |
|
||
| reviewedAt | String (ISO 8601) | 审批时间(创建时为 null) |
|
||
| approvalNo | String | 审批单号(创建时为 null) |
|
||
| departureDate | String (yyyy-MM-dd) | 出发日期 |
|
||
| daysBeforeDept | Integer | 距出发天数 |
|
||
| refundRatio | Integer | 退款比例(百分比,本接口为 null,不调退款政策) |
|
||
| policyId | Long | 退款政策 ID(本接口为 null) |
|
||
| policyName | String | 退款政策名称(本接口为 null) |
|
||
| appealStatus | Integer | 申诉状态(创建时为 null) |
|
||
| appealStatusLabel | String | 申诉状态标签(创建时为 null) |
|
||
| appealReason | String | 申诉原因(创建时为 null) |
|
||
| appealAmount | BigDecimal | 申诉退款金额(创建时为 null) |
|
||
| appealedAt | String (ISO 8601) | 申诉时间(创建时为 null) |
|
||
| refundedAt | String (ISO 8601) | 退款完成时间(创建时为 null) |
|
||
|
||
本接口创建的申请:policyId / policyName / refundRatio 均为 null(客服手填金额,不走退款政策计算)。
|
||
|
||
## 6. 枚举 / 数据字典
|
||
|
||
### 6.1 refundType(退款类型,出参字段)
|
||
|
||
**所属字段**:refundType | **类型**:String | 本接口固定为 DEPOSIT
|
||
|
||
| 值 | 中文 | 说明 |
|
||
|----|------|------|
|
||
| FULL | 全额退款 | 全额退还已付金额 |
|
||
| PARTIAL | 部分退款 | 部分退款 |
|
||
| DEPOSIT | 订金退款 | 仅退还订金部分,本接口固定此类型 |
|
||
| BALANCE | 尾款退款 | 仅退还尾款部分 |
|
||
|
||
### 6.2 status(退款申请状态,出参字段)
|
||
|
||
**所属字段**:status | **类型**:String | 创建后固定为 PENDING
|
||
|
||
| 值 | 中文 | 说明 |
|
||
|----|------|------|
|
||
| PENDING | 待审核 | 申请已提交,等待主管审批 |
|
||
| APPROVED | 已通过 | 主管审批通过,进入退款流程 |
|
||
| REJECTED | 已拒绝 | 主管审批拒绝 |
|
||
| APPEALING | 申诉中 | 用户对拒绝结果申诉 |
|
||
| APPEAL_APPROVED | 申诉通过 | 申诉被通过 |
|
||
| APPEAL_REJECTED | 申诉拒绝 | 申诉被拒绝 |
|
||
| REFUNDING | 退款中 | 正在处理退款 |
|
||
| REFUNDED | 已退款 | 退款已完成 |
|
||
| CANCELLED | 已取消 | 申请已撤回取消 |
|
||
|
||
活跃状态(同订单已有此类状态时拒绝重复提交):PENDING / APPROVED / REFUNDING / APPEALING / APPEAL_APPROVED
|
||
|
||
### 6.3 applicantType(申请人类型,出参字段)
|
||
|
||
**所属字段**:applicantType | **类型**:String | 本接口固定为 ADMIN
|
||
|
||
| 值 | 中文 | 说明 |
|
||
|----|------|------|
|
||
| USER | 用户 | 小程序用户自助发起(mp 接口) |
|
||
| ADMIN | 管理员 | 客服/定制师代发起(本接口) |
|
||
|
||
### 6.4 reasonValue(退款原因字典值,入参字段)
|
||
|
||
**所属字段**:reasonValue | **类型**:String | **必填**:是
|
||
|
||
字典值通过 `GET /admin/order/refund/reason/list` 接口获取,下面为示例(以实际字典接口返回为准):
|
||
|
||
| 值(示例) | 中文 |
|
||
|-----------|------|
|
||
| schedule_conflict | 行程冲突/时间变动 |
|
||
| personal_reason | 个人原因 |
|
||
| product_issue | 产品问题 |
|
||
| service_complaint | 服务投诉 |
|
||
|
||
实际可用值以 `GET /admin/order/refund/reason/list` 返回为准。
|
||
|
||
## 7. 错误码
|
||
|
||
| code | 含义 | 触发场景 |
|
||
|------|------|----------|
|
||
| 200 | 成功 | 退款申请创建成功 |
|
||
| 401 | 未授权 | 未携带或 Token 无效/过期 |
|
||
| 404 | 订单不存在 | orderId 对应的订单不存在 |
|
||
| 530007 | 退款金额超过订金金额 | amount 大于订单 depositAmount,message 含具体金额:退款金额不能超过订金金额: amount={x}, deposit={y} |
|
||
| 530004 | 重复退款申请 | 同一订单已存在 ACTIVE 状态的退款申请 |
|
||
|
||
## 8. 示例
|
||
|
||
### 8.1 典型成功
|
||
|
||
场景说明:客服代用户发起订金退款,退 500 元,选择行程冲突原因。
|
||
|
||
请求:
|
||
|
||
```
|
||
POST /admin/order/refund/apply
|
||
Authorization: Bearer <admin-jwt>
|
||
Idempotent-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"orderId": 1234567890123,
|
||
"amount": 500.00,
|
||
"reasonValue": "schedule_conflict",
|
||
"reasonText": "行程冲突/时间变动",
|
||
"reasonDetail": "客户因工作变动无法出行,需要退款"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"data": {
|
||
"applicationId": 9876543210001,
|
||
"orderId": 1234567890123,
|
||
"orderNo": "HL2026052300001",
|
||
"productName": "云南大理双廊古镇 5 日深度游",
|
||
"refundType": "DEPOSIT",
|
||
"refundTypeLabel": "订金退款",
|
||
"reasonText": "行程冲突/时间变动",
|
||
"reasonDetail": "客户因工作变动无法出行,需要退款",
|
||
"paidAmount": 2000.00,
|
||
"calculatedAmount": 500.00,
|
||
"actualAmount": null,
|
||
"policyId": null,
|
||
"policyName": null,
|
||
"refundRatio": null,
|
||
"status": "PENDING",
|
||
"statusLabel": "待审核",
|
||
"applicantType": "ADMIN",
|
||
"applicantId": 10086,
|
||
"applicantName": "李小明",
|
||
"departureDate": "2026-06-15",
|
||
"daysBeforeDept": 23,
|
||
"reviewAdminId": null,
|
||
"reviewAdminName": null,
|
||
"reviewRemark": null,
|
||
"reviewedAt": null,
|
||
"approvalNo": null,
|
||
"appealStatus": null,
|
||
"appealStatusLabel": null,
|
||
"appealReason": null,
|
||
"appealAmount": null,
|
||
"appealedAt": null,
|
||
"refundedAt": null,
|
||
"createTime": "2026-05-23T10:30:00",
|
||
"updateTime": "2026-05-23T10:30:00"
|
||
},
|
||
"message": "ok",
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
### 8.2 边界情况
|
||
|
||
场景说明:退款金额等于订单订金金额上限(全额退订金),不填补充说明(reasonDetail 为 null)。
|
||
|
||
请求:
|
||
|
||
```
|
||
POST /admin/order/refund/apply
|
||
Authorization: Bearer <admin-jwt>
|
||
Idempotent-Key: b2c3d4e5-f6a7-8901-bcde-f12345678901
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"orderId": 1234567890124,
|
||
"amount": 2000.00,
|
||
"reasonValue": "personal_reason",
|
||
"reasonText": "个人原因",
|
||
"reasonDetail": null
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"data": {
|
||
"applicationId": 9876543210002,
|
||
"orderId": 1234567890124,
|
||
"orderNo": "HL2026052300002",
|
||
"productName": "西藏拉萨布达拉宫 7 日游",
|
||
"refundType": "DEPOSIT",
|
||
"refundTypeLabel": "订金退款",
|
||
"reasonText": "个人原因",
|
||
"reasonDetail": null,
|
||
"paidAmount": 5000.00,
|
||
"calculatedAmount": 2000.00,
|
||
"actualAmount": null,
|
||
"policyId": null,
|
||
"policyName": null,
|
||
"refundRatio": null,
|
||
"status": "PENDING",
|
||
"statusLabel": "待审核",
|
||
"applicantType": "ADMIN",
|
||
"applicantId": 10086,
|
||
"applicantName": "李小明",
|
||
"departureDate": "2026-06-10",
|
||
"daysBeforeDept": 18,
|
||
"reviewAdminId": null,
|
||
"reviewAdminName": null,
|
||
"reviewRemark": null,
|
||
"reviewedAt": null,
|
||
"approvalNo": null,
|
||
"createTime": "2026-05-23T10:35:00",
|
||
"updateTime": "2026-05-23T10:35:00"
|
||
},
|
||
"message": "ok",
|
||
"success": true
|
||
}
|
||
```
|
||
|
||
### 8.3 业务失败(异常)
|
||
|
||
场景说明:退款金额超过订金金额,触发 530007 错误。
|
||
|
||
请求:
|
||
|
||
```
|
||
POST /admin/order/refund/apply
|
||
Authorization: Bearer <admin-jwt>
|
||
Idempotent-Key: c3d4e5f6-a7b8-9012-cdef-123456789012
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"orderId": 1234567890123,
|
||
"amount": 9999.00,
|
||
"reasonValue": "personal_reason",
|
||
"reasonText": "个人原因"
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"code": 530007,
|
||
"message": "退款金额不能超过订金金额: amount=9999.00, deposit=2000.00",
|
||
"success": false
|
||
}
|
||
```
|
||
|
||
## 9. 业务边界
|
||
|
||
- 适用场景:订单已支付(存在成功支付记录)时可发起退款申请
|
||
- 不适用场景:
|
||
- 订单不存在 -> 返回 404
|
||
- 订单未支付 -> 后端校验失败,返回业务错误
|
||
- 同订单已有 ACTIVE 状态退款申请(PENDING/APPROVED/REFUNDING/APPEALING/APPEAL_APPROVED)-> 返回 530004 拒绝重复提交
|
||
- amount 超过订单订金金额 -> 返回 530007
|
||
- amount <= 0 -> 返回 400 参数校验失败
|
||
- 特殊边界:
|
||
- 本接口不调退款政策计算,policyId/policyName/refundRatio 均为 null
|
||
- 退款类型固定为 DEPOSIT,不允许客服指定其他类型
|
||
- 申请创建后状态固定为 PENDING,需走 `PUT /admin/order/refund/{applicationId}/review` 主管审批流程
|
||
- 5 秒内携带相同 Idempotent-Key 重复提交视为同一请求,返回第一次的结果(不重复创建)
|
||
|
||
## 10. 修改前后对比
|
||
|
||
全新接口,无修改前后对比。管理后台之前没有代用户发起退款的入口,本次为纯新增。
|
||
|
||
## 11. 影响评估 / 回滚
|
||
|
||
- 是否破坏向后兼容:否(全新接口,旧代码无感知)
|
||
- 前端是否必须同步上线:否(后端先上,前端可独立部署)
|
||
|
||
## 12. 注意事项
|
||
|
||
- Header 必须携带 `Idempotent-Key`(UUID 格式),防止客服误操作重复提交。前端在进入发起退款页时生成一个 UUID,整个提交流程复用同一个 key
|
||
- 退款原因字典值需提前获取:调本接口前先调 `GET /admin/order/refund/reason/list` 拿到可用的 reasonValue 列表,不可自行填写字典 key
|
||
- 金额校验上限为订单订金金额,超过返回 530007,message 含具体金额数值
|
||
- 提交成功后申请状态为 PENDING,可通过 applicationId 跳转至退款进度页,或按订单维度查询退款列表
|
||
|
||
## 13. 关联 / 联系人
|
||
|
||
### 13.1 链接
|
||
|
||
- **Issue**: [#2930](https://git.1814.love:8443/wx/HL/issues/2930)
|
||
- **PR**: [#2932](https://git.1814.love:8443/wx/HL/pulls/2932)
|
||
- **Merge commit**: [17e7fce90](https://git.1814.love:8443/wx/HL/commit/17e7fce90e5e4eb21e4e9c6bb4fb1d86e9c1fa21)
|
||
- **实现 commit**: [ca5e1a366](https://git.1814.love:8443/wx/HL/commit/ca5e1a36647edb01ba6c7b1337c07149c41665cb)
|
||
|
||
### 13.2 联系人
|
||
|
||
- **后端负责人**: @yaosutu
|