支付成功后自动开通权限流程

概述

当用户支付成功后,系统会自动开通相应的订阅权限和Token额度。本文档说明完整的自动开通流程。

流程说明

1. 创建支付订单

当用户选择套餐并创建支付订单时:

# src/users/billing.py - create_payment()
payment = PaymentRecord(...)
# 保存计划信息到支付记录的外部数据中
payment.external_data = {
    "plan": plan.value,  # 例如: "personal"
    "months": months     # 订阅月数
}

关键点

  • 支付记录中保存了订阅计划信息
  • 如果免费计划(金额为0),会立即激活,无需支付

2. 支付回调处理

当支付渠道(微信/支付宝/Stripe)发送支付成功回调时:

# src/users/billing.py - handle_payment_callback()
# 1. 验证支付回调签名
# 2. 更新支付状态为 COMPLETED
# 3. 从支付记录中获取订阅计划
plan = payment.external_data.get("plan")  # 优先使用创建订单时保存的计划
# 4. 升级订阅
await user_service.upgrade_subscription(payment.user_id, plan)
# 5. 同步更新Token计费配置
await token_billing_service.upgrade_plan(payment.user_id, plan.value)

3. 订阅升级

# src/users/service.py - upgrade_subscription()
# 1. 更新用户订阅信息
subscription.plan = new_plan
subscription.status = SubscriptionStatus.ACTIVE
subscription.started_at = datetime.utcnow()
subscription.expires_at = datetime.utcnow() + timedelta(days=30)
# 2. 同步更新Token计费配置
await token_billing_service.upgrade_plan(user_id, new_plan.value)

4. Token计费配置更新

# src/users/token_billing.py - upgrade_plan()
# 更新用户Token余额表中的套餐配置
UPDATE user_token_balance SET
    plan_code = :plan_code,
    monthly_quota = :monthly_quota,
    updated_at = NOW()
WHERE user_id = :user_id

自动开通的内容

支付成功后,系统会自动完成以下操作:

  1. 订阅状态更新

    • 套餐类型更新为新套餐
    • 订阅状态设置为 ACTIVE
    • 设置订阅开始时间和到期时间(30天)
  2. Token额度更新

    • 更新 user_token_balance 表中的套餐代码
    • 更新月度Token限额(根据新套餐配置)
    • 例如:
      • 免费版:50,000 Token/月
      • 个人版:500,000 Token/月
      • 专业版:2,000,000 Token/月
      • 企业版:无限Token
  3. 权限更新

    • 根据新套餐更新用户权限
    • 包括:API访问权限、历史记录保留天数、专家访问权限等

API端点

支付回调端点

POST /api/v1/users/payment/callback/{provider}

参数

  • provider: 支付渠道(wechat/alipay/stripe)
  • payment_id: 支付订单ID(可选,可从回调数据中解析)
  • callback_data: 支付回调数据(JSON或表单数据)

示例

# 微信支付回调
curl -X POST "http://localhost:8000/api/v1/users/payment/callback/wechat" \
  -H "Content-Type: application/json" \
  -d '{
    "out_trade_no": "payment_id_here",
    "transaction_id": "wx_transaction_id",
    "total_fee": 1900,
    "trade_state": "SUCCESS"
  }'

测试支付回调

模拟支付成功回调

from src.users.billing import billing_service, PaymentProvider
from uuid import UUID

# 假设有一个支付订单ID
payment_id = UUID("your-payment-id-here")

# 模拟支付成功回调
callback_data = {
    "transaction_id": "test_transaction_123",
    "total_fee": 1900,
    "trade_state": "SUCCESS"
}

# 处理回调
success = await billing_service.handle_payment_callback(
    payment_id=payment_id,
    provider=PaymentProvider.WECHAT,
    callback_data=callback_data
)

if success:
    print("支付成功,权限已自动开通")
else:
    print("支付处理失败")

注意事项

1. 支付记录存储

当前实现使用内存字典 _payments 存储支付记录,生产环境需要改为数据库存储

# 当前实现(仅用于开发)
self._payments: Dict[UUID, PaymentRecord] = {}

# 生产环境应改为数据库存储
# 需要创建 payments 表并实现持久化

2. 回调签名验证

当前 _verify_callback() 方法返回 True生产环境必须实现真实的签名验证

async def _verify_callback(
    self,
    provider: PaymentProvider,
    callback_data: Dict[str, Any]
) -> bool:
    """验证支付回调签名"""
    if provider == PaymentProvider.WECHAT:
        # 实现微信支付签名验证
        # 使用微信支付API密钥验证签名
        pass
    elif provider == PaymentProvider.ALIPAY:
        # 实现支付宝签名验证
        pass
    # ...
    return True  # 当前简化处理

3. 计划信息获取

支付回调处理中,优先从支付记录的 external_data 中获取计划信息,确保准确性:

# 优先使用创建订单时保存的计划
plan_value = payment.external_data.get("plan")
if plan_value:
    plan = SubscriptionPlan(plan_value)
else:
    # 如果没有,尝试从回调数据获取(可能不准确)
    plan = callback_data.get("plan", SubscriptionPlan.PERSONAL)

4. 错误处理

  • 如果订阅升级失败,会记录警告日志但不会阻止支付状态更新
  • 如果Token计费配置更新失败,会记录警告日志但不会回滚订阅升级

相关文件

  • src/users/billing.py - 支付服务和回调处理
  • src/users/service.py - 用户服务和订阅管理
  • src/users/token_billing.py - Token计费服务
  • src/users/router.py - 支付回调API端点

流程图

用户选择套餐
    ↓
创建支付订单(保存计划信息)
    ↓
用户完成支付
    ↓
支付渠道发送回调
    ↓
验证回调签名
    ↓
更新支付状态为 COMPLETED
    ↓
从支付记录获取订阅计划
    ↓
升级用户订阅
    ↓
更新Token计费配置
    ↓
权限自动开通完成

总结

支付成功后会自动开通权限

流程包括:

  1. 支付回调验证
  2. 订阅状态更新
  3. Token额度更新
  4. 权限配置更新

所有操作在支付回调处理中自动完成,用户无需手动操作。