Add subcription feature 3

This commit is contained in:
Urtzi Alfaro
2026-01-15 20:45:49 +01:00
parent a4c3b7da3f
commit b674708a4c
83 changed files with 9451 additions and 6828 deletions

View File

@@ -82,15 +82,29 @@ class SubscriptionRepository(TenantBaseRepository):
else:
subscription_data["next_billing_date"] = datetime.utcnow() + timedelta(days=30)
# Check if subscription with this subscription_id already exists to prevent duplicates
if subscription_data.get('subscription_id'):
existing_subscription = await self.get_by_provider_id(subscription_data['subscription_id'])
if existing_subscription:
# Update the existing subscription instead of creating a duplicate
updated_subscription = await self.update(str(existing_subscription.id), subscription_data)
logger.info("Existing subscription updated",
subscription_id=subscription_data['subscription_id'],
tenant_id=subscription_data.get('tenant_id'),
plan=subscription_data.get('plan'))
return updated_subscription
# Create subscription
subscription = await self.create(subscription_data)
logger.info("Subscription created successfully",
subscription_id=subscription.id,
tenant_id=subscription.tenant_id,
plan=subscription.plan,
monthly_price=subscription.monthly_price)
return subscription
except (ValidationError, DuplicateRecordError):
@@ -514,7 +528,8 @@ class SubscriptionRepository(TenantBaseRepository):
"""Create a subscription not linked to any tenant (for registration flow)"""
try:
# Validate required data for tenant-independent subscription
required_fields = ["user_id", "plan", "subscription_id", "customer_id"]
# user_id may not exist during registration, so validate other required fields
required_fields = ["plan", "subscription_id", "customer_id"]
validation_result = self._validate_tenant_data(subscription_data, required_fields)
if not validation_result["is_valid"]:
@@ -567,16 +582,41 @@ class SubscriptionRepository(TenantBaseRepository):
else:
subscription_data["next_billing_date"] = datetime.utcnow() + timedelta(days=30)
# Create tenant-independent subscription
subscription = await self.create(subscription_data)
logger.info("Tenant-independent subscription created successfully",
subscription_id=subscription.id,
user_id=subscription.user_id,
plan=subscription.plan,
monthly_price=subscription.monthly_price)
return subscription
# Check if subscription with this subscription_id already exists
existing_subscription = await self.get_by_provider_id(subscription_data['subscription_id'])
if existing_subscription:
# Update the existing subscription instead of creating a duplicate
updated_subscription = await self.update(str(existing_subscription.id), subscription_data)
logger.info("Existing tenant-independent subscription updated",
subscription_id=subscription_data['subscription_id'],
user_id=subscription_data.get('user_id'),
plan=subscription_data.get('plan'))
return updated_subscription
else:
# Create new subscription, but handle potential duplicate errors
try:
subscription = await self.create(subscription_data)
logger.info("Tenant-independent subscription created successfully",
subscription_id=subscription.id,
user_id=subscription.user_id,
plan=subscription.plan,
monthly_price=subscription.monthly_price)
return subscription
except DuplicateRecordError:
# Another process may have created the subscription between our check and create
# Try to get the existing subscription and return it
final_subscription = await self.get_by_provider_id(subscription_data['subscription_id'])
if final_subscription:
logger.info("Race condition detected: subscription already created by another process",
subscription_id=subscription_data['subscription_id'])
return final_subscription
else:
# This shouldn't happen, but re-raise the error if we can't find it
raise
except (ValidationError, DuplicateRecordError):
raise
@@ -700,3 +740,29 @@ class SubscriptionRepository(TenantBaseRepository):
logger.error("Failed to cleanup orphaned subscriptions",
error=str(e))
raise DatabaseError(f"Cleanup failed: {str(e)}")
async def get_by_customer_id(self, customer_id: str) -> List[Subscription]:
"""
Get subscriptions by Stripe customer ID
Args:
customer_id: Stripe customer ID
Returns:
List of Subscription objects
"""
try:
query = select(Subscription).where(Subscription.customer_id == customer_id)
result = await self.session.execute(query)
subscriptions = result.scalars().all()
logger.debug("Found subscriptions by customer_id",
customer_id=customer_id,
count=len(subscriptions))
return subscriptions
except Exception as e:
logger.error("Error getting subscriptions by customer_id",
customer_id=customer_id,
error=str(e))
raise DatabaseError(f"Failed to get subscriptions by customer_id: {str(e)}")