You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

14 KiB

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

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

核心功能

创建充值订单

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 创建支付
  • 返回订单信息和支付参数

处理支付回调

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

执行迁移

python app/migrations/010_recharge_service_tables.py

回滚迁移

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. 订单号生成

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. 创建充值订单(套餐)

请求

POST /api/v1/recharge/orders
Authorization: Bearer <token>
Content-Type: application/json

{
  "packageId": "550e8400-e29b-41d4-a716-446655440000",
  "paymentMethod": "wechat"
}

响应

{
  "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. 创建充值订单(自定义金额)

请求

POST /api/v1/recharge/orders
Authorization: Bearer <token>
Content-Type: application/json

{
  "amount": 50.0,
  "paymentMethod": "alipay"
}

3. 查询订单列表

请求

GET /api/v1/recharge/orders?paymentStatus=paid&page=1&pageSize=20
Authorization: Bearer <token>

响应

{
  "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. 取消订单

请求

POST /api/v1/recharge/orders/{id}/cancel
Authorization: Bearer <token>

数据完整性

引用完整性验证

创建订单时

# 验证用户存在
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}")

支付回调时

# 验证用户存在
if not await self.repository.exists_user(order.user_id):
    raise NotFoundError(f"用户不存在: {order.user_id}")

孤儿记录检查

定时任务

# 检查用户不存在的订单
orphan_orders = await repository.check_orphan_orders()
if orphan_orders:
    logger.error(f"发现 {len(orphan_orders)} 个孤儿充值订单")
    # 发送告警通知

用户删除时的级联处理

# 取消用户的所有待支付订单
cancelled_count = await recharge_repo.cancel_user_pending_orders(user_id)
logger.info(f"用户 {user_id} 删除,已取消 {cancelled_count} 个待支付订单")

# 保留已支付订单记录(用于财务审计)

测试建议

1. 单元测试

# 测试创建订单
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. 集成测试

# 使用沙箱环境测试完整支付流程
1. 创建订单
2. 获取支付二维码
3. 模拟支付回调
4. 验证订单状态
5. 验证积分增加

3. 压力测试

# 测试并发创建订单
# 测试并发支付回调(幂等性)
# 测试大量订单查询性能

后续工作

1. 扩展支付方式

  • 微信 H5 支付
  • 微信小程序支付
  • 支付宝 H5 支付
  • 支付宝 APP 支付

2. 订单退款

  • 实现退款接口
  • 调用第三方退款 API
  • 扣减用户积分
  • 记录退款日志

3. 定时任务

  • 订单超时自动取消
  • 孤儿订单检查和告警
  • 支付回调重试机制

4. 监控和告警

  • 支付成功率监控
  • 回调失败告警
  • 异常订单告警
  • 孤儿订单告警

5. 财务对账

  • 订单对账报表
  • 支付流水导出
  • 退款记录统计

依赖关系

依赖服务

  • user-service(验证用户存在)
  • credit-service(增加积分、查询套餐)
  • payment-service(创建支付、验证回调)

被依赖

  • 无(充值服务是业务终端)

配置要求

环境变量

需要在 .env 文件中配置支付平台参数(已在 payment-service 中配置):

# 微信支付
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

相关文档


变更类型:新功能
影响范围:充值服务
向后兼容:是(新增服务)
需要迁移:是(执行数据库迁移脚本)