Support subcription payments
This commit is contained in:
152
services/tenant/app/services/payment_service.py
Normal file
152
services/tenant/app/services/payment_service.py
Normal file
@@ -0,0 +1,152 @@
|
||||
"""
|
||||
Payment Service for handling subscription payments
|
||||
This service abstracts payment provider interactions and makes the system payment-agnostic
|
||||
"""
|
||||
|
||||
import structlog
|
||||
from typing import Dict, Any, Optional
|
||||
import uuid
|
||||
|
||||
from app.core.config import settings
|
||||
from shared.clients.payment_client import PaymentProvider, PaymentCustomer, Subscription, PaymentMethod
|
||||
from shared.clients.stripe_client import StripeProvider
|
||||
from shared.database.base import create_database_manager
|
||||
from app.repositories.subscription_repository import SubscriptionRepository
|
||||
from app.models.tenants import Subscription as SubscriptionModel
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
class PaymentService:
|
||||
"""Service for handling payment provider interactions"""
|
||||
|
||||
def __init__(self):
|
||||
# Initialize payment provider based on configuration
|
||||
# For now, we'll use Stripe, but this can be swapped for other providers
|
||||
self.payment_provider: PaymentProvider = StripeProvider(
|
||||
api_key=settings.STRIPE_SECRET_KEY,
|
||||
webhook_secret=settings.STRIPE_WEBHOOK_SECRET
|
||||
)
|
||||
|
||||
# Initialize database components
|
||||
self.database_manager = create_database_manager(settings.DATABASE_URL, "tenant-service")
|
||||
self.subscription_repo = SubscriptionRepository(SubscriptionModel, None) # Will be set in methods
|
||||
|
||||
async def create_customer(self, user_data: Dict[str, Any]) -> PaymentCustomer:
|
||||
"""Create a customer in the payment provider system"""
|
||||
try:
|
||||
customer_data = {
|
||||
'email': user_data.get('email'),
|
||||
'name': user_data.get('full_name'),
|
||||
'metadata': {
|
||||
'user_id': user_data.get('user_id'),
|
||||
'tenant_id': user_data.get('tenant_id')
|
||||
}
|
||||
}
|
||||
|
||||
return await self.payment_provider.create_customer(customer_data)
|
||||
except Exception as e:
|
||||
logger.error("Failed to create customer in payment provider", error=str(e))
|
||||
raise e
|
||||
|
||||
async def create_subscription(
|
||||
self,
|
||||
customer_id: str,
|
||||
plan_id: str,
|
||||
payment_method_id: str,
|
||||
trial_period_days: Optional[int] = None
|
||||
) -> Subscription:
|
||||
"""Create a subscription for a customer"""
|
||||
try:
|
||||
return await self.payment_provider.create_subscription(
|
||||
customer_id,
|
||||
plan_id,
|
||||
payment_method_id,
|
||||
trial_period_days
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Failed to create subscription in payment provider", error=str(e))
|
||||
raise e
|
||||
|
||||
async def process_registration_with_subscription(
|
||||
self,
|
||||
user_data: Dict[str, Any],
|
||||
plan_id: str,
|
||||
payment_method_id: str,
|
||||
use_trial: bool = False
|
||||
) -> Dict[str, Any]:
|
||||
"""Process user registration with subscription creation"""
|
||||
try:
|
||||
# Create customer in payment provider
|
||||
customer = await self.create_customer(user_data)
|
||||
|
||||
# Determine trial period
|
||||
trial_period_days = None
|
||||
if use_trial:
|
||||
trial_period_days = 90 # 3 months trial for pilot users
|
||||
|
||||
# Create subscription
|
||||
subscription = await self.create_subscription(
|
||||
customer.id,
|
||||
plan_id,
|
||||
payment_method_id,
|
||||
trial_period_days
|
||||
)
|
||||
|
||||
# Save subscription to database
|
||||
async with self.database_manager.get_session() as session:
|
||||
self.subscription_repo.session = session
|
||||
subscription_record = await self.subscription_repo.create({
|
||||
'id': str(uuid.uuid4()),
|
||||
'tenant_id': user_data.get('tenant_id'),
|
||||
'customer_id': customer.id,
|
||||
'subscription_id': subscription.id,
|
||||
'plan_id': plan_id,
|
||||
'status': subscription.status,
|
||||
'current_period_start': subscription.current_period_start,
|
||||
'current_period_end': subscription.current_period_end,
|
||||
'created_at': subscription.created_at,
|
||||
'trial_period_days': trial_period_days
|
||||
})
|
||||
|
||||
return {
|
||||
'customer_id': customer.id,
|
||||
'subscription_id': subscription.id,
|
||||
'status': subscription.status,
|
||||
'trial_period_days': trial_period_days
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error("Failed to process registration with subscription", error=str(e))
|
||||
raise e
|
||||
|
||||
async def cancel_subscription(self, subscription_id: str) -> Subscription:
|
||||
"""Cancel a subscription in the payment provider"""
|
||||
try:
|
||||
return await self.payment_provider.cancel_subscription(subscription_id)
|
||||
except Exception as e:
|
||||
logger.error("Failed to cancel subscription in payment provider", error=str(e))
|
||||
raise e
|
||||
|
||||
async def update_payment_method(self, customer_id: str, payment_method_id: str) -> PaymentMethod:
|
||||
"""Update the payment method for a customer"""
|
||||
try:
|
||||
return await self.payment_provider.update_payment_method(customer_id, payment_method_id)
|
||||
except Exception as e:
|
||||
logger.error("Failed to update payment method in payment provider", error=str(e))
|
||||
raise e
|
||||
|
||||
async def get_invoices(self, customer_id: str) -> list:
|
||||
"""Get invoices for a customer from the payment provider"""
|
||||
try:
|
||||
return await self.payment_provider.get_invoices(customer_id)
|
||||
except Exception as e:
|
||||
logger.error("Failed to get invoices from payment provider", error=str(e))
|
||||
raise e
|
||||
|
||||
async def get_subscription(self, subscription_id: str) -> Subscription:
|
||||
"""Get subscription details from the payment provider"""
|
||||
try:
|
||||
return await self.payment_provider.get_subscription(subscription_id)
|
||||
except Exception as e:
|
||||
logger.error("Failed to get subscription from payment provider", error=str(e))
|
||||
raise e
|
||||
Reference in New Issue
Block a user