import stripe import requests from typing import Dict, Any, Optional from fastapi import HTTPException from app.core.config import settings from app.models.transaction import PaymentGateway class StripeService: def __init__(self): if settings.STRIPE_SECRET_KEY: stripe.api_key = settings.STRIPE_SECRET_KEY def create_payment_intent( self, amount: float, currency: str = "usd", metadata: Optional[Dict] = None ) -> Dict[str, Any]: if not settings.STRIPE_SECRET_KEY: raise HTTPException(status_code=500, detail="Stripe not configured") try: intent = stripe.PaymentIntent.create( amount=int(amount * 100), # Stripe expects amount in cents currency=currency.lower(), metadata=metadata or {}, ) return { "client_secret": intent.client_secret, "payment_intent_id": intent.id, "status": intent.status, } except stripe.error.StripeError as e: raise HTTPException(status_code=400, detail=str(e)) def confirm_payment(self, payment_intent_id: str) -> Dict[str, Any]: if not settings.STRIPE_SECRET_KEY: raise HTTPException(status_code=500, detail="Stripe not configured") try: intent = stripe.PaymentIntent.retrieve(payment_intent_id) return { "payment_intent_id": intent.id, "status": intent.status, "amount": intent.amount / 100, # Convert back from cents "currency": intent.currency, } except stripe.error.StripeError as e: raise HTTPException(status_code=400, detail=str(e)) class PaystackService: def __init__(self): self.base_url = "https://api.paystack.co" self.headers = { "Authorization": f"Bearer {settings.PAYSTACK_SECRET_KEY}", "Content-Type": "application/json", } def initialize_transaction( self, email: str, amount: float, currency: str = "NGN", metadata: Optional[Dict] = None, ) -> Dict[str, Any]: if not settings.PAYSTACK_SECRET_KEY: raise HTTPException(status_code=500, detail="Paystack not configured") data = { "email": email, "amount": int(amount * 100), # Paystack expects amount in kobo "currency": currency.upper(), "metadata": metadata or {}, } try: response = requests.post( f"{self.base_url}/transaction/initialize", json=data, headers=self.headers, ) response.raise_for_status() result = response.json() if result["status"]: return { "authorization_url": result["data"]["authorization_url"], "access_code": result["data"]["access_code"], "reference": result["data"]["reference"], } else: raise HTTPException(status_code=400, detail=result["message"]) except requests.RequestException as e: raise HTTPException(status_code=500, detail=f"Paystack API error: {str(e)}") def verify_transaction(self, reference: str) -> Dict[str, Any]: if not settings.PAYSTACK_SECRET_KEY: raise HTTPException(status_code=500, detail="Paystack not configured") try: response = requests.get( f"{self.base_url}/transaction/verify/{reference}", headers=self.headers ) response.raise_for_status() result = response.json() if result["status"]: data = result["data"] return { "reference": data["reference"], "status": data["status"], "amount": data["amount"] / 100, # Convert back from kobo "currency": data["currency"], "gateway_response": data["gateway_response"], } else: raise HTTPException(status_code=400, detail=result["message"]) except requests.RequestException as e: raise HTTPException(status_code=500, detail=f"Paystack API error: {str(e)}") class PaymentService: def __init__(self): self.stripe_service = StripeService() self.paystack_service = PaystackService() def initialize_payment( self, gateway: PaymentGateway, amount: float, currency: str, email: str, metadata: Optional[Dict] = None, ) -> Dict[str, Any]: if gateway == PaymentGateway.STRIPE: return self.stripe_service.create_payment_intent(amount, currency, metadata) elif gateway == PaymentGateway.PAYSTACK: return self.paystack_service.initialize_transaction( email, amount, currency, metadata ) else: raise HTTPException(status_code=400, detail="Unsupported payment gateway") def verify_payment(self, gateway: PaymentGateway, reference: str) -> Dict[str, Any]: if gateway == PaymentGateway.STRIPE: return self.stripe_service.confirm_payment(reference) elif gateway == PaymentGateway.PAYSTACK: return self.paystack_service.verify_transaction(reference) else: raise HTTPException(status_code=400, detail="Unsupported payment gateway") payment_service = PaymentService()