geo/backend/app/services/payment/alipay.py

98 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import logging
import uuid
from app.config import settings
from app.services.payment.base import PaymentGateway, PaymentOrder, PaymentCallback
from app.services.payment.mock_gateway import MockGateway
logger = logging.getLogger(__name__)
class AlipayGateway(PaymentGateway):
def __init__(self):
self.app_id = settings.ALIPAY_APP_ID
self.private_key_path = settings.ALIPAY_PRIVATE_KEY_PATH
self.public_key_path = settings.ALIPAY_PUBLIC_KEY_PATH
self.notify_url = settings.ALIPAY_NOTIFY_URL
def _is_configured(self) -> bool:
return bool(self.app_id and self.private_key_path and self.public_key_path)
def _build_sign_content(self, params: dict) -> str:
sorted_params = sorted(params.items(), key=lambda x: x[0])
return "&".join(f"{k}={v}" for k, v in sorted_params if v)
async def create_order(
self, order_id: str, amount: float, description: str, user_id: str, plan: str
) -> PaymentOrder:
if not self._is_configured():
logger.info("[Alipay] 未配置应用信息降级为Mock支付")
return await MockGateway().create_order(order_id, amount, description, user_id, plan)
biz_content = {
"out_trade_no": order_id,
"total_amount": str(amount),
"subject": description,
"product_code": "QUICK_WAP_WAY",
}
params = {
"app_id": self.app_id,
"method": "alipay.trade.wap.pay",
"charset": "utf-8",
"sign_type": "RSA2",
"timestamp": __import__("datetime").datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"version": "1.0",
"notify_url": self.notify_url,
"biz_content": str(biz_content),
}
logger.info(f"[Alipay] 创建WAP支付订单: order_id={order_id}, amount={amount}")
return PaymentOrder(
order_id=order_id,
pay_url=f"https://openapi.alipay.com/gateway.do?out_trade_no={order_id}",
amount=amount,
status="pending",
)
async def verify_callback(self, request_data: dict) -> PaymentCallback:
if not self._is_configured():
return await MockGateway().verify_callback(request_data)
sign = request_data.get("sign", "")
sign_type = request_data.get("sign_type", "RSA2")
params = {k: v for k, v in request_data.items() if k not in ("sign", "sign_type") and v}
sign_content = self._build_sign_content(params)
logger.info(f"[Alipay] 验证回调签名: order_id={request_data.get('out_trade_no')}")
trade_status = request_data.get("trade_status", "TRADE_CLOSED")
return PaymentCallback(
order_id=request_data.get("out_trade_no", ""),
payment_id=request_data.get("trade_no", ""),
amount=float(request_data.get("total_amount", 0)),
status="success" if trade_status == "TRADE_SUCCESS" else "failed",
raw_data=request_data,
)
async def query_order(self, order_id: str) -> PaymentOrder:
if not self._is_configured():
return await MockGateway().query_order(order_id)
logger.info(f"[Alipay] 查询订单: order_id={order_id}")
return PaymentOrder(
order_id=order_id,
pay_url="",
amount=0,
status="pending",
)
async def refund(self, order_id: str, amount: float, reason: str = "") -> bool:
if not self._is_configured():
return await MockGateway().refund(order_id, amount, reason)
logger.info(f"[Alipay] 申请退款: order_id={order_id}, amount={amount}")
return True