# 充值渠道（Deposit Channel）接入文档

## 一、说明

充值渠道用于**配置用户充值时可选的支付渠道**。每个「提供商 + 支付方式」组合是**一条独立渠道**，例如 jaya 的 QRIS、jaya 的 BRI 算两条；有些渠道（如 futurepay）在渠道商侧选择方式，不需要额外参数。

单表 `deposit_channels`，每行包含：内部名、显示名、提供商（`pay_type`）、创建参数（`params`，如 `{"method":"QRIS"}`）、单笔 min/max 限额、排序、启停。

接入方分两类：

- **用户端（App / H5）**：传**要购买的硬币数**，后端换算成 IDR 金额后，返回当前金额可用的渠道列表，前端展示给用户选择，再按返回的 `pay_type` 调用对应的下单接口。
- **管理后台**：对充值渠道做完整 CRUD。

### 前端使用流程

1. 调 `POST /v1/order/deposit/channel/list`，传 `{"coins": 购买的硬币数}`。
2. 拿到可用渠道列表（已按金额过滤、`sort` 降序）。每条渠道含 `pay_type` + `display_name` + `params`。
3. 用户选定某渠道后，**按 `pay_type` 映射到对应的下单接口**，并把 `params` 里的参数转发过去：

   | `pay_type` | 下单接口 | 需转发的 params |
   |---|---|---|
   | `PAY_TYPE_JAYA` (15) | `POST /v1/order/jaya/create` | `method`（QRIS / BRI） |
   | `PAY_TYPE_UNISPAY` (17) | `POST /v1/order/unispay/create` | `pay_type`（6212 扫码 / 6211 钱包 / 6210 网银，6210 另需 `bank`） |
   | `PAY_TYPE_FUTUREPAY` (14) | `POST /v1/order/futurepay/create` | 无（params 为空，渠道商侧选择） |
   | `PAY_TYPE_HAIPAY` (13) | `POST /v1/order/haipay/create` | 无 |
   | `PAY_TYPE_MONETA_PAY` (6) | `POST /v1/order/monetapay/create` | 视配置 |
   | `PAY_TYPE_STRIPE` (4) | `POST /v1/order/stripe/payment/create` | 视配置 |

> 渠道列表接口与下单是分离的：列表只负责「告诉前端有哪些渠道、用哪个接口、带什么参数」，实际下单仍走各自原有的 create 接口。

### 通用约定

- 所有接口均为 **HTTP POST**，请求 / 响应体为 **JSON**。
- 统一响应外层包裹：
  ```json
  { "code": 200, "message": "success", "data": { ... } }
  ```
  成功 `code=200`；空响应（create/update/delete）成功时 `data` 为 `{}`。
- **金额单位为 IDR（印尼盾）整数**；`min_amount` / `max_amount` 为 `0` 表示不限。
- `pay_type` 枚举在 JSON 中可传字符串名（`"PAY_TYPE_JAYA"`）或数字值（`15`），响应默认返回字符串名。
- `params` 为字符串字典 `map<string,string>`，空为 `{}`。

### 金额换算（用户端筛选逻辑）

后端取汇率参数 `WealthParameter`，按下式把硬币数换算成 IDR 再与渠道 min/max 比较：

```
idr = floor( coins × RateCoinsToUs × RateUsToInd )
```

只返回 `is_disabled=false` 且 `idr` 落在 `[min_amount, max_amount]`（0=不限）内的渠道，按 `sort` 降序（越大越靠前）。

### 鉴权头

| 接入方 | 路径前缀 | 鉴权 |
|---|---|---|
| 用户端 | `/v1/order/...` | `Authorization: <token>` + App 签名头 `X-Meta-Sign` / `X-Meta-Device-Id` / `X-Meta-Timestamp`（与其他用户接口一致） |
| 管理后台 | `/v1/man/...` | `Authorization: <admin token>`（需管理员账号，无需 App 签名） |

---

## 二、用户端接口

### 1. 列出可用充值渠道

- **POST** `/v1/order/deposit/channel/list`

**请求：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `coins` | int64 | 是 | 要购买的硬币数，`>0`。后端换算成 IDR 再过滤 |

**响应 `data`：**
```json
{
  "channels": [
    {
      "pay_type": "PAY_TYPE_JAYA",
      "display_name": "QRIS",
      "params": { "method": "QRIS" },
      "min_amount": 0,
      "max_amount": 5000000
    },
    {
      "pay_type": "PAY_TYPE_UNISPAY",
      "display_name": "E-Wallet",
      "params": { "pay_type": "6211" },
      "min_amount": 0,
      "max_amount": 0
    }
  ]
}
```

**字段说明（DepositChannelOption）：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `pay_type` | enum | 提供商 / 路由，前端据此选下单接口（见上方映射表） |
| `display_name` | string | 展示给用户的渠道名 |
| `params` | map\<string,string\> | 转发给下单接口的参数（method / pay_type / bank…），空为 `{}` |
| `min_amount` | int64 | 单笔最小 IDR，0=不限（仅供展示，后端已过滤） |
| `max_amount` | int64 | 单笔最大 IDR，0=不限（仅供展示，后端已过滤） |

> 内部名 `name`、`is_disabled`、时间戳等不下发给用户端。

---

## 三、管理后台接口

### 1. 列表 — POST `/v1/man/deposit/channel/list`

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `offset` | int32 | 否 | `>=0` |
| `limit` | int32 | 否 | `0~200`；不传 / 0 默认 50 |
| `name` | string | 否 | 按内部名 / 显示名模糊过滤 |
| `pay_type` | enum | 否 | 按提供商过滤；不传 / `PAY_TYPE_UNKNOWN` 不过滤 |

**响应 `data`：** `{ "total": 5, "channels": [ <DepositChannel>, ... ] }`，按 `sort` 降序、再 `id` 升序。

### 2. 新增 — POST `/v1/man/deposit/channel/create`

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `name` | string | 是 | 内部名，非空 |
| `display_name` | string | 是 | 显示名，非空 |
| `pay_type` | enum | 是 | 提供商，须为可下单提供商之一（见下方白名单），否则报参数错误 |
| `params` | map\<string,string\> | 否 | 创建参数，如 `{"method":"QRIS"}`；不传存为 `{}` |
| `min_amount` | int64 | 否 | `>=0`，0=不限 |
| `max_amount` | int64 | 否 | `>=0`，0=不限 |
| `sort` | int32 | 否 | 排序，越大越靠前 |
| `is_disabled` | bool | 否 | 是否禁用 |

响应 `data`：`{}`

**pay_type 白名单**（仅这些有对应下单接口，其余拒绝）：`PAY_TYPE_JAYA`、`PAY_TYPE_UNISPAY`、`PAY_TYPE_FUTUREPAY`、`PAY_TYPE_HAIPAY`、`PAY_TYPE_MONETA_PAY`、`PAY_TYPE_STRIPE`。

### 3. 更新 — POST `/v1/man/deposit/channel/update`

字段同 create，额外必填 `id`（int64，`>0`）。整体覆盖各字段（含 `params`，传空则覆盖为 `{}`）。`id` 不存在返回未找到错误。响应 `data`：`{}`

### 4. 删除 — POST `/v1/man/deposit/channel/delete`

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id` | int64 | 是 | 渠道 id，`>0` |

物理删除。响应 `data`：`{}`

---

## 四、模型字段说明

### DepositChannel（后台列表/详情返回）

| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int64 | 主键 |
| `name` | string | 内部名（运营识别用，不唯一约束） |
| `display_name` | string | 前端显示名 |
| `pay_type` | enum | 提供商 / 路由，见下方枚举 |
| `params` | map\<string,string\> | 创建参数，如 `{"method":"QRIS"}` / `{"pay_type":"6212"}`，空为 `{}` |
| `min_amount` | int64 | 单笔最小 IDR，0=不限 |
| `max_amount` | int64 | 单笔最大 IDR，0=不限 |
| `sort` | int32 | 排序，越大越靠前（列表与下发均按此降序） |
| `is_disabled` | bool | 是否禁用（用户端只看到启用的） |
| `created_at` | int64 | 创建时间（Unix 秒） |
| `updated_at` | int64 | 更新时间（Unix 秒） |

### pay_type 枚举（复用 Order.PayType，仅充值相关）

| 名 | 值 | 提供商 | params 约定 |
|---|---|---|---|
| `PAY_TYPE_STRIPE` | 4 | Stripe | 视配置 |
| `PAY_TYPE_MONETA_PAY` | 6 | MonetaPay | 视配置 |
| `PAY_TYPE_HAIPAY` | 13 | HaiPay | 无 |
| `PAY_TYPE_FUTUREPAY` | 14 | FuturePay | 无（渠道商侧选择） |
| `PAY_TYPE_JAYA` | 15 | JayaPay | `method`：`QRIS` / `BRI` |
| `PAY_TYPE_UNISPAY` | 17 | UnisPay | `pay_type`：`6212` 扫码 / `6211` 钱包 / `6210` 网银（网银另需 `bank`） |

> `PAY_TYPE_UNKNOWN`(0) 仅用于后台列表「不按提供商过滤」，不可用于新增 / 更新。

---

## 五、初始化数据

迁移在**空表时**写入以下 5 条（min/max 均为 0=不限，`is_disabled=false`）：

| name | display_name | pay_type | params | sort |
|---|---|---|---|---|
| `jaya-qris` | QRIS | PAY_TYPE_JAYA | `{"method":"QRIS"}` | 100 |
| `jaya-bri` | BRI | PAY_TYPE_JAYA | `{"method":"BRI"}` | 90 |
| `unispay-qris` | QRIS | PAY_TYPE_UNISPAY | `{"pay_type":"6212"}` | 80 |
| `unispay-wallet` | E-Wallet | PAY_TYPE_UNISPAY | `{"pay_type":"6211"}` | 70 |
| `futurepay` | FuturePay | PAY_TYPE_FUTUREPAY | `{}` | 60 |

---

## 六、接口一览

| 接入方 | 方法 | 路径 | 作用 |
|---|---|---|---|
| 用户端 | POST | `/v1/order/deposit/channel/list` | 按硬币数列出可用充值渠道 |
| 后台 | POST | `/v1/man/deposit/channel/list` | 渠道列表 |
| 后台 | POST | `/v1/man/deposit/channel/create` | 新增渠道 |
| 后台 | POST | `/v1/man/deposit/channel/update` | 更新渠道 |
| 后台 | POST | `/v1/man/deposit/channel/delete` | 删除渠道 |
