Add subcription feature 4
This commit is contained in:
@@ -129,13 +129,15 @@ class AuthService:
|
||||
payment_setup_result: Optional[Dict[str, Any]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Complete registration after successful payment verification
|
||||
This is called AFTER frontend confirms SetupIntent and handles 3DS
|
||||
Complete registration after successful payment verification.
|
||||
|
||||
NEW ARCHITECTURE: This calls tenant service to create subscription
|
||||
AFTER SetupIntent verification. No subscription exists until this point.
|
||||
|
||||
Args:
|
||||
setup_intent_id: Verified SetupIntent ID (may be None if no 3DS was required)
|
||||
setup_intent_id: Verified SetupIntent ID
|
||||
user_data: User registration data
|
||||
payment_setup_result: Optional payment setup result with subscription info
|
||||
payment_setup_result: Optional payment setup result with customer_id etc.
|
||||
|
||||
Returns:
|
||||
Complete registration result
|
||||
@@ -144,26 +146,37 @@ class AuthService:
|
||||
RegistrationError: If registration completion fails
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Completing registration after payment verification, email={user_data.email}, setup_intent_id={setup_intent_id}")
|
||||
logger.info(f"Completing registration after verification, email={user_data.email}, setup_intent_id={setup_intent_id}")
|
||||
|
||||
# If we already have subscription info from payment_setup_result, use it
|
||||
# This happens when no 3DS was required and subscription was created immediately
|
||||
if payment_setup_result and payment_setup_result.get('subscription_id'):
|
||||
subscription_result = payment_setup_result
|
||||
elif setup_intent_id:
|
||||
# Step 1: Verify SetupIntent and create subscription via tenant service
|
||||
subscription_result = await self.tenant_client.verify_and_complete_registration(
|
||||
setup_intent_id,
|
||||
{
|
||||
"email": user_data.email,
|
||||
"full_name": user_data.full_name,
|
||||
"plan_id": user_data.subscription_plan or "professional",
|
||||
"billing_cycle": user_data.billing_cycle or "monthly",
|
||||
"coupon_code": user_data.coupon_code
|
||||
}
|
||||
)
|
||||
else:
|
||||
raise RegistrationError("No setup_intent_id or subscription_id available for registration completion")
|
||||
if not setup_intent_id:
|
||||
raise RegistrationError("SetupIntent ID is required for registration completion")
|
||||
|
||||
# Get customer_id and other data from payment_setup_result
|
||||
customer_id = ""
|
||||
payment_method_id = ""
|
||||
trial_period_days = 0
|
||||
|
||||
if payment_setup_result:
|
||||
customer_id = payment_setup_result.get('customer_id') or payment_setup_result.get('payment_customer_id', '')
|
||||
payment_method_id = payment_setup_result.get('payment_method_id', '')
|
||||
trial_period_days = payment_setup_result.get('trial_period_days', 0)
|
||||
|
||||
# Call tenant service to verify SetupIntent and CREATE subscription
|
||||
subscription_result = await self.tenant_client.verify_and_complete_registration(
|
||||
setup_intent_id,
|
||||
{
|
||||
"email": user_data.email,
|
||||
"full_name": user_data.full_name,
|
||||
"plan_id": user_data.subscription_plan or "professional",
|
||||
"subscription_plan": user_data.subscription_plan or "professional",
|
||||
"billing_cycle": user_data.billing_cycle or "monthly",
|
||||
"billing_interval": user_data.billing_cycle or "monthly",
|
||||
"coupon_code": user_data.coupon_code,
|
||||
"customer_id": customer_id,
|
||||
"payment_method_id": payment_method_id or user_data.payment_method_id,
|
||||
"trial_period_days": trial_period_days
|
||||
}
|
||||
)
|
||||
|
||||
# Use a single database session for both user creation and onboarding progress
|
||||
# to ensure proper transaction handling and avoid foreign key constraint violations
|
||||
@@ -256,37 +269,35 @@ class AuthService:
|
||||
|
||||
# Check if SetupIntent requires action (3DS)
|
||||
if payment_setup_result.get('requires_action', False):
|
||||
logger.info(f"Registration requires SetupIntent confirmation (3DS), email={user_data.email}, setup_intent_id={payment_setup_result.get('setup_intent_id')}, subscription_id={payment_setup_result.get('subscription_id')}")
|
||||
logger.info(f"Registration requires SetupIntent confirmation (3DS), email={user_data.email}, setup_intent_id={payment_setup_result.get('setup_intent_id')}")
|
||||
|
||||
# Return SetupIntent for frontend to handle 3DS
|
||||
# Note: subscription_id is included because for trial subscriptions,
|
||||
# the subscription is already created in 'trialing' status
|
||||
# Note: NO subscription exists yet - subscription is created after verification
|
||||
return {
|
||||
'requires_action': True,
|
||||
'action_type': 'setup_intent_confirmation',
|
||||
'client_secret': payment_setup_result.get('client_secret'),
|
||||
'setup_intent_id': payment_setup_result.get('setup_intent_id'),
|
||||
'subscription_id': payment_setup_result.get('subscription_id'),
|
||||
'customer_id': payment_setup_result.get('customer_id'),
|
||||
'payment_customer_id': payment_setup_result.get('payment_customer_id'),
|
||||
'plan_id': payment_setup_result.get('plan_id'),
|
||||
'payment_method_id': payment_setup_result.get('payment_method_id'),
|
||||
'billing_cycle': payment_setup_result.get('billing_cycle'),
|
||||
'coupon_info': payment_setup_result.get('coupon_info'),
|
||||
'trial_info': payment_setup_result.get('trial_info'),
|
||||
'trial_period_days': payment_setup_result.get('trial_period_days', 0),
|
||||
'coupon_code': payment_setup_result.get('coupon_code'),
|
||||
'email': payment_setup_result.get('email'),
|
||||
'message': 'Payment verification required. Frontend must confirm SetupIntent to handle 3DS.'
|
||||
'message': 'Payment verification required. Frontend must confirm SetupIntent.'
|
||||
}
|
||||
else:
|
||||
logger.info(f"Registration payment setup completed without 3DS, email={user_data.email}, customer_id={payment_setup_result.get('customer_id')}")
|
||||
# No 3DS required - SetupIntent already succeeded
|
||||
logger.info(f"Registration SetupIntent succeeded without 3DS, email={user_data.email}, setup_intent_id={payment_setup_result.get('setup_intent_id')}")
|
||||
|
||||
# No 3DS required - proceed with user creation and subscription
|
||||
# setup_intent_id may be None if no 3DS was required - use subscription_id instead
|
||||
# Complete registration - create subscription now
|
||||
setup_intent_id = payment_setup_result.get('setup_intent_id')
|
||||
registration_result = await self.complete_registration_after_payment_verification(
|
||||
setup_intent_id,
|
||||
user_data,
|
||||
payment_setup_result # Pass full result for additional context
|
||||
payment_setup_result
|
||||
)
|
||||
|
||||
return {
|
||||
@@ -295,8 +306,8 @@ class AuthService:
|
||||
'subscription_id': registration_result.get('subscription_id'),
|
||||
'payment_customer_id': registration_result.get('payment_customer_id'),
|
||||
'status': registration_result.get('status'),
|
||||
'coupon_info': registration_result.get('coupon_info'),
|
||||
'trial_info': registration_result.get('trial_info'),
|
||||
'access_token': registration_result.get('access_token'),
|
||||
'refresh_token': registration_result.get('refresh_token'),
|
||||
'message': 'Registration completed successfully'
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user