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

@@ -292,7 +292,7 @@ class TenantServiceClient(BaseServiceClient):
count=len(result) if isinstance(result, list) else 0)
return result if result else []
except Exception as e:
logger.error("Error getting active tenants", error=str(e))
logger.error(f"Error getting active tenants: {str(e)}")
return []
# ================================================================
@@ -417,72 +417,55 @@ class TenantServiceClient(BaseServiceClient):
result = await self.get("../health") # Health endpoint is not tenant-scoped
return result is not None
except Exception as e:
logger.error("Tenant service health check failed", error=str(e))
logger.error(f"Tenant service health check failed: {str(e)}")
return False
async def get_subscription_status(self, tenant_id: str) -> Optional[Dict[str, Any]]:
"""
Get subscription status for a tenant
Args:
tenant_id: Tenant ID
Returns:
Dictionary with subscription status information
"""
try:
result = await self.get(f"tenants/{tenant_id}/subscription/status")
if result:
logger.info("Retrieved subscription status from tenant service",
tenant_id=tenant_id, status=result.get('status'))
return result
except Exception as e:
logger.error("Error getting subscription status",
error=str(e), tenant_id=tenant_id)
return None
async def get_subscription_details(self, tenant_id: str) -> Optional[Dict[str, Any]]:
"""
Get detailed subscription information for a tenant
Args:
tenant_id: Tenant ID
Returns:
Dictionary with subscription details
"""
try:
result = await self.get(f"tenants/{tenant_id}/subscription")
if result:
logger.info("Retrieved subscription details from tenant service",
tenant_id=tenant_id, plan=result.get('plan'))
return result
except Exception as e:
logger.error("Error getting subscription details",
error=str(e), tenant_id=tenant_id)
return None
# ================================================================
# PAYMENT CUSTOMER MANAGEMENT
# ================================================================
async def create_payment_customer(
self,
user_data: Dict[str, Any],
payment_method_id: Optional[str] = None
) -> Optional[Dict[str, Any]]:
"""
Create a payment customer for a user
This method creates a payment customer record in the tenant service
during user registration or onboarding. It handles the integration
with payment providers and returns the payment customer details.
Args:
user_data: User data including:
- user_id: User ID (required)
- email: User email (required)
- full_name: User full name (required)
- name: User name (optional, defaults to full_name)
payment_method_id: Optional payment method ID to attach to the customer
Returns:
Dict with payment customer details including:
- success: boolean
- payment_customer_id: string
- payment_method: dict with payment method details
- customer: dict with customer details
Returns None if creation fails
"""
try:
logger.info("Creating payment customer via tenant service",
user_id=user_data.get('user_id'),
email=user_data.get('email'))
# Prepare data for tenant service
tenant_data = {
"user_data": user_data,
"payment_method_id": payment_method_id
}
# Call tenant service endpoint
result = await self.post("/payment-customers/create", tenant_data)
if result and result.get("success"):
logger.info("Payment customer created successfully via tenant service",
user_id=user_data.get('user_id'),
payment_customer_id=result.get('payment_customer_id'))
return result
else:
logger.error("Payment customer creation failed via tenant service",
user_id=user_data.get('user_id'),
error=result.get('detail') if result else 'No detail provided')
return None
except Exception as e:
logger.error("Failed to create payment customer via tenant service",
user_id=user_data.get('user_id'),
error=str(e))
return None
async def create_subscription_for_registration(
self,
user_data: Dict[str, Any],
@@ -537,7 +520,7 @@ class TenantServiceClient(BaseServiceClient):
}
# Call tenant service endpoint
result = await self.post("/subscriptions/create-for-registration", subscription_data)
result = await self.post("tenants/subscriptions/create-for-registration", subscription_data)
if result and result.get("success"):
data = result.get("data", {})
@@ -598,7 +581,7 @@ class TenantServiceClient(BaseServiceClient):
# Call tenant service endpoint
result = await self.post(
f"/tenants/{tenant_id}/link-subscription",
f"tenants/{tenant_id}/link-subscription",
linking_data
)
@@ -648,7 +631,7 @@ class TenantServiceClient(BaseServiceClient):
# Call tenant service endpoint
result = await self.post(
"/payment-customers/create",
"tenants/payment-customers/create",
{
"user_data": user_data,
"payment_method_id": payment_method_id
@@ -696,7 +679,7 @@ class TenantServiceClient(BaseServiceClient):
# Call tenant service orchestration endpoint
result = await self.post(
"/payment-customers/create",
"registration-payment-setup",
user_data
)
@@ -740,7 +723,7 @@ class TenantServiceClient(BaseServiceClient):
# Call tenant service orchestration endpoint
result = await self.get(
f"/setup-intents/{setup_intent_id}/verify"
f"setup-intents/{setup_intent_id}/verify"
)
if result:
@@ -779,7 +762,7 @@ class TenantServiceClient(BaseServiceClient):
# Call tenant service endpoint
result = await self.get(
f"/setup-intents/{setup_intent_id}/verify"
f"tenants/setup-intents/{setup_intent_id}/verify"
)
if result:
@@ -799,6 +782,67 @@ class TenantServiceClient(BaseServiceClient):
error=str(e))
raise
async def verify_and_complete_registration(
self,
setup_intent_id: str,
user_data: Dict[str, Any]
) -> Dict[str, Any]:
"""
Verify SetupIntent and complete registration via tenant service orchestration
This method calls the tenant service's orchestration endpoint to verify
SetupIntent status and complete the registration process by creating
the user record after successful payment verification.
Args:
setup_intent_id: SetupIntent ID to verify
user_data: User data for registration (email, full_name, etc.)
Returns:
Dictionary with registration completion result including user details
and subscription information
Raises:
Exception: If verification or registration completion fails
"""
try:
logger.info("Verifying SetupIntent and completing registration via tenant service orchestration",
setup_intent_id=setup_intent_id,
email=user_data.get('email'))
# Prepare data for tenant service orchestration
registration_data = {
"setup_intent_id": setup_intent_id,
"user_data": user_data
}
# Call tenant service orchestration endpoint
result = await self.post(
"verify-and-complete-registration",
registration_data
)
if result and result.get("success"):
logger.info("Registration completed successfully via tenant service orchestration",
setup_intent_id=setup_intent_id,
user_id=result.get('user_id'),
email=user_data.get('email'))
return result
else:
logger.error("Registration completion failed via tenant service orchestration",
setup_intent_id=setup_intent_id,
email=user_data.get('email'),
error=result.get('detail') if result else 'No detail provided')
raise Exception("Registration completion failed: " +
(result.get('detail') if result else 'Unknown error'))
except Exception as e:
logger.error("Failed to complete registration via tenant service orchestration",
setup_intent_id=setup_intent_id,
email=user_data.get('email'),
error=str(e))
raise
# Factory function for dependency injection
def create_tenant_client(config: BaseServiceSettings) -> TenantServiceClient: