# Recharge Service 实现 > **日期**:2026-01-27 > **类型**:新功能 > **影响范围**:充值服务 --- ## 变更概述 实现完整的充值管理服务(recharge-service),支持用户充值订单创建、支付处理、支付回调、订单管理等功能。集成微信支付和支付宝支付。 --- ## 变更详情 ### 1. 数据库设计 **新增表**: #### recharge_orders(充值订单表) - `order_id` - UUID v7 主键 - `user_id` - 用户 ID(应用层验证) - `package_id` - 套餐 ID(可选,应用层验证) - `order_no` - 订单编号(唯一) - `amount` - 订单金额 - `credits` - 基础积分数 - `bonus_credits` - 赠送积分数 - `payment_method` - 支付方式(SMALLINT:1=微信,2=支付宝) - `payment_status` - 支付状态(SMALLINT:1=待支付,2=已支付,3=失败,4=退款,5=取消) - `transaction_id` - 第三方交易 ID - `created_at` - 创建时间 - `paid_at` - 支付时间 - `expired_at` - 过期时间 - `remark` - 备注 **索引**: - 基础索引:user_id, package_id, order_no, created_at, transaction_id - 组合索引:(user_id, payment_status), (user_id, created_at) - 条件索引:payment_status WHERE payment_status = 1(优化待支付查询) #### payment_callbacks(支付回调日志表) - `callback_id` - UUID v7 主键 - `order_no` - 订单编号 - `payment_method` - 支付方式(SMALLINT) - `transaction_id` - 第三方交易 ID - `callback_data` - 回调数据(JSONB) - `is_processed` - 是否已处理 - `process_result` - 处理结果 - `created_at` - 接收时间 - `processed_at` - 处理时间 **索引**: - 基础索引:order_no, is_processed, created_at - 组合索引:(order_no, created_at) ### 2. 枚举类型 **新增文件**:`app/models/recharge/enums.py` ```python class PaymentMethod(IntEnum): """支付方式""" WECHAT = 1 # 微信支付 ALIPAY = 2 # 支付宝 class PaymentStatus(IntEnum): """支付状态""" PENDING = 1 # 待支付 PAID = 2 # 已支付 FAILED = 3 # 支付失败 REFUNDED = 4 # 已退款 CANCELLED = 5 # 已取消 ``` ### 3. 模型定义 **新增文件**: - `app/models/recharge/__init__.py` - `app/models/recharge/enums.py` - `app/models/recharge/order.py` **特性**: - 使用 UUID v7 主键 - 无外键约束(应用层验证) - 枚举使用 SMALLINT 存储 - 完整的索引策略 - to_dict() 方法返回 camelCase 字段 ### 4. Repository 层 **新增文件**:`app/repositories/recharge_repository.py` **功能**: - ✅ 引用完整性验证(exists_user, exists_package) - ✅ 订单 CRUD 操作 - ✅ 订单查询(按用户、状态、分页) - ✅ 过期订单查询 - ✅ 回调日志记录 - ✅ 孤儿订单检查 - ✅ 用户删除时取消待支付订单 ### 5. Service 层 **新增文件**:`app/services/recharge_service.py` **核心功能**: #### 创建充值订单 ```python async def create_order( user_id: UUID, package_id: Optional[UUID] = None, amount: Optional[Decimal] = None, payment_method: str = 'wechat' ) -> Dict[str, Any] ``` - 验证用户和套餐存在性 - 生成唯一订单号(RCH + 时间戳 + 随机字符串) - 创建订单记录 - 调用 payment-service 创建支付 - 返回订单信息和支付参数 #### 处理支付回调 ```python async def handle_payment_callback( payment_method: str, callback_data: Dict[str, Any] ) -> Dict[str, Any] ``` - 记录回调日志 - 验证签名(调用 payment-service) - 查询订单并检查状态(幂等性) - 更新订单状态 - 增加用户积分(调用 credit-service) - 更新用户充值总额 #### 订单管理 - `get_order()` - 查询订单详情 - `get_user_orders()` - 查询用户订单列表(支持筛选和分页) - `cancel_order()` - 取消待支付订单 - `expire_orders()` - 定时任务:取消过期订单 ### 6. Schema 定义 **新增文件**:`app/schemas/recharge.py` **请求 Schema**: - `RechargeOrderCreateRequest` - 创建订单请求 - `RechargeOrderQueryRequest` - 查询订单列表请求 **响应 Schema**: - `RechargeOrderResponse` - 订单响应 - `PaymentParamsResponse` - 支付参数响应 - `RechargeOrderCreateResponse` - 创建订单响应 - `RechargeOrderListResponse` - 订单列表响应 ### 7. API 路由 **新增文件**:`app/api/v1/recharge.py` **接口列表**: | 方法 | 路径 | 说明 | 认证 | |------|------|------|------| | POST | `/api/v1/recharge/orders` | 创建充值订单 | ✅ | | GET | `/api/v1/recharge/orders/{id}` | 查询订单详情 | ✅ | | GET | `/api/v1/recharge/orders` | 查询订单列表 | ✅ | | POST | `/api/v1/recharge/orders/{id}/cancel` | 取消订单 | ✅ | | POST | `/api/v1/recharge/callbacks/wechat` | 微信支付回调 | ❌ | | POST | `/api/v1/recharge/callbacks/alipay` | 支付宝回调 | ❌ | ### 8. 数据库迁移 **新增文件**: - `app/migrations/010_recharge_service_tables.py` - `app/migrations/sql/010_recharge_service_tables.sql` **执行迁移**: ```bash python app/migrations/010_recharge_service_tables.py ``` **回滚迁移**: ```bash python app/migrations/010_recharge_service_tables.py downgrade ``` --- ## 技术实现 ### 服务架构 ``` ┌─────────────────────────────────────────────┐ │ API Layer (recharge.py) │ │ - 创建订单 │ │ - 查询订单 │ │ - 取消订单 │ │ - 支付回调 │ └─────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────┐ │ Service Layer (recharge_service.py) │ │ - 业务逻辑 │ │ - 订单管理 │ │ - 支付处理 │ │ - 回调处理 │ └─────────────────────────────────────────────┘ ↓ ↓ ↓ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Repository │ │ Credit │ │ Payment │ │ Layer │ │ Service │ │ Service │ │ - 数据访问 │ │ - 增加积分 │ │ - 创建支付 │ │ - 引用验证 │ │ │ │ - 验证回调 │ └──────────────┘ └──────────────┘ └──────────────┘ ↓ ↓ ┌──────────────┐ ┌──────────────┐ │ PostgreSQL │ │ 第三方支付 │ │ Database │ │ 平台 API │ └──────────────┘ └──────────────┘ ``` ### 核心特性 #### 1. 应用层引用完整性 - 无数据库外键约束 - Repository 层提供 exists_user() 和 exists_package() 验证 - Service 层在创建订单前验证引用完整性 - 支付回调处理时验证用户存在性 #### 2. 幂等性保证 - 支付回调处理前检查订单状态 - 已支付订单不重复处理 - 记录所有回调日志便于排查 #### 3. 订单号生成 ```python def _generate_order_no(self) -> str: """格式: RCH + 时间戳(14位) + 随机字符串(8位)""" timestamp = datetime.now(timezone.utc).strftime('%Y%m%d%H%M%S') random_str = uuid.uuid4().hex[:8].upper() return f"RCH{timestamp}{random_str}" ``` #### 4. 订单过期处理 - 订单创建时设置 30 分钟过期时间 - 定时任务自动取消过期订单 - 可通过 Celery 定时执行 `expire_orders()` #### 5. 支付集成 - 调用 payment-service 创建支付 - 支持微信支付和支付宝 - 自动验证回调签名 - 记录完整回调数据 --- ## 使用示例 ### 1. 创建充值订单(套餐) **请求**: ```bash POST /api/v1/recharge/orders Authorization: Bearer Content-Type: application/json { "packageId": "550e8400-e29b-41d4-a716-446655440000", "paymentMethod": "wechat" } ``` **响应**: ```json { "code": 200, "message": "Success", "data": { "order": { "id": "01936d8e-1234-7890-abcd-ef1234567890", "orderNo": "RCH20260127100000ABC12345", "amount": 49.9, "credits": 600, "bonusCredits": 100, "paymentMethod": "wechat", "paymentStatus": "pending", "expiredAt": "2026-01-27T10:30:00Z" }, "paymentParams": { "qrcodeUrl": "weixin://wxpay/bizpayurl?pr=xxx", "expiresIn": 1800 } } } ``` ### 2. 创建充值订单(自定义金额) **请求**: ```bash POST /api/v1/recharge/orders Authorization: Bearer Content-Type: application/json { "amount": 50.0, "paymentMethod": "alipay" } ``` ### 3. 查询订单列表 **请求**: ```bash GET /api/v1/recharge/orders?paymentStatus=paid&page=1&pageSize=20 Authorization: Bearer ``` **响应**: ```json { "code": 200, "message": "Success", "data": { "items": [ { "id": "01936d8e-1234-7890-abcd-ef1234567890", "orderNo": "RCH20260127100000ABC12345", "amount": 49.9, "credits": 600, "paymentStatus": "paid", "createdAt": "2026-01-27T10:00:00Z" } ], "total": 10, "page": 1, "pageSize": 20, "totalPages": 1 } } ``` ### 4. 取消订单 **请求**: ```bash POST /api/v1/recharge/orders/{id}/cancel Authorization: Bearer ``` --- ## 数据完整性 ### 引用完整性验证 **创建订单时**: ```python # 验证用户存在 if not await self.repository.exists_user(user_id): raise NotFoundError(f"用户不存在: {user_id}") # 验证套餐存在 if package_id and not await self.repository.exists_package(package_id): raise NotFoundError(f"套餐不存在: {package_id}") ``` **支付回调时**: ```python # 验证用户存在 if not await self.repository.exists_user(order.user_id): raise NotFoundError(f"用户不存在: {order.user_id}") ``` ### 孤儿记录检查 **定时任务**: ```python # 检查用户不存在的订单 orphan_orders = await repository.check_orphan_orders() if orphan_orders: logger.error(f"发现 {len(orphan_orders)} 个孤儿充值订单") # 发送告警通知 ``` ### 用户删除时的级联处理 ```python # 取消用户的所有待支付订单 cancelled_count = await recharge_repo.cancel_user_pending_orders(user_id) logger.info(f"用户 {user_id} 删除,已取消 {cancelled_count} 个待支付订单") # 保留已支付订单记录(用于财务审计) ``` --- ## 测试建议 ### 1. 单元测试 ```python # 测试创建订单 async def test_create_order(): order = await service.create_order( user_id=user_id, package_id=package_id, payment_method='wechat' ) assert order['order']['paymentStatus'] == 'pending' assert 'paymentParams' in order # 测试支付回调 async def test_payment_callback(): result = await service.handle_payment_callback( payment_method='wechat', callback_data=mock_callback_data ) assert result['success'] is True ``` ### 2. 集成测试 ```bash # 使用沙箱环境测试完整支付流程 1. 创建订单 2. 获取支付二维码 3. 模拟支付回调 4. 验证订单状态 5. 验证积分增加 ``` ### 3. 压力测试 ```bash # 测试并发创建订单 # 测试并发支付回调(幂等性) # 测试大量订单查询性能 ``` --- ## 后续工作 ### 1. 扩展支付方式 - 微信 H5 支付 - 微信小程序支付 - 支付宝 H5 支付 - 支付宝 APP 支付 ### 2. 订单退款 - 实现退款接口 - 调用第三方退款 API - 扣减用户积分 - 记录退款日志 ### 3. 定时任务 - 订单超时自动取消 - 孤儿订单检查和告警 - 支付回调重试机制 ### 4. 监控和告警 - 支付成功率监控 - 回调失败告警 - 异常订单告警 - 孤儿订单告警 ### 5. 财务对账 - 订单对账报表 - 支付流水导出 - 退款记录统计 --- ## 依赖关系 **依赖服务**: - user-service(验证用户存在) - credit-service(增加积分、查询套餐) - payment-service(创建支付、验证回调) **被依赖**: - 无(充值服务是业务终端) --- ## 配置要求 ### 环境变量 需要在 `.env` 文件中配置支付平台参数(已在 payment-service 中配置): ```bash # 微信支付 WECHAT_PAY_MCHID= WECHAT_PAY_PRIVATE_KEY= WECHAT_PAY_CERT_SERIAL_NO= WECHAT_PAY_APIV3_KEY= WECHAT_APPID= WECHAT_PAY_NOTIFY_URL=https://api.jointo.ai/api/v1/recharge/callbacks/wechat # 支付宝 ALIPAY_APPID= ALIPAY_PRIVATE_KEY= ALIPAY_PUBLIC_KEY= ALIPAY_NOTIFY_URL=https://api.jointo.ai/api/v1/recharge/callbacks/alipay ``` --- ## 相关文档 - [Payment Service 实现](./2026-01-27-payment-service-implementation.md) - [Credit Service 实现](./2026-01-27-credit-service-implementation.md) - [User Service 重构](./2026-01-27-user-service-refactor.md) --- **变更类型**:新功能 **影响范围**:充值服务 **向后兼容**:是(新增服务) **需要迁移**:是(执行数据库迁移脚本)