import logging import stripe from typing import Optional, Dict, Any from app.config import settings from app.services.payment_gateway import PaymentGateway logger = logging.getLogger(__name__) class StripePaymentService(PaymentGateway): name = "stripe" supported_types = ["card", "alipay", "wechat"] def __init__(self): self.secret_key = settings.STRIPE_SECRET_KEY self.webhook_secret = settings.STRIPE_WEBHOOK_SECRET if self.secret_key: stripe.api_key = self.secret_key async def create_order(self, order_no: str, amount: int, description: str, **kwargs) -> Dict[str, Any]: if not self.secret_key: raise ValueError("Stripe 未配置") pay_type = kwargs.get("pay_type", "card") success_url = kwargs.get("success_url", "") cancel_url = kwargs.get("cancel_url", "") payment_method_types = ["card"] if pay_type == "alipay": payment_method_types = ["alipay"] elif pay_type == "wechat": payment_method_types = ["wechat_pay"] session = stripe.checkout.Session.create( payment_method_types=payment_method_types, line_items=[{ "price_data": { "currency": "usd", "product_data": {"name": description}, "unit_amount": amount, }, "quantity": 1, }], mode="payment", success_url=success_url or "https://trade.yuzhiran.com/workspace/credits?stripe=success", cancel_url=cancel_url or "https://trade.yuzhiran.com/workspace/credits?stripe=cancel", metadata={"order_no": order_no}, ) return { "gateway_order_id": session.id, "merchant_order_id": order_no, "session_url": session.url, "session_id": session.id, "amount": amount / 100, "status": "pending", } async def query_order(self, order_no: str) -> Dict[str, Any]: try: session = stripe.checkout.Session.retrieve(order_no) return { "status": session.status, "payment_status": session.payment_status, "amount": session.amount_total / 100 if session.amount_total else 0, "currency": session.currency or "usd", "customer_email": session.customer_details.email if session.customer_details else None, } except stripe.error.StripeError as e: logger.error(f"Stripe query failed: {e}") return {"status": "unknown"} async def refund(self, order_no: str, amount: int, reason: str = "") -> Dict[str, Any]: try: payment_intents = stripe.checkout.Session.list( payment_intent=True ) refund = stripe.Refund.create( payment_intent=order_no, amount=amount, reason="requested_by_customer", ) return {"status": refund.status, "refund_id": refund.id} except stripe.error.StripeError as e: logger.error(f"Stripe refund failed: {e}") raise ValueError(f"退款失败: {e}") async def query_refund(self, order_no: str) -> Dict[str, Any]: return {"status": "not_implemented"} def verify_callback(self, headers: dict, body: str) -> bool: if not self.webhook_secret: logger.warning("Stripe webhook secret not configured") return False try: sig_header = headers.get("stripe-signature", "") stripe.Webhook.construct_event(body, sig_header, self.webhook_secret) return True except stripe.error.SignatureVerificationError as e: logger.warning(f"Stripe webhook signature invalid: {e}") return False def parse_callback(self, body: str, headers: dict) -> Dict[str, Any]: event = stripe.Webhook.construct_event(body, headers.get("stripe-signature", ""), self.webhook_secret) session = event.data.object return { "event": event.type, "order_no": session.get("metadata", {}).get("order_no", ""), "gateway_order_id": session.get("id", ""), "gateway_order_no": session.get("payment_intent", ""), "amount": (session.get("amount_total", 0) or 0) / 100, "success": event.type == "checkout.session.completed", "raw": session, } async def close_order(self, order_no: str) -> Dict[str, Any]: try: stripe.checkout.Session.expire(order_no) return {"status": "expired"} except stripe.error.StripeError as e: logger.error(f"Stripe close order failed: {e}") raise ValueError(f"关闭订单失败: {e}")