Add subcription feature
This commit is contained in:
@@ -420,6 +420,207 @@ class TenantServiceClient(BaseServiceClient):
|
||||
logger.error("Tenant service health check failed", error=str(e))
|
||||
return False
|
||||
|
||||
# ================================================================
|
||||
# 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],
|
||||
plan_id: str,
|
||||
payment_method_id: str,
|
||||
billing_cycle: str = "monthly",
|
||||
coupon_code: Optional[str] = None
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Create a tenant-independent subscription during user registration
|
||||
|
||||
This method creates a subscription that is not linked to any tenant yet.
|
||||
The subscription will be linked to a tenant during the onboarding flow
|
||||
when the user creates their bakery/tenant.
|
||||
|
||||
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)
|
||||
plan_id: Subscription plan ID (starter, professional, enterprise)
|
||||
payment_method_id: Stripe payment method ID
|
||||
billing_cycle: Billing cycle (monthly or yearly), defaults to monthly
|
||||
coupon_code: Optional coupon code for discounts/trials
|
||||
|
||||
Returns:
|
||||
Dict with subscription creation results including:
|
||||
- success: boolean
|
||||
- subscription_id: string (Stripe subscription ID)
|
||||
- customer_id: string (Stripe customer ID)
|
||||
- status: string (subscription status)
|
||||
- plan: string (plan name)
|
||||
- billing_cycle: string (billing interval)
|
||||
- trial_period_days: int (if trial applied)
|
||||
- coupon_applied: boolean
|
||||
Returns None if creation fails
|
||||
"""
|
||||
try:
|
||||
logger.info("Creating tenant-independent subscription for registration",
|
||||
user_id=user_data.get('user_id'),
|
||||
plan_id=plan_id,
|
||||
billing_cycle=billing_cycle)
|
||||
|
||||
# Prepare data for tenant service
|
||||
subscription_data = {
|
||||
"user_data": user_data,
|
||||
"plan_id": plan_id,
|
||||
"payment_method_id": payment_method_id,
|
||||
"billing_interval": billing_cycle,
|
||||
"coupon_code": coupon_code
|
||||
}
|
||||
|
||||
# Call tenant service endpoint
|
||||
result = await self.post("/subscriptions/create-for-registration", subscription_data)
|
||||
|
||||
if result and result.get("success"):
|
||||
data = result.get("data", {})
|
||||
logger.info("Tenant-independent subscription created successfully",
|
||||
user_id=user_data.get('user_id'),
|
||||
subscription_id=data.get('subscription_id'),
|
||||
plan=data.get('plan'))
|
||||
return data
|
||||
else:
|
||||
logger.error("Subscription 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 subscription for registration via tenant service",
|
||||
user_id=user_data.get('user_id'),
|
||||
plan_id=plan_id,
|
||||
error=str(e))
|
||||
return None
|
||||
|
||||
async def link_subscription_to_tenant(
|
||||
self,
|
||||
tenant_id: str,
|
||||
subscription_id: str,
|
||||
user_id: str
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Link a pending subscription to a tenant
|
||||
|
||||
This completes the registration flow by associating the subscription
|
||||
created during registration with the tenant created during onboarding.
|
||||
|
||||
Args:
|
||||
tenant_id: Tenant ID to link subscription to
|
||||
subscription_id: Subscription ID (from registration)
|
||||
user_id: User ID performing the linking (for validation)
|
||||
|
||||
Returns:
|
||||
Dict with linking results:
|
||||
- success: boolean
|
||||
- tenant_id: string
|
||||
- subscription_id: string
|
||||
- status: string
|
||||
Returns None if linking fails
|
||||
"""
|
||||
try:
|
||||
logger.info("Linking subscription to tenant",
|
||||
tenant_id=tenant_id,
|
||||
subscription_id=subscription_id,
|
||||
user_id=user_id)
|
||||
|
||||
# Prepare data for tenant service
|
||||
linking_data = {
|
||||
"subscription_id": subscription_id,
|
||||
"user_id": user_id
|
||||
}
|
||||
|
||||
# Call tenant service endpoint
|
||||
result = await self.post(
|
||||
f"/tenants/{tenant_id}/link-subscription",
|
||||
linking_data
|
||||
)
|
||||
|
||||
if result and result.get("success"):
|
||||
logger.info("Subscription linked to tenant successfully",
|
||||
tenant_id=tenant_id,
|
||||
subscription_id=subscription_id)
|
||||
return result
|
||||
else:
|
||||
logger.error("Subscription linking failed via tenant service",
|
||||
tenant_id=tenant_id,
|
||||
subscription_id=subscription_id,
|
||||
error=result.get('detail') if result else 'No detail provided')
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Failed to link subscription to tenant via tenant service",
|
||||
tenant_id=tenant_id,
|
||||
subscription_id=subscription_id,
|
||||
error=str(e))
|
||||
return None
|
||||
|
||||
|
||||
# Factory function for dependency injection
|
||||
def create_tenant_client(config: BaseServiceSettings) -> TenantServiceClient:
|
||||
|
||||
Reference in New Issue
Block a user