# 退款政策与退款原因管理接口说明（管理后台）

- **日期**: 2026-06-22
- **端类型**: 管理后台
- **接口路径前缀**: /v3/admin/order/refund-policy
- **服务**: hl-order-service-v3（端口 8086，网关前缀 /v3）
- **说明**: 本文档为现有已上线接口的对接说明，非新版本改动

---

## 1. 接口背景

退款政策模块支持按「距出发天数」设置分阶梯退款比例，产品设计时可绑定指定政策；退款原因模块维护 C 端用户申请退款时可选择的原因选项。两个模块均由管理后台维护，不开放给小程序。

---

## 2. 变更清单

| 类型 | 接口 | 说明 |
|------|------|------|
| 接口说明 | GET /v3/admin/order/refund-policy/list | 退款政策全量列表（含禁用） |
| 接口说明 | GET /v3/admin/order/refund-policy/enabled | 启用政策列表（含 payType 过滤） |
| 接口说明 | GET /v3/admin/order/refund-policy/{policyId} | 退款政策详情（含阶梯规则） |
| 接口说明 | POST /v3/admin/order/refund-policy | 创建退款政策 |
| 接口说明 | PUT /v3/admin/order/refund-policy/{policyId} | 修改退款政策 |
| 接口说明 | DELETE /v3/admin/order/refund-policy/{policyId} | 删除退款政策（软删） |
| 接口说明 | PUT /v3/admin/order/refund-policy/{policyId}/toggle | 启用/禁用退款政策 |
| 接口说明 | POST /v3/admin/order/refund-policy/reason | 创建退款原因 |
| 接口说明 | PUT /v3/admin/order/refund-policy/reason/{reasonId} | 修改退款原因 |
| 接口说明 | DELETE /v3/admin/order/refund-policy/reason/{reasonId} | 删除退款原因（软删） |

---

## 3. 接口详情（通用）

- **认证**: JWT，Header Authorization: Bearer token，需管理员身份（adminId 从 token 解析）
- **幂等性**: 创建/修改无幂等 header，前端需防止重复点击
- **Content-Type**: application/json
- **响应格式**: 统一 { "code": 200, "data": ..., "msg": "success" }

---

## 4. 接口入参

### 4.1 政策列表

#### GET /v3/admin/order/refund-policy/list

无入参，返回全量政策列表（含禁用），按创建时间倒序。

#### GET /v3/admin/order/refund-policy/enabled

| 参数 | 位置 | 类型 | 必填 | 说明 |
|------|------|------|------|------|
| payType | Query | String | 否 | 按支付类型过滤。传 FULL 返回 FULL+BOTH 的政策；传 DEPOSIT 返回 DEPOSIT+BOTH 的政策；不传返回全部启用政策 |

#### GET /v3/admin/order/refund-policy/{policyId}

| 参数 | 位置 | 类型 | 必填 | 说明 |
|------|------|------|------|------|
| policyId | Path | Long(String) | 是 | 退款政策 ID |

### 4.2 创建/修改退款政策（请求体）

POST /v3/admin/order/refund-policy 和 PUT /v3/admin/order/refund-policy/{policyId} 共用同一请求体结构：

| 字段 | 类型 | 必填 | 校验 | 说明 |
|------|------|------|------|------|
| policyName | String | 是 | 最大 100 字 | 政策名称，如「国内游退款政策」 |
| remark | String | 否 | 最大 500 字 | 备注说明 |
| applyPayType | String | 否 | FULL/DEPOSIT/BOTH | 适用支付类型；不传默认 BOTH |
| rules | Array | 是 | 不能为空 | 退款规则阶梯 |
| rules[].minDays | Integer | 是 | >= 0 | 距出发最少天数（含当天）。例如 minDays=7 表示出发前 7 天及以上适用此规则 |
| rules[].refundRatio | Integer | 是 | 0~100 | 退款比例（百分比）。0=不可退；100=全退 |

PUT 时额外路径参数：

| 参数 | 位置 | 类型 | 必填 | 说明 |
|------|------|------|------|------|
| policyId | Path | Long(String) | 是 | 退款政策 ID |

### 4.3 删除退款政策

DELETE /v3/admin/order/refund-policy/{policyId}

| 参数 | 位置 | 类型 | 必填 | 说明 |
|------|------|------|------|------|
| policyId | Path | Long(String) | 是 | 退款政策 ID |

### 4.4 启用/禁用退款政策

PUT /v3/admin/order/refund-policy/{policyId}/toggle

| 参数 | 位置 | 类型 | 必填 | 说明 |
|------|------|------|------|------|
| policyId | Path | Long(String) | 是 | 退款政策 ID |
| enabled | Query | Boolean | 是 | true=启用；false=禁用 |

### 4.5 创建/修改退款原因（请求体）

POST /v3/admin/order/refund-policy/reason 和 PUT /v3/admin/order/refund-policy/reason/{reasonId} 共用：

| 字段 | 类型 | 必填 | 校验 | 说明 |
|------|------|------|------|------|
| reasonText | String | 是 | 最大 200 字 | 退款原因文本，展示给 C 端用户，如「行程有变」 |
| reasonCode | String | 否 | 最大 64 字 | 机器可读编码，如 TIME_CONFLICT / OTHER |
| category | String | 否 | 最大 50 字 | 分类，走数据字典 refund_reason_category（见第 6 节） |
| sortOrder | Integer | 否 | - | 排序号，数字越小越靠前 |

### 4.6 删除退款原因

DELETE /v3/admin/order/refund-policy/reason/{reasonId}

| 参数 | 位置 | 类型 | 必填 | 说明 |
|------|------|------|------|------|
| reasonId | Path | Long(String) | 是 | 退款原因 ID |

---

## 5. 出参字段

### 5.1 RefundPolicyVO（退款政策）

| 字段 | 类型 | 说明 |
|------|------|------|
| policyId | String | 政策 ID（Long 序列化为 String，防 JS 精度丢失） |
| policyName | String | 政策名称 |
| enabled | Boolean | 是否启用 |
| applyPayType | String | 适用支付类型：FULL/DEPOSIT/BOTH（见第 6 节） |
| remark | String | 备注 |
| createdBy | String | 创建人 ID |
| createTime | String | 创建时间 ISO 格式，如 2026-06-01T10:00:00 |
| updateTime | String | 更新时间 |
| rules | Array | 退款规则阶梯列表 |
| rules[].ruleId | String | 规则 ID |
| rules[].minDays | Integer | 距出发最少天数 |
| rules[].refundRatio | Integer | 退款比例（百分比） |

阶梯算法说明：规则按 minDays 降序排列，距出发天数 >= 当前规则 minDays 时命中。calculatedAmount = paidAmount x refundRatio / 100，向下取整保留 2 位小数。

### 5.2 RefundReasonVO（退款原因）

| 字段 | 类型 | 说明 |
|------|------|------|
| reasonId | String | 原因 ID |
| reasonText | String | 原因描述，展示给 C 端 |
| reasonCode | String | 机器可读编码 |
| category | String | 分类（字典 refund_reason_category 的 key） |
| sortOrder | Integer | 排序号 |
| enabled | Boolean | 是否启用 |

---

## 6. 枚举 / 数据字典

### 6.1 applyPayType（适用支付类型）—— 字典 payment_type

| 值 | 中文 | 说明 |
|----|------|------|
| FULL | 全款支付 | 仅适用于全款支付的订单 |
| DEPOSIT | 定金支付 | 仅适用于定金+尾款的订单 |
| BOTH | 两者均可 | 全款和定金订单均适用（不传默认值） |

### 6.2 退款原因分类 —— 字典 refund_reason_category

category 字段存储字典 key，前端下拉展示时从数据字典接口获取标签。常见 key 示例（以实际字典表为准）：

| key 示例 | 说明 |
|----------|------|
| USER_REASON | 用户原因（行程变化/临时改变等） |
| SERVICE_REASON | 服务原因（产品质量问题等） |
| OTHER | 其他 |

字典实际值以管理后台数据字典模块配置为准，前端需从字典接口动态拉取。

---

## 7. 错误码

| 错误码 | 说明 | 触发场景 |
|--------|------|----------|
| 530209 | 退款政策阶梯天数重复或重叠 | 创建/修改政策时 rules 中有 minDays 重叠的规则 |
| 530210 | 退款政策正在被使用，无法删除 | 删除政策时有退款申请正在引用该政策 |
| 400 | 参数校验失败 | policyName 为空、rules 为空、refundRatio 超范围等 |

---

## 8. 示例

### 8.1 典型成功：创建退款政策

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

```json
{
  "policyName": "国内游标准退款政策",
  "applyPayType": "FULL",
  "remark": "适用于所有国内游产品",
  "rules": [
    { "minDays": 30, "refundRatio": 90 },
    { "minDays": 15, "refundRatio": 70 },
    { "minDays": 7,  "refundRatio": 50 },
    { "minDays": 0,  "refundRatio": 0  }
  ]
}
```

响应：

```json
{
  "code": 200,
  "data": {
    "policyId": "1234567890123456789",
    "policyName": "国内游标准退款政策",
    "enabled": true,
    "applyPayType": "FULL",
    "remark": "适用于所有国内游产品",
    "createTime": "2026-06-22T10:00:00",
    "rules": [
      { "ruleId": "111", "minDays": 30, "refundRatio": 90 },
      { "ruleId": "112", "minDays": 15, "refundRatio": 70 },
      { "ruleId": "113", "minDays": 7,  "refundRatio": 50 },
      { "ruleId": "114", "minDays": 0,  "refundRatio": 0  }
    ]
  },
  "msg": "success"
}
```

### 8.2 边界情况：不可退政策（仅一条 minDays=0, refundRatio=0）

请求体：

```json
{
  "policyName": "不可退政策",
  "applyPayType": "BOTH",
  "rules": [ { "minDays": 0, "refundRatio": 0 } ]
}
```

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

### 8.3 业务失败：阶梯天数重叠

请求体：

```json
{
  "policyName": "冲突政策",
  "rules": [
    { "minDays": 7, "refundRatio": 80 },
    { "minDays": 7, "refundRatio": 50 }
  ]
}
```

响应：

```json
{ "code": 530209, "data": null, "msg": "退款政策阶梯天数重复或重叠：7" }
```

---

## 9. 业务边界

适用场景：
- 管理员在「退款设置」模块维护全局退款政策库
- 产品编排时从 GET /enabled 拉取可选政策列表绑定到产品；payType 过滤：全款产品传 FULL，定金产品传 DEPOSIT

不适用场景：
- 接口不开放给小程序 C 端（C 端只能查已绑定政策的规则预览）
- 删除或禁用政策后，已绑定该政策的产品申请退款时降级使用默认政策（全退），前端不需要特殊处理

特殊边界：
- 修改政策规则时，替换整个 rules 列表（不做增量合并），需传完整阶梯
- 历史退款申请已快照政策信息（policyName/refundRatio），修改政策不影响已有退款申请
- 退款原因删除为软删，C 端不再展示，但已使用该原因的历史申请原因文本仍保留

---

## 10. 修改前后对比

本文档为对接说明文档，无改动历史，跳过本节。

---

## 11. 影响评估 / 回滚

本文档为对接说明文档，跳过本节。

---

## 12. 注意事项

1. ID 字段均为 String 类型：policyId / ruleId / reasonId 在 JSON 中返回 String（Long 转 String 防 JS 精度丢失），前端接收和传参均用 String，不要转 Number
2. rules 阶梯天数语义：minDays 是「距出发最少天数（含）」，无 maxDays 字段，阶梯间隔由两条相邻规则的 minDays 差值隐式决定
3. enabled 接口 payType 过滤逻辑：传 FULL 返回 FULL+BOTH，传 DEPOSIT 返回 DEPOSIT+BOTH，因为 BOTH 类政策两种支付类型都适用
4. 修改政策 rules 为全量替换，传入 rules 列表会替换原有所有规则，不支持单条追加

---

## 13. 关联 / 联系人

- **服务**: hl-order-service-v3（端口 8086）
- **后端负责人**: 腰苏图
- **Gitea 项目**: https://git.1814.love:8443/wx/HL
