# 代理预充值功能

## 功能概述

代理商（店铺）余额钱包的在线充值系统，支持微信在线支付和线下转账两种充值方式，具备完整的 Service/Handler/回调处理链路。充值仅针对余额钱包（`wallet_type=main`），佣金钱包通过分佣自动入账。

### 背景与动机

原有 `tb_agent_recharge_record` 表和 Store 层骨架已存在，但缺少 Service 层和 Handler 层，无法通过 API 发起充值。本次补全完整实现，并集成至支付配置管理体系（按 `payment_config_id` 动态路由至微信直连或富友通道）。

## 核心流程

### 在线充值流程（微信）

```
代理/平台 → POST /api/admin/agent-recharges
    │
    ├─ 验证权限：代理只能充自己店铺，平台可指定任意店铺
    ├─ 验证金额范围（1 分~100 万元）
    ├─ 查找目标店铺的 main 钱包
    ├─ 查询 active 支付配置 → 无配置则拒绝（返回 1175）
    ├─ 记录 payment_config_id
    └─ 创建充值订单（status=1 待支付）
         └─ 返回订单信息（客户端支付发起【留桩】）

支付成功 → POST /api/callback/wechat-pay 或 /api/callback/fuiou-pay
    │
    ├─ 按订单号前缀 "ARCH" 识别为代理充值
    ├─ 查询充值记录，取 payment_config_id
    ├─ 按配置验签
    └─ agentRechargeService.HandlePaymentCallback()
        ├─ 幂等检查（WHERE status = 1）
        ├─ 更新充值记录状态 → 2（已完成）
        ├─ 代理主钱包余额增加（乐观锁防并发）
        └─ 创建钱包流水记录
```

### 线下充值流程（仅平台）

```
平台 → POST /api/admin/agent-recharges
    └─ payment_method = "offline"
    └─ 创建充值订单（status=1 待支付）

平台确认 → POST /api/admin/agent-recharges/:id/offline-pay
    ├─ 验证操作密码（二次鉴权）
    └─ 事务内：
        ├─ 更新充值记录状态 → 2（已完成）
        ├─ 记录 paid_at、completed_at
        ├─ 代理主钱包余额增加（乐观锁 version 字段）
        ├─ 创建钱包流水记录
        └─ 记录审计日志
```

## 接口说明

### 基础路径

`/api/admin/agent-recharges`

**权限要求**：企业账号（`user_type=4`）在路由层被拦截，返回 `1005`。

### 接口列表

| 方法 | 路径 | 说明 | 权限 |
|------|------|------|------|
| POST | `/api/admin/agent-recharges` | 创建充值订单 | 代理（自己店铺）/ 平台（任意店铺）|
| GET | `/api/admin/agent-recharges` | 查询充值记录列表 | 代理（自己店铺）/ 平台（全部）|
| GET | `/api/admin/agent-recharges/:id` | 查询充值记录详情 | 代理（自己店铺）/ 平台（全部）|
| POST | `/api/admin/agent-recharges/:id/offline-pay` | 确认线下充值到账 | 仅平台 |

### 创建充值订单

**请求体示例（在线充值）**

```json
{
  "shop_id": 101,
  "amount": 50000,
  "payment_method": "wechat"
}
```

**请求体示例（线下充值）**

```json
{
  "shop_id": 101,
  "amount": 200000,
  "payment_method": "offline"
}
```

**请求字段**

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| shop_id | integer | 是 | 目标店铺 ID（代理只能填自己所属店铺）|
| amount | integer | 是 | 充值金额（单位：分），范围 1~100000000 |
| payment_method | string | 是 | `wechat`（在线）/ `offline`（线下，仅平台）|

**成功响应**

```json
{
  "code": 0,
  "msg": "success",
  "data": {
    "id": 88,
    "recharge_no": "ARCH20260316100001",
    "shop_id": 101,
    "amount": 50000,
    "payment_method": "wechat",
    "payment_channel": "wechat_direct",
    "payment_config_id": 3,
    "status": 1,
    "created_at": "2026-03-16T10:00:00+08:00"
  },
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

### 线下充值确认

**请求体**

```json
{
  "operation_password": "Abc123456"
}
```

操作密码验证通过后，事务内同步完成：余额到账 + 钱包流水 + 审计日志。

## 权限控制矩阵

| 操作 | 平台账号 | 代理账号 | 企业账号 |
|------|----------|----------|----------|
| 创建充值（在线） | ✅ 任意店铺 | ✅ 仅自己店铺 | ❌ |
| 创建充值（线下） | ✅ 任意店铺 | ❌ | ❌ |
| 线下充值确认 | ✅ | ❌ | ❌ |
| 查询充值列表 | ✅ 全部 | ✅ 仅自己店铺 | ❌ |
| 查询充值详情 | ✅ 全部 | ✅ 仅自己店铺 | ❌ |

**越权统一响应**：代理访问他人店铺充值记录时，返回 `1121 CodeRechargeNotFound`（不区分不存在与无权限）

## 数据模型

### `tb_agent_recharge_record` 新增字段

| 字段 | 类型 | 可空 | 说明 |
|------|------|------|------|
| `payment_config_id` | bigint | 是 | 关联支付配置 ID（线下充值为 NULL，在线充值记录实际使用的配置）|

### 充值订单状态枚举

| 值 | 含义 |
|----|------|
| 1 | 待支付 |
| 2 | 已完成 |
| 3 | 已取消 |

### 支付方式与通道

| payment_method | payment_channel | 说明 |
|---------------|----------------|------|
| wechat | wechat_direct | 微信直连通道（provider_type=wechat）|
| wechat | fuyou | 富友通道（provider_type=fuiou）|
| offline | offline | 线下转账 |

> 前端统一显示"微信支付"，后端根据生效配置的 `provider_type` 自动路由，前端不感知具体通道。

### 充值单号规则

前缀 `ARCH`，全局唯一，用于回调时识别订单类型。

## 幂等性设计

- 回调处理使用状态条件更新：`WHERE status = 1`
- `RowsAffected == 0` 时说明已被处理，直接返回成功，不重复入账
- 钱包余额更新使用乐观锁（`version` 字段），并发冲突时最多重试 3 次

## 审计日志

线下充值确认（`OfflinePay`）操作记录审计日志，字段包括：

| 字段 | 值 |
|------|-----|
| `operator_id` | 当前操作人 ID |
| `operation_type` | `offline_recharge` |
| `operation_desc` | `确认代理充值到账：充值单号 {recharge_no}，金额 {amount} 分` |
| `before_data` | 操作前余额和充值记录状态 |
| `after_data` | 操作后余额和充值记录状态 |

## 涉及文件

### 新增文件

| 层级 | 文件 | 说明 |
|------|------|------|
| DTO | `internal/model/dto/agent_recharge_dto.go` | 请求/响应 DTO |
| Service | `internal/service/agent_recharge/service.go` | 充值业务逻辑 |
| Handler | `internal/handler/admin/agent_recharge.go` | 4 个 Handler 方法 |
| 路由 | `internal/routes/agent_recharge.go` | 路由注册 |

### 修改文件

| 文件 | 变更说明 |
|------|---------|
| `internal/model/agent_wallet.go` | 新增 `PaymentConfigID *uint` 字段 |
| `internal/handler/callback/payment.go` | 新增 "ARCH" 前缀分发 → agentRechargeService.HandlePaymentCallback() |
| `internal/bootstrap/` 系列 | 注册 AgentRechargeService、AgentRechargeHandler |
| `cmd/api/docs.go` / `cmd/gendocs/main.go` | 注册 AgentRechargeHandler |
| `migrations/000081_add_payment_config_id_to_agent_recharge.up.sql` | tb_agent_recharge_record 新增 payment_config_id 列 |

## 常量定义

```go
// pkg/constants/wallet.go
AgentRechargeOrderPrefix = "ARCH"            // 充值单号前缀
AgentRechargeMinAmount   = 1                 // 最小充值：1 分
AgentRechargeMaxAmount   = 100000000         // 最大充值：100 万元（单位：分）
```

## 已知限制（留桩）

**客户端支付发起未实现**：在线充值（`payment_method=wechat`）创建订单成功后，前端获取支付参数的接口本次未实现。充值回调处理已完整实现——等支付发起改造完成后，完整的充值支付闭环即可联通。
