# 申诉退款执行接口废弃 → 迁移至售后工单流程

- **日期**：2026-06-22
- **变更类型**：删除接口 ⚠️
- **端类型**：管理后台
- **后端负责人**：腰苏图

---

## 1. 接口背景

v2 退款申诉流程在 refund 域有一个独立的「手动执行退款」步骤：企微 OA 申诉审批通过后，管理员还需要手动调用 execute-appeal 接口并填写实退金额，才会真正触发微信退款。

v3 将「退款申诉」整体迁移至**售后工单中心**（com.hulalv.aftersale），并把「两步（OA 通过 + 手动执行）」改为「一步（处置时核定金额，OA 通过后系统自动退款）」。因此 v2 的 execute-appeal 接口在 v3 **不存在**。

---

## 2. 变更清单

| 变更类型 | 接口 | 说明 |
|---|---|---|
| ⚠️ 删除 | `PUT /order/refund/{applicationId}/execute-appeal` | v3 无此接口，调用返回 404 |
| ✨ 替代 | `POST /v3/admin/aftersale/ticket/{id}/resolve` | 处置工单并核定金额，OA 通过后自动退款 |
| ✨ 新增 | `POST /v3/admin/aftersale/ticket/{id}/process` | 受理申诉工单（SUBMITTED→PROCESSING） |
| ✨ 查询 | `GET /v3/admin/aftersale/ticket/page` | 申诉工单分页列表 |
| ✨ 查询 | `GET /v3/admin/aftersale/ticket/{id}` | 申诉工单详情 |

---

## 3. 废弃接口明细

### PUT /order/refund/{applicationId}/execute-appeal（v2，已删除）

**⚠️ 此接口在 v3 不存在，调用将返回 404。**

- **v2 路径**：`PUT /order/refund/{applicationId}/execute-appeal`
- **v2 查询参数**：
  - `actualAmount`（BigDecimal，必填）：管理员手填的实际退款金额
  - `remark`（String，选填）：备注
- **v2 语义**：企微 OA 申诉审批通过后，状态置为 `APPEAL_APPROVED`（此时还没退钱），管理员再调此接口填写 actualAmount，才触发微信退款。这是 OA 通过后的独立手动执行步。

---

## 4. 为什么没有了

v3 申诉流程整体迁入售后工单中心，执行模型发生了根本性变化：

| 维度 | v2 | v3 |
|---|---|---|
| 金额确认时机 | OA 通过后手动填 actualAmount | 处置时就填 resolutionAmount（OA 提交前确定） |
| 退款触发方式 | 管理员手动调 execute-appeal | OA 通过后系统自动触发 |
| 申诉入口 | refund 域独立接口 | 售后工单中心（菜单：售后 → 申诉） |

因为退款触发已经自动化，所以不再需要独立的手动执行接口。

---

## 5. 迁移指引：v3 申诉退款完整链路

> 以下是管理后台视角的完整操作步骤，对应 v2 的整个申诉退款流程。

| 步骤 | v3 接口 | 方法 | 说明 |
|---|---|---|---|
| ① 发起申诉（用户侧） | `POST /v3/mp/aftersale/ticket` | POST | C 端用户发起，category=APPEAL，type=REFUND_REJECTED 或 REFUND_AMOUNT_DISPUTE，targetRefId=关联退款申请 ID |
| ② 受理工单 | `POST /v3/admin/aftersale/ticket/{id}/process` | POST | 工单状态 SUBMITTED→PROCESSING，可设 assigneeId/remark |
| ③ 处置工单（核定金额） | `POST /v3/admin/aftersale/ticket/{id}/resolve` | POST | **对应 v2 的 execute-appeal**，填 decision=APPROVE、resolutionType=REFUND、resolutionAmount=核定金额，系统自动提企微 OA |
| ④ 退款自动执行 | 无需调接口 | — | 企微 OA 审批通过后，系统自动触发微信退款，无手动执行步 |

**核心对应关系**：

```
v2：PUT /order/refund/{id}/execute-appeal?actualAmount=500.00&remark=同意退差价

v3：POST /v3/admin/aftersale/ticket/{id}/resolve
    { "decision":"APPROVE", "resolutionType":"REFUND", "resolutionAmount":500.00, "remark":"同意退差价" }
    → OA 通过后自动退款，无额外操作
```

---

## 6. resolve 接口入参字段表

**接口**：`POST /v3/admin/aftersale/ticket/{id}/resolve`
**认证**：JWT（管理后台 Token）
**路径参数**：`id`（Long，工单 ID）

**请求体（ResolveTicketReqVO）**：

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| decision | String | 必填 | 处置决定：`APPROVE`（同意）/ `REJECT`（驳回） |
| resolutionType | String | APPROVE 时必填 | 处置方式：`REFUND`（退款）/ `RECTIFY`（整改）/ `REJECT`（维持原决定） |
| resolutionAmount | BigDecimal | resolutionType=REFUND 时必填 | 后台核定退款金额，≥0，是退款的唯一金额依据（对应 v2 的 actualAmount） |
| remark | String | 选填 | 处置说明，建议填写核定原因 |

---

## 7. 错误码

| 错误码 | 含义 | 场景 |
|---|---|---|
| 旧接口 404 | v2 路径已下线 | 调用 `/order/refund/*/execute-appeal` |
| 工单相关错误码 | 见售后工单 changelog（Issue #4161） | 工单状态非法、金额超可退余额等 |

---

## 8. 示例

### 8.1 典型成功（同意退款 500 元）

**v3 新调用**：
```http
POST /v3/admin/aftersale/ticket/9001/resolve
Authorization: Bearer <admin-token>
Content-Type: application/json

{
  "decision": "APPROVE",
  "resolutionType": "REFUND",
  "resolutionAmount": 500.00,
  "remark": "经核实酒店降级，同意退差价¥500"
}
```

```json
{
  "code": 200,
  "data": null,
  "msg": "success"
}
```

OA 通过后系统自动触发微信退款，无需再调任何接口。

### 8.2 边界情况（金额为 0，驳回申诉）

```http
POST /v3/admin/aftersale/ticket/9002/resolve
Content-Type: application/json

{
  "decision": "REJECT",
  "remark": "经核实服务已按合同履行，驳回申诉"
}
```

decision=REJECT 时 resolutionType 和 resolutionAmount 可不填。

### 8.3 v2 旧接口调用（已失效，返回 404）

```http
PUT /order/refund/8001/execute-appeal?actualAmount=500.00&remark=同意退差价
```

```json
404 Not Found
（v3 此路径不存在，请迁移至 /v3/admin/aftersale/ticket/{id}/resolve）
```

---

## 9. 业务边界

**适用**：
- 用户已通过 C 端（或客服代客）发起了申诉工单
- 工单处于 PROCESSING 状态（已受理）
- resolutionAmount ≤ 订单可退余额（由 resolve 接口前置校验）

**不适用**：
- 工单尚未受理（SUBMITTED 状态），需先调 process 接口受理
- 工单已处置（RESOLVED/CLOSED），不可重复 resolve
- resolutionType=REFUND 但不传 resolutionAmount（接口拒绝）

**特殊边界**：
- resolutionAmount 与用户诉求金额 claimAmount 是双金额模型，后台核定金额由管理员独立决定，不受用户填写的 claimAmount 约束（与 v2 actualAmount 语义一致）
- 退款超额/累计校验在 refund 域兜底，resolve 时工单层也预检可退余额，两层校验

---

## 10. 修改前后对比

### 流程对比

| 阶段 | v2 流程 | v3 流程 |
|---|---|---|
| 用户发起申诉 | 调退款申诉接口（refund 域） | 创建售后工单（aftersale 域），category=APPEAL |
| 管理员受理 | 无独立受理步骤 | `POST /v3/admin/aftersale/ticket/{id}/process` |
| 核定金额 + 提 OA | 单独的 OA 提交步骤（金额 OA 通过后才填） | `POST /v3/admin/aftersale/ticket/{id}/resolve`（处置时即填金额，系统自动提 OA） |
| 执行退款 | **管理员手动调 execute-appeal** | OA 通过后**系统自动退款** |

### 字段对比

| v2 字段 | v2 语义 | v3 字段 | v3 语义 |
|---|---|---|---|
| `actualAmount`（query param） | OA 通过后手填实退金额 | `resolutionAmount`（请求体） | 处置时预填核定金额，OA 通过后直接用 |
| `remark`（query param） | 执行备注 | `remark`（请求体） | 处置说明 |
| 无 | — | `decision` | APPROVE/REJECT，明确处置决定 |
| 无 | — | `resolutionType` | REFUND/RECTIFY/REJECT，明确处置方式 |

---

## 11. 影响评估 / 回滚

**破坏兼容**：是。v2 execute-appeal 路径在 v3 不存在，直接 404。

**前端同步事项**：
1. 删除调用 `PUT /order/refund/{id}/execute-appeal` 的代码
2. 在售后工单详情页接入 `POST /v3/admin/aftersale/ticket/{id}/resolve` 替代
3. 售后工单列表/详情见 Issue #4161 的 changelog（changelogs-v2/2026-06/22_4161_售后申诉中心-新增接口-管理后台.md）

**回滚方案**：如需临时降级，可在前端继续调 v2 的 execute-appeal（v2 服务 hl-order-service-v2 端口 8094 仍在运行）；v3 no rollback，此接口不会补建。

---

## 12. 注意事项

- `resolutionAmount` 是退款的唯一金额依据，一旦 OA 通过无法修改，请管理员在处置时确认准确金额再提交。
- resolve 之后工单进入「待 OA 审批」状态，此时工单不可取消、不可重新处置；如需修改金额，需先联系技术撤回 OA 流程（当前无前端入口）。
- 售后工单中心同时承载「投诉」和「申诉」两种类型，查询时注意用 `category=APPEAL` 过滤，避免与投诉工单混淆。
- v3 申诉工单的发起方是 C 端用户（`/v3/mp/aftersale/ticket`），管理后台只有受理和处置权限，不能代客创建 APPEAL 类型工单（仅 COMPLAINT 类型支持管理端代客）。

---

## 13. 关联 / 联系人

- **关联 Issue**：https://git.1814.love:8443/wx/HL/issues/4161（售后申诉中心上线）
- **v2 原接口 PR**：历史遗留，无单独 PR 记录
- **后端负责人**：腰苏图（@yaosutu）
- **售后工单 changelog 参考**：`changelogs-v2/2026-06/22_4161_售后申诉中心-新增接口-管理后台.md`
