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
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- 第三方交易 IDcreated_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- 第三方交易 IDcallback_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__.pyapp/models/recharge/enums.pyapp/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.pyapp/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
相关文档
变更类型:新功能
影响范围:充值服务
向后兼容:是(新增服务)
需要迁移:是(执行数据库迁移脚本)