Automated Action b78ac1f072 Create comprehensive gym membership management system
Features:
- User registration and authentication with JWT tokens
- Multi-level admin access (Admin and Super Admin)
- Gym management with membership plans
- Subscription management with payment integration
- Stripe and Paystack payment gateway support
- Role-based access control
- SQLite database with Alembic migrations
- Comprehensive API endpoints with FastAPI
- Database models for users, gyms, memberships, subscriptions, and transactions
- Admin endpoints for user management and financial reporting
- Health check and documentation endpoints

Core Components:
- FastAPI application with CORS support
- SQLAlchemy ORM with relationship mapping
- JWT-based authentication with bcrypt password hashing
- Payment service abstraction for multiple gateways
- Pydantic schemas for request/response validation
- Alembic database migration system
- Admin dashboard functionality
- Environment variable configuration
2025-06-20 09:08:21 +00:00

154 lines
5.5 KiB
Python

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()