# 提现银行（Withdraw Bank）接入文档

## 一、说明

提现银行用于**配置用户提现时可选的银行 / 钱包**，以及每个银行在各代付渠道（jaya / unispay / futurepay）下的代付银行码与限额。

数据分两张表：

- **主表 `withdraw_banks`**：面向用户展示的银行 / 钱包（名字、类型、排序、启停）。
- **渠道映射表 `withdraw_bank_channels`**：每行 = 某代付渠道下的一个银行码，关联到主表银行（`bank_id`），并带单笔 min/max 限额。`bank_id=0` 表示该目录行尚未映射到主表银行。

接入方分两类：

- **用户端（App / H5）**：只读，获取「提现可选银行列表」。
- **管理后台**：对主表和渠道映射做完整 CRUD，以及「整体替换某银行的渠道关联」。

### 通用约定

- 所有接口均为 **HTTP POST**，请求 / 响应体为 **JSON**。
- 统一响应外层包裹：
  ```json
  { "code": 200, "message": "success", "data": { ... } }
  ```
  `code=200` 为成功，`data` 为各接口的响应体；失败时 `code` 为业务错误码、`message` 为提示，`data` 为 null。
- 空响应（create/update/delete）成功时 `data` 为 `{}`。
- **金额单位为 IDR（印尼盾）整数**；`min_amount` / `max_amount` 为 `0` 表示不限。
- 枚举在 JSON 中可传**字符串名**（如 `"TYPE_BANK"`）或**数字值**（如 `1`），响应默认返回字符串名。

### 鉴权头

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

---

## 二、用户端接口

### 1. 获取提现可选银行 / 钱包列表

- **POST** `/v1/user/withdraw/bank/list`
- 请求体：`{}`（无参数）
- 仅返回**启用**的主表银行；排序：钱包在前，同类按 `sort` 升序。

**响应 `data`：**
```json
{
  "banks": [
    { "name": "DANA", "type": "e-wallet" },
    { "name": "BCA",  "type": "bank" }
  ]
}
```

**字段说明：**

| 字段 | 类型 | 说明 |
|---|---|---|
| `name` | string | 银行 / 钱包名称（提现下单时回传此名） |
| `type` | string | `bank`=银行卡，`e-wallet`=钱包 |

> 用户选定 `name` 后走原有提现下单流程；后端按 name + 代付渠道查渠道映射拿到代付银行码与限额。

---

## 三、管理后台接口

### A. 主表（银行 / 钱包）

#### 1. 列表 — POST `/v1/man/withdraw/bank/list`

**请求：**

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `offset` | int32 | 否 | 偏移，`>=0` |
| `limit` | int32 | 否 | 每页条数，`0~200`；不传 / 0 默认 50 |
| `name` | string | 否 | 按名字模糊过滤 |
| `type` | enum | 否 | 按类型过滤；不传 / `TYPE_UNKNOWN` 表示不过滤 |

**响应 `data`：** `{ "total": 12, "banks": [ <WithdrawBank>, ... ] }`（含各渠道映射 `channels`）

#### 2. 新增 — POST `/v1/man/withdraw/bank/create`

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `name` | string | 是 | 名字，非空 |
| `type` | enum | 是 | `TYPE_BANK` / `TYPE_EWALLET` |
| `sort` | int32 | 否 | 排序，越小越靠前 |
| `is_disabled` | bool | 否 | 是否禁用 |

响应 `data`：`{}`

#### 3. 更新 — POST `/v1/man/withdraw/bank/update`

字段同 create，额外必填 `id`（int64，`>0`）。整体覆盖 name/type/sort/is_disabled。`id` 不存在返回未找到错误。响应 `data`：`{}`

#### 4. 删除 — POST `/v1/man/withdraw/bank/delete`

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

删除主表银行，同时把其下渠道映射的 `bank_id` 置 0（保留在目录里，解除关联）。响应 `data`：`{}`

### B. 渠道映射目录

#### 5. 列表 — POST `/v1/man/withdraw/bank/channel/list`

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `offset` | int32 | 否 | `>=0` |
| `limit` | int32 | 否 | `0~500`；不传 / 0 默认 50 |
| `bank_id` | int64 | 否 | 按主表银行过滤（`>0` 生效） |
| `channel_type` | enum | 否 | 按渠道过滤；`TYPE_UNKNOWN` 不过滤 |

**响应 `data`：** `{ "total": 30, "channels": [ <WithdrawBankChannel>, ... ] }`

#### 6. 新增 — POST `/v1/man/withdraw/bank/channel/create`

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `channel_type` | enum | 是 | 渠道，非 `TYPE_UNKNOWN` |
| `code` | string | 是 | 渠道代付银行码，非空 |
| `bank_id` | int64 | 否 | 映射主表 id，0=未映射 |
| `is_disabled` | bool | 否 | 是否禁用 |
| `min_amount` | int64 | 否 | 单笔最小 IDR，0=不限 |
| `max_amount` | int64 | 否 | 单笔最大 IDR，0=不限 |

约束：同一银行在同一渠道下只能关联一条（`bank_id>0` 时校验，重复返回已存在错误）。响应 `data`：`{}`

#### 7. 更新 — POST `/v1/man/withdraw/bank/channel/update`

字段同 create，额外必填 `id`（int64，`>0`）。同渠道同银行唯一校验（排除自身）。响应 `data`：`{}`

#### 8. 删除 — POST `/v1/man/withdraw/bank/channel/delete`

`id`（int64，必填，`>0`）。物理删除该映射。响应 `data`：`{}`

#### 9. 整体设置某银行的渠道关联 — POST `/v1/man/withdraw/bank/channel/set`

一次性替换某主表银行的全部渠道关联：先把该银行历史关联清掉（`bank_id` 置 0），再按传入项重建（命中目录行则改其 `bank_id`/限额，否则新建）。

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `bank_id` | int64 | 是 | 主表银行 id，`>0`，需存在 |
| `items` | array | 否 | 渠道关联集合，每个渠道至多一条（重复 `channel_type` 报错） |
| `items[].channel_type` | enum | 是 | 渠道，非 `TYPE_UNKNOWN` |
| `items[].code` | string | 是 | 渠道代付银行码 |
| `items[].is_disabled` | bool | 否 | 是否禁用 |
| `items[].min_amount` | int64 | 否 | 0=不限 |
| `items[].max_amount` | int64 | 否 | 0=不限 |

响应 `data`：`{}`

---

## 四、模型字段说明

### WithdrawBank（主表，后台列表/详情返回）

| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int64 | 主键 |
| `name` | string | 银行 / 钱包名（唯一） |
| `type` | enum | 见 WithdrawBank.Type |
| `sort` | int32 | 排序，越小越靠前 |
| `is_disabled` | bool | 是否禁用（用户端只看到启用的） |
| `channels` | array\<WithdrawBankChannel\> | 该银行各渠道映射 |
| `created_at` | int64 | 创建时间（Unix 秒） |
| `updated_at` | int64 | 更新时间（Unix 秒） |

### WithdrawBankChannel（渠道映射）

| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | int64 | 主键 |
| `channel_type` | enum | 见 WithdrawBankChannel.Type |
| `code` | string | 渠道代付银行码 |
| `bank_id` | int64 | 映射主表 id，0=未映射 |
| `is_disabled` | bool | 是否禁用 |
| `min_amount` | int64 | 单笔最小 IDR，0=不限 |
| `max_amount` | int64 | 单笔最大 IDR，0=不限 |
| `created_at` | int64 | 创建时间（Unix 秒） |
| `updated_at` | int64 | 更新时间（Unix 秒） |

### 枚举

**WithdrawBank.Type**（银行类型）

| 名 | 值 | 说明 |
|---|---|---|
| `TYPE_UNKNOWN` | 0 | 未知（过滤时表示不限） |
| `TYPE_BANK` | 1 | 银行卡 |
| `TYPE_EWALLET` | 2 | 钱包 |

> 用户端 `type` 字符串：银行卡=`bank`，钱包=`e-wallet`。

**WithdrawBankChannel.Type**（代付渠道）

| 名 | 值 | 说明 |
|---|---|---|
| `TYPE_UNKNOWN` | 0 | 未知（过滤时表示不限） |
| `TYPE_JAYAPAY` | 1 | JayaPay |
| `TYPE_UNISPAY` | 2 | UnisPay |
| `TYPE_FUTUREPAY` | 3 | FuturePay |

---

## 五、接口一览

| 接入方 | 方法 | 路径 | 作用 |
|---|---|---|---|
| 用户端 | POST | `/v1/user/withdraw/bank/list` | 提现可选银行/钱包列表 |
| 后台 | POST | `/v1/man/withdraw/bank/list` | 主表列表 |
| 后台 | POST | `/v1/man/withdraw/bank/create` | 新增主表银行 |
| 后台 | POST | `/v1/man/withdraw/bank/update` | 更新主表银行 |
| 后台 | POST | `/v1/man/withdraw/bank/delete` | 删除主表银行 |
| 后台 | POST | `/v1/man/withdraw/bank/channel/list` | 渠道映射列表 |
| 后台 | POST | `/v1/man/withdraw/bank/channel/create` | 新增渠道映射 |
| 后台 | POST | `/v1/man/withdraw/bank/channel/update` | 更新渠道映射 |
| 后台 | POST | `/v1/man/withdraw/bank/channel/delete` | 删除渠道映射 |
| 后台 | POST | `/v1/man/withdraw/bank/channel/set` | 整体设置某银行的渠道关联 |
