# 代理预充值功能 ## 功能概述 代理商(店铺)余额钱包的在线充值系统,支持微信在线支付和线下转账两种充值方式,具备完整的 Service/Handler/回调处理链路。充值仅针对余额钱包(`wallet_type=main`),佣金钱包通过分佣自动入账。 ### 背景与动机 原有 `tb_agent_recharge_record` 表和 Store 层骨架已存在,但缺少 Service 层和 Handler 层,无法通过 API 发起充值。本次补全完整实现,并集成至支付配置管理体系(按 `payment_config_id` 动态路由至微信直连或富友通道)。 ## 核心流程 ### 在线充值流程(微信) ``` 代理/平台 → POST /api/admin/agent-recharges │ ├─ 验证权限:代理只能充自己店铺,平台可指定任意店铺 ├─ 验证金额范围(100 元~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 | 是 | 充值金额(单位:分),范围 10000~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 = 10000 // 最小充值:100 元(单位:分) AgentRechargeMaxAmount = 100000000 // 最大充值:100 万元(单位:分) ``` ## 已知限制(留桩) **客户端支付发起未实现**:在线充值(`payment_method=wechat`)创建订单成功后,前端获取支付参数的接口本次未实现。充值回调处理已完整实现——等支付发起改造完成后,完整的充值支付闭环即可联通。