Add subcription feature 8
This commit is contained in:
@@ -130,20 +130,37 @@ class AuthService:
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Complete registration after successful payment verification.
|
||||
|
||||
NEW ARCHITECTURE: This calls tenant service to create subscription
|
||||
AFTER SetupIntent verification. No subscription exists until this point.
|
||||
|
||||
This is the CORE method that creates the subscription and user.
|
||||
It is called by complete_registration_with_verified_payment in both scenarios:
|
||||
1. After 3DS authentication (requires_action=True flow)
|
||||
2. Immediately after start-registration (requires_action=False flow)
|
||||
|
||||
CRITICAL: This is the FIRST and ONLY place where:
|
||||
- Subscription is created via tenant service
|
||||
- User record is created in auth database
|
||||
- Onboarding progress is saved
|
||||
- Auth tokens are generated
|
||||
|
||||
This ensures that subscriptions are only created after SetupIntent verification,
|
||||
preventing duplicate subscriptions and maintaining payment security.
|
||||
|
||||
Args:
|
||||
setup_intent_id: Verified SetupIntent ID
|
||||
setup_intent_id: Verified SetupIntent ID (must not be None)
|
||||
user_data: User registration data
|
||||
payment_setup_result: Optional payment setup result with customer_id etc.
|
||||
|
||||
Returns:
|
||||
Complete registration result
|
||||
Complete registration result with:
|
||||
- user: Created user data
|
||||
- subscription_id: Created subscription ID
|
||||
- payment_customer_id: Stripe customer ID
|
||||
- status: Subscription status
|
||||
- access_token: JWT access token
|
||||
- refresh_token: JWT refresh token
|
||||
|
||||
Raises:
|
||||
RegistrationError: If registration completion fails
|
||||
RegistrationError: If registration completion fails (e.g., missing setup_intent_id)
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Completing registration after verification, email={user_data.email}, setup_intent_id={setup_intent_id}")
|
||||
@@ -250,13 +267,28 @@ class AuthService:
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Start secure registration flow with SetupIntent-first approach
|
||||
Main entry point for new registration architecture
|
||||
|
||||
This is the FIRST step in the atomic registration flow:
|
||||
1. Creates Stripe customer
|
||||
2. Creates SetupIntent with confirm=True
|
||||
3. Returns SetupIntent data to frontend
|
||||
|
||||
IMPORTANT: NO subscription is created in this step!
|
||||
Subscription creation happens in complete_registration_after_payment_verification
|
||||
|
||||
Two possible outcomes:
|
||||
- requires_action=True: 3DS required, frontend must confirm SetupIntent
|
||||
- requires_action=False: No 3DS required, but frontend STILL must call complete-registration
|
||||
|
||||
Args:
|
||||
user_data: User registration data
|
||||
|
||||
Returns:
|
||||
Registration flow result (may require 3DS)
|
||||
Registration flow result with SetupIntent data
|
||||
- requires_action: True if 3DS required, False if not
|
||||
- setup_intent_id: SetupIntent ID for verification
|
||||
- client_secret: For 3DS authentication (when requires_action=True)
|
||||
- Other SetupIntent metadata
|
||||
|
||||
Raises:
|
||||
RegistrationError: If registration flow fails
|
||||
@@ -292,23 +324,20 @@ class AuthService:
|
||||
# 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')}")
|
||||
|
||||
# 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
|
||||
)
|
||||
|
||||
# Note: NO subscription created yet - frontend must call complete-registration
|
||||
# This ensures consistent flow whether 3DS is required or not
|
||||
return {
|
||||
'requires_action': False,
|
||||
'user': registration_result.get('user'),
|
||||
'subscription_id': registration_result.get('subscription_id'),
|
||||
'payment_customer_id': registration_result.get('payment_customer_id'),
|
||||
'status': registration_result.get('status'),
|
||||
'access_token': registration_result.get('access_token'),
|
||||
'refresh_token': registration_result.get('refresh_token'),
|
||||
'message': 'Registration completed successfully'
|
||||
'setup_intent_id': payment_setup_result.get('setup_intent_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'),
|
||||
'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': 'SetupIntent succeeded without 3DS. Frontend must call complete-registration to create subscription.'
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
@@ -321,15 +350,29 @@ class AuthService:
|
||||
user_data: UserRegistration
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Complete registration after frontend confirms SetupIntent (3DS handled)
|
||||
This is called by frontend after user completes 3DS authentication
|
||||
Complete registration after frontend confirms SetupIntent
|
||||
|
||||
This is the SECOND step in the atomic registration flow and is called in TWO scenarios:
|
||||
1. After user completes 3DS authentication (when requires_action=True)
|
||||
2. Immediately after start-registration (when requires_action=False)
|
||||
|
||||
In BOTH cases, this method:
|
||||
- Verifies the SetupIntent status with Stripe
|
||||
- Calls tenant service to create the subscription (first time subscription is created)
|
||||
- Creates the user record in auth database
|
||||
- Saves onboarding progress
|
||||
- Generates auth tokens for auto-login
|
||||
|
||||
This ensures a CONSISTENT flow whether 3DS is required or not:
|
||||
Step 1: start-registration creates SetupIntent only (NO subscription yet)
|
||||
Step 2: complete-registration verifies SetupIntent and creates subscription
|
||||
|
||||
Args:
|
||||
setup_intent_id: SetupIntent ID that was confirmed
|
||||
setup_intent_id: SetupIntent ID that was confirmed (either by Stripe or frontend)
|
||||
user_data: User registration data
|
||||
|
||||
Returns:
|
||||
Complete registration result
|
||||
Complete registration result with user data, tokens, and subscription info
|
||||
|
||||
Raises:
|
||||
RegistrationError: If completion fails
|
||||
|
||||
Reference in New Issue
Block a user