# 退款政策与退款原因管理接口 v2->v3 迁移说明（管理后台）

- **端类型**：管理后台
- **日期**：2026-06-22
- **服务**：hl-order-service-v3（端口 8086）
- **接口路径前缀**：`/v3/admin/order/refund-policy`

---

## 1. 接口背景

退款政策与退款原因管理功能已在 v3 就绪，与 v2 功能一致，路径整体由
`/admin/order/refund-policy` 升版为 `/v3/admin/order/refund-policy`。
本文档补充 v2→v3 完整路径对照表与退款金额计算算法差异，供前端迁移核对。

---

## 2. 变更清单

| 类型 | 描述 |
|------|------|
| 路径变更 | 退款政策 7 个端点：/admin/order/refund-policy/* 统一升为 /v3/admin/order/refund-policy/* |
| 路径变更 | 退款原因 3 个端点：/admin/order/refund-policy/reason/* 统一升为 /v3/admin/order/refund-policy/reason/* |
| 新增端点 | 补 reason/list 列表端点（PR #4243），返回全量退款原因含禁用 |
| 无字段变更 | 入参/出参/枚举全部与 v2 一致 |
| 算法差异 | 退款金额计算：v3 区间判定与舍入方式与 v2 不同（详见第 12 节） |

---

## 3. 接口详情

- **认证**：需携带管理端 JWT（Authorization: Bearer token），Gateway 注入 adminId
- **幂等性**：GET 天然幂等；POST/PUT 非幂等，重复提交会新建或覆盖
- **限流**：走 Gateway 全局策略，无独立限流
- **Content-Type**：application/json

---

### 退款原因管理端点清单

| 方法 | 路径 | 用途 |
|------|------|------|
| GET | /v3/admin/order/refund-policy/reason/list | 退款原因列表（含禁用，按 sortOrder 升序，供管理后台维护） |
| POST | /v3/admin/order/refund-policy/reason | 创建退款原因 |
| PUT | /v3/admin/order/refund-policy/reason/{reasonId} | 修改退款原因 |
| DELETE | /v3/admin/order/refund-policy/reason/{reasonId} | 软删除退款原因 |

> GET reason/list 返回 List<RefundReasonVO>，字段详见第 5 节。与 C 端区别：admin 接口调用 listReasons(false) 返回全量含禁用；C 端 GET /v3/internal/mp/order/refund/reasons 只返启用项（listReasons(true)）。
>
> 出参示例：
> 


## 4. 入参

### 4.1 路径参数 / Query 参数

| 接口 | 参数名 | 类型 | 必填 | 说明 |
|------|--------|------|------|------|
| GET /enabled | payType | String | 否 | FULL 或 DEPOSIT；不传返回全部启用政策 |
| GET /{policyId} | policyId | Long | 是 | 路径参数 |
| PUT /{policyId} | policyId | Long | 是 | 路径参数 |
| DELETE /{policyId} | policyId | Long | 是 | 路径参数 |
| PUT /{policyId}/toggle | policyId | Long | 是 | 路径参数 |
| PUT /{policyId}/toggle | enabled | Boolean | 是 | Query 参数，true=启用 |
| PUT /reason/{reasonId} | reasonId | Long | 是 | 路径参数 |
| DELETE /reason/{reasonId} | reasonId | Long | 是 | 路径参数 |

### 4.2 请求体字段

#### 退款政策请求 RefundPolicyRequest（创建/修改通用）

| 字段 | 类型 | 必填 | 校验 | 说明 |
|------|------|------|------|------|
| policyName | String | 是 | 非空，<=100 字 | 政策名称 |
| remark | String | 否 | <=500 字 | 备注说明 |
| applyPayType | String | 否 | FULL/DEPOSIT/BOTH | 适用支付类型；不传后端默认 BOTH |
| rules | Array | 是 | 非空，至少 1 条 | 退款规则阶梯列表 |
| rules[].minDays | Integer | 是 | >=0 | 距出发最少天数（含当天） |
| rules[].refundRatio | Integer | 是 | 0~100 | 退款比例（百分比） |

#### 退款原因请求 RefundReasonRequest（创建/修改通用）

| 字段 | 类型 | 必填 | 校验 | 说明 |
|------|------|------|------|------|
| reasonText | String | 是 | 非空，<=200 字 | C 端可见原因文本 |
| reasonCode | String | 否 | <=64 字 | 机器可读编码，如 TIME_CONFLICT/OTHER |
| category | String | 否 | <=50 字 | 分类，取值来自字典 refund_reason_category |
| sortOrder | Integer | 否 | — | 排序号，越小越靠前 |

---

## 5. 出参字段

### RefundPolicyVO（退款政策）

| 字段 | 类型 | 说明 |
|------|------|------|
| policyId | String（Long 序列化） | 政策 ID（雪花） |
| policyName | String | 政策名称 |
| enabled | Boolean | 是否启用 |
| applyPayType | String | 适用支付类型（FULL/DEPOSIT/BOTH） |
| remark | String | 备注，可为 null |
| createdBy | String（Long 序列化） | 创建人 adminId |
| createTime | String（ISO 8601） | 创建时间 |
| updateTime | String（ISO 8601） | 更新时间 |
| rules | Array | 退款规则阶梯列表，按 minDays 升序 |
| rules[].ruleId | String（Long 序列化） | 规则 ID |
| rules[].minDays | Integer | 距出发最少天数 |
| rules[].refundRatio | Integer | 退款比例（百分比） |

> VO 不返回 maxDays（区间上界由后端按规则集排序推导），前端只需展示 minDays + refundRatio。

### RefundReasonVO（退款原因）

| 字段 | 类型 | 说明 |
|------|------|------|
| reasonId | String（Long 序列化） | 原因 ID（雪花） |
| reasonText | String | 原因描述（C 端展示文本） |
| reasonCode | String | 业务编码，可为 null |
| category | String | 分类（字典 refund_reason_category 值） |
| sortOrder | Integer | 排序号 |
| enabled | Boolean | 是否启用 |

---

## 6. 枚举 / 数据字典

### applyPayType（字典 payment_type）

| 值 | 含义 |
|----|------|
| FULL | 仅适用全款支付产品 |
| DEPOSIT | 仅适用定金支付产品 |
| BOTH | 全款与定金均适用（默认值） |

> GET /enabled 的 payType Query 参数只接受 FULL 或 DEPOSIT（不接受 BOTH）。
> 传 FULL 返回 applyPayType 为 FULL 或 BOTH 的政策；传 DEPOSIT 同理。

### category（字典 refund_reason_category）

退款原因分类，取值由系统数据字典 refund_reason_category 维护。
创建/修改时传字典中已有的 key，后端不做枚举校验，建议与字典保持一致。

---

## 7. 错误码

| 错误码 | 说明 | 触发条件 |
|--------|------|----------|
| 200 | 成功 | — |
| 400 | 参数校验失败 | policyName 为空/rules 为空/refundRatio 超出 0~100/applyPayType 非法值 |
| 530209 | 退款政策阶梯天数重复或重叠 | rules 中有相同 minDays |
| 1002 | 资源不存在 | policyId/reasonId 不存在或已软删除 |
| 401 | 未认证 | 未携带或 JWT 失效 |

---

## 8. 示例

### 8.1 典型成功：创建退款政策（3 档阶梯）

请求：POST /v3/admin/order/refund-policy



响应：



### 8.2 边界情况：单档不可退政策（refundRatio=0，minDays=0）

请求：POST /v3/admin/order/refund-policy



响应结构同 8.1，rules 只有一条，remark 为 null。

### 8.3 业务失败：policyName 为空触发 400

请求体缺少 policyName 字段，响应：



---

## 9. 业务边界

**适用**
- 管理员维护全局退款政策库和退款原因选项
- 产品编排时从 GET /enabled 拉取可选政策列表（可按 payType 过滤）绑定到产品
- 软删除：DELETE 政策/原因后数据保留，C 端不再展示

**不适用**
- 接口仅管理端可用，不开放给小程序 C 端
- 删除/禁用政策后，已绑定该政策的产品申请退款时降级使用默认政策

**特殊边界**
- PUT 修改规则时全量替换原有规则列表，需携带完整规则集
- 历史退款申请已快照政策信息，修改政策不影响已有退款申请金额
- 退款原因无独立启停端点，通过 DELETE 软删下线

---

## 10. v2→v3 路径对照表

| 功能 | v2 路径 | v3 路径 | 契约变化 |
|------|---------|---------|----------|
| 退款政策列表（含禁用） | GET /admin/order/refund-policy/list | GET /v3/admin/order/refund-policy/list | 无 |
| 启用的退款政策列表 | GET /admin/order/refund-policy/enabled | GET /v3/admin/order/refund-policy/enabled | 无 |
| 退款政策详情 | GET /admin/order/refund-policy/{policyId} | GET /v3/admin/order/refund-policy/{policyId} | 无 |
| 创建退款政策 | POST /admin/order/refund-policy | POST /v3/admin/order/refund-policy | 无 |
| 修改退款政策 | PUT /admin/order/refund-policy/{policyId} | PUT /v3/admin/order/refund-policy/{policyId} | 无 |
| 删除退款政策 | DELETE /admin/order/refund-policy/{policyId} | DELETE /v3/admin/order/refund-policy/{policyId} | 无 |
| 启用/禁用退款政策 | PUT /admin/order/refund-policy/{policyId}/toggle | PUT /v3/admin/order/refund-policy/{policyId}/toggle | 无 |
| 创建退款原因 | POST /admin/order/refund-policy/reason | POST /v3/admin/order/refund-policy/reason | 无 |
| 修改退款原因 | PUT /admin/order/refund-policy/reason/{reasonId} | PUT /v3/admin/order/refund-policy/reason/{reasonId} | 无 |
| 删除退款原因 | DELETE /admin/order/refund-policy/reason/{reasonId} | DELETE /v3/admin/order/refund-policy/reason/{reasonId} | 无 |
| 退款原因列表（含禁用） | GET /admin/order/refund-policy/reason/list | GET /v3/admin/order/refund-policy/reason/list | 无；admin 返回全量含禁用，C 端 /internal/mp/order/refund/reasons 只返启用 |

v2 旧路径在 v2 服务下线后返回 404，v3 路径为新基线。

---

## 11. 影响评估 / 回滚

- **影响**：前端需将 base URL 切换至 v3 服务（端口 8086），路径前缀由 /admin/ 改为 /v3/admin/，字段契约不变
- **回滚方案**：前端回退 base URL 至 v2 服务即可，v3 与 v2 数据库独立互不影响

---

## 12. 注意事项

**退款金额计算算法差异（v2 vs v3）—— 存量政策迁移与对账时必须核对**

| 项目 | v2 | v3 |
|------|----|----|
| 区间判定 | minDays 单边匹配（>=minDays 命中最小 minDays 规则） | [minDays, maxDays) 双边区间，maxDays 由后端按规则集排序推导 |
| 舍入模式 | HALF_EVEN（银行家舍入） | DOWN（向下截断） |
| 结果差异 | 边界天数处两版计算结果可能不同 | 同政策同天数下，v3 退款金额 <= v2 退款金额 |

相同 minDays/refundRatio 配置，v2 和 v3 实际退款金额可能不同。
若迁移存量政策并对历史退款金额做对账，需按上表核对两版计算结果。

---

## 13. 关联 / 联系人

- **后端负责人**：腰苏图（yaosutu）
- **服务**：hl-order-service-v3，退款域 com.hulalv.refund
- **Controller**：AdminRefundPolicyController，路径前缀 /v3/admin/order/refund-policy
- **Gitea 项目**：https://git.1814.love:8443/wx/HL
