- 新增api/payment/支付服务(微信、支付宝) - 新增api/routers/payment.py支付路由 - 更新database/models.py支付相关模型 - 新增数据库迁移文件(订单表、用户订阅字段) - 更新main.py、requirements.txt、.env.production Co-authored-by: Cursor <cursoragent@cursor.com>
174 lines
5.1 KiB
Python
174 lines
5.1 KiB
Python
"""
|
|
统一支付服务门面
|
|
提供统一的支付接口,屏蔽微信/支付宝的底层差异
|
|
"""
|
|
import logging
|
|
from typing import Dict, Optional
|
|
|
|
from .config import PaymentConfig
|
|
from .wechat_pay import WeChatPayClient
|
|
from .alipay_pay import AlipayClient
|
|
from .schemas import PaymentResult, NotifyResult, PaymentStatus
|
|
from .exceptions import PaymentError, PaymentConfigError
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# 支持的支付方式
|
|
PAYMENT_METHOD_WECHAT = "wechat"
|
|
PAYMENT_METHOD_ALIPAY = "alipay"
|
|
SUPPORTED_METHODS = {PAYMENT_METHOD_WECHAT, PAYMENT_METHOD_ALIPAY}
|
|
|
|
|
|
class PaymentService:
|
|
"""
|
|
统一支付服务
|
|
|
|
使用方式:
|
|
config = PaymentConfig.from_env()
|
|
payment_service = PaymentService(config)
|
|
|
|
# 创建支付订单
|
|
result = payment_service.create_payment("wechat", order_no, 9900, "高级版套餐")
|
|
|
|
# 处理回调
|
|
notify = payment_service.handle_wechat_notify(headers, body)
|
|
|
|
# 查询状态
|
|
status = payment_service.query_payment("wechat", order_no)
|
|
"""
|
|
|
|
def __init__(self, config: PaymentConfig):
|
|
self._config = config
|
|
self._wechat_client: Optional[WeChatPayClient] = None
|
|
self._alipay_client: Optional[AlipayClient] = None
|
|
|
|
@property
|
|
def wechat_client(self) -> WeChatPayClient:
|
|
"""获取微信支付客户端(懒加载)"""
|
|
if self._wechat_client is None:
|
|
self._wechat_client = WeChatPayClient(self._config.wechat)
|
|
return self._wechat_client
|
|
|
|
@property
|
|
def alipay_client(self) -> AlipayClient:
|
|
"""获取支付宝客户端(懒加载)"""
|
|
if self._alipay_client is None:
|
|
self._alipay_client = AlipayClient(self._config.alipay)
|
|
return self._alipay_client
|
|
|
|
def create_payment(
|
|
self,
|
|
method: str,
|
|
out_trade_no: str,
|
|
total_amount: int,
|
|
description: str,
|
|
) -> PaymentResult:
|
|
"""
|
|
创建支付订单
|
|
|
|
Args:
|
|
method: 支付方式 (wechat / alipay)
|
|
out_trade_no: 商户订单号
|
|
total_amount: 金额(单位:分)
|
|
description: 商品描述
|
|
|
|
Returns:
|
|
PaymentResult
|
|
"""
|
|
self._validate_method(method)
|
|
|
|
if method == PAYMENT_METHOD_WECHAT:
|
|
return self.wechat_client.create_app_order(
|
|
out_trade_no=out_trade_no,
|
|
total_amount=total_amount,
|
|
description=description,
|
|
)
|
|
else:
|
|
return self.alipay_client.create_app_order(
|
|
out_trade_no=out_trade_no,
|
|
total_amount=total_amount,
|
|
subject=description,
|
|
)
|
|
|
|
def handle_wechat_notify(
|
|
self, headers: Dict[str, str], body: str
|
|
) -> NotifyResult:
|
|
"""
|
|
处理微信支付异步回调通知
|
|
|
|
Args:
|
|
headers: 请求头
|
|
body: 请求体
|
|
|
|
Returns:
|
|
NotifyResult
|
|
"""
|
|
return self.wechat_client.verify_notify(headers=headers, body=body)
|
|
|
|
def handle_alipay_notify(self, params: Dict[str, str]) -> NotifyResult:
|
|
"""
|
|
处理支付宝异步回调通知
|
|
|
|
Args:
|
|
params: 回调参数
|
|
|
|
Returns:
|
|
NotifyResult
|
|
"""
|
|
return self.alipay_client.verify_notify(params=params)
|
|
|
|
def query_payment(self, method: str, out_trade_no: str) -> PaymentStatus:
|
|
"""
|
|
查询支付订单状态
|
|
|
|
Args:
|
|
method: 支付方式 (wechat / alipay)
|
|
out_trade_no: 商户订单号
|
|
|
|
Returns:
|
|
PaymentStatus
|
|
"""
|
|
self._validate_method(method)
|
|
|
|
if method == PAYMENT_METHOD_WECHAT:
|
|
return self.wechat_client.query_order(out_trade_no=out_trade_no)
|
|
else:
|
|
return self.alipay_client.query_order(out_trade_no=out_trade_no)
|
|
|
|
def close_payment(self, method: str, out_trade_no: str) -> bool:
|
|
"""
|
|
关闭支付订单
|
|
|
|
Args:
|
|
method: 支付方式 (wechat / alipay)
|
|
out_trade_no: 商户订单号
|
|
|
|
Returns:
|
|
是否关闭成功
|
|
"""
|
|
self._validate_method(method)
|
|
|
|
if method == PAYMENT_METHOD_WECHAT:
|
|
return self.wechat_client.close_order(out_trade_no=out_trade_no)
|
|
else:
|
|
return self.alipay_client.close_order(out_trade_no=out_trade_no)
|
|
|
|
def is_method_available(self, method: str) -> bool:
|
|
"""检查指定支付方式是否可用"""
|
|
if method == PAYMENT_METHOD_WECHAT:
|
|
return self._config.wechat.is_configured
|
|
elif method == PAYMENT_METHOD_ALIPAY:
|
|
if getattr(self._config, "alipay_under_development", True):
|
|
return False
|
|
return self._config.alipay.is_configured
|
|
return False
|
|
|
|
@staticmethod
|
|
def _validate_method(method: str):
|
|
"""验证支付方式"""
|
|
if method not in SUPPORTED_METHODS:
|
|
raise PaymentError(
|
|
f"不支持的支付方式: {method},支持的方式: {', '.join(SUPPORTED_METHODS)}",
|
|
code="UNSUPPORTED_METHOD",
|
|
)
|