Add subcription feature 8

This commit is contained in:
Urtzi Alfaro
2026-01-16 16:09:32 +01:00
parent 5e01b34cc0
commit fa7b62bd6c
2 changed files with 115 additions and 47 deletions

View File

@@ -39,20 +39,30 @@ async def start_registration(
"""
Start secure registration flow with SetupIntent-first approach
This is the FIRST step in the new registration architecture:
1. Creates payment customer
2. Attaches payment method
3. Creates SetupIntent for verification
4. Returns SetupIntent to frontend for 3DS handling
This is the FIRST step in the atomic registration architecture:
1. Creates Stripe customer via tenant service
2. Creates SetupIntent with confirm=True
3. Returns SetupIntent data to frontend
If 3DS is required, frontend must confirm SetupIntent and call complete-registration
If no 3DS required, user is created immediately and registration completes
IMPORTANT: NO subscription or user is created in this step!
Two possible outcomes:
- requires_action=True: 3DS required, frontend must confirm SetupIntent then call complete-registration
- requires_action=False: No 3DS required, but frontend STILL must call complete-registration
In BOTH cases, the frontend must call complete-registration to create the subscription and user.
This ensures consistent flow and prevents duplicate subscriptions.
Args:
user_data: User registration data with payment info
Returns:
Registration result (may require 3DS)
SetupIntent result with:
- 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)
- customer_id: Stripe customer ID
- Other SetupIntent metadata
Raises:
HTTPException: 400 for validation errors, 500 for server errors
@@ -124,6 +134,7 @@ async def start_registration(
return {
"requires_action": False,
"setup_intent_id": result.get('setup_intent_id'),
"user": user_data_response,
"subscription_id": result.get('subscription_id'),
"payment_customer_id": result.get('payment_customer_id'),
@@ -156,31 +167,45 @@ async def start_registration(
@router.post("/complete-registration",
response_model=Dict[str, Any],
summary="Complete registration after 3DS verification")
summary="Complete registration after SetupIntent verification")
async def complete_registration(
verification_data: Dict[str, Any],
request: Request,
auth_service: AuthService = Depends(get_auth_service)
) -> Dict[str, Any]:
"""
Complete registration after frontend confirms SetupIntent (3DS handled)
Complete registration after frontend confirms SetupIntent
This is the SECOND step in the registration architecture:
1. Called after frontend confirms SetupIntent
2. Called after user completes 3DS authentication (if required)
3. Verifies SetupIntent status
4. Creates subscription with verified payment method
5. Creates user record
6. Saves onboarding progress
This is the SECOND step in the atomic registration architecture:
1. Called after frontend confirms SetupIntent (with or without 3DS)
2. Verifies SetupIntent status with Stripe
3. Creates subscription with verified payment method (FIRST time subscription is created)
4. Creates user record in auth database
5. Saves onboarding progress
6. Generates auth tokens for auto-login
This endpoint is called in TWO scenarios:
1. After user completes 3DS authentication (requires_action=True flow)
2. Immediately after start-registration (requires_action=False flow)
In BOTH cases, this is where the subscription and user are actually created.
This ensures consistent flow and prevents duplicate subscriptions.
Args:
verification_data: SetupIntent verification data
verification_data: Must contain:
- setup_intent_id: Verified SetupIntent ID
- user_data: Original user registration data
Returns:
Complete registration result
Complete registration result with:
- user: Created user data
- subscription_id: Created subscription ID
- payment_customer_id: Stripe customer ID
- access_token: JWT access token
- refresh_token: JWT refresh token
Raises:
HTTPException: 400 for validation errors, 500 for server errors
HTTPException: 400 if setup_intent_id is missing, 500 for server errors
"""
try:
# Validate required fields