@ -7,6 +7,7 @@ from api.serializers import GroupStageSerializer, MatchSerializer, PlayerRegistr
from django . contrib . auth . mixins import LoginRequiredMixin
from django . contrib . auth . mixins import LoginRequiredMixin
from django . contrib . auth import logout
from django . contrib . auth import logout
from . utils . extensions import is_not_sqlite_backend
from . utils . extensions import is_not_sqlite_backend
import stripe
from django . contrib . auth import update_session_auth_hash
from django . contrib . auth import update_session_auth_hash
from django . contrib . auth . views import PasswordResetCompleteView
from django . contrib . auth . views import PasswordResetCompleteView
@ -25,7 +26,8 @@ from django.core.files.storage import default_storage
from django . core . files . base import ContentFile
from django . core . files . base import ContentFile
from django . views . generic import View
from django . views . generic import View
from django . db . models import Q
from django . db . models import Q
from . models import Club , Tournament , CustomUser , Event , Round , Match , TeamScore , TeamRegistration , PlayerRegistration , UserOrigin
from . models import Club , Tournament , CustomUser , Event , Round , Match , TeamScore , TeamRegistration , PlayerRegistration , UserOrigin , PlayerPaymentType
from . models . player_registration import RegistrationStatus
from datetime import datetime , timedelta
from datetime import datetime , timedelta
import time
import time
import json
import json
@ -64,6 +66,7 @@ from .utils.apns import send_push_notification
from . utils . licence_validator import LicenseValidator
from . utils . licence_validator import LicenseValidator
from django . views . generic . edit import UpdateView
from django . views . generic . edit import UpdateView
from . forms import CustomPasswordChangeForm
from . forms import CustomPasswordChangeForm
from . services . email_service import TournamentEmailService
def index ( request ) :
def index ( request ) :
now = timezone . now ( )
now = timezone . now ( )
@ -749,20 +752,25 @@ def register_tournament(request, tournament_id):
# Only initialize a fresh cart for GET requests
# Only initialize a fresh cart for GET requests
# For POST requests, use the existing cart to maintain state
# For POST requests, use the existing cart to maintain state
if request . method == ' GET ' :
if request . method == ' GET ' :
# ALWAYS initialize a fresh cart when entering the registration page (GET request)
# Check if we're returning from Stripe (don't reinitialize if we have a checkout session)
# This ensures no old cart data persists
if ' stripe_checkout_session_id ' in request . session :
registration_cart . initialize_registration_cart ( request , tournament_id )
# We're returning from Stripe, don't reinitialize the cart
pass
# Auto-add the authenticated user with license
else :
if request . user . is_authenticated and request . user . licence_id :
# ALWAYS initialize a fresh cart when entering the registration page (GET request)
player_data = {
# This ensures no old cart data persists
' first_name ' : request . user . first_name ,
registration_cart . initialize_registration_cart ( request , tournament_id )
' last_name ' : request . user . last_name ,
' licence_id ' : request . user . licence_id ,
# Auto-add the authenticated user with license
' email ' : request . user . email ,
if request . user . is_authenticated and request . user . licence_id :
' phone ' : request . user . phone
player_data = {
}
' first_name ' : request . user . first_name ,
registration_cart . add_player_to_cart ( request , player_data )
' last_name ' : request . user . last_name ,
' licence_id ' : request . user . licence_id ,
' email ' : request . user . email ,
' phone ' : request . user . phone
}
registration_cart . add_player_to_cart ( request , player_data )
else :
else :
# For POST, ensure tournament ID is correct
# For POST, ensure tournament ID is correct
current_tournament_id = registration_cart . get_tournament_from_cart ( request )
current_tournament_id = registration_cart . get_tournament_from_cart ( request )
@ -790,7 +798,8 @@ def register_tournament(request, tournament_id):
context = {
context = {
' tournament ' : tournament ,
' tournament ' : tournament ,
' current_players ' : cart_data [ ' players ' ] ,
' current_players ' : cart_data [ ' players ' ] ,
' registration_successful ' : False
' registration_successful ' : False ,
' cart_data ' : cart_data # Add this line
}
}
# Initialize forms
# Initialize forms
@ -908,9 +917,8 @@ def register_tournament(request, tournament_id):
# Checkout and create registration
# Checkout and create registration
success , result = registration_cart . checkout_registration_cart ( request )
success , result = registration_cart . checkout_registration_cart ( request )
if success :
if success :
waiting_list_position = tournament . get_waiting_list_position ( )
waiting_list_position = cart_data . get ( ' waiting_list_position ' , - 1 )
if is_not_sqlite_backend ( ) :
if is_not_sqlite_backend ( ) :
from . services . email_service import TournamentEmailService
email_service = TournamentEmailService ( )
email_service = TournamentEmailService ( )
email_service . send_registration_confirmation (
email_service . send_registration_confirmation (
request ,
request ,
@ -929,6 +937,72 @@ def register_tournament(request, tournament_id):
for error in errors :
for error in errors :
messages . error ( request , f " { field } : { error } " )
messages . error ( request , f " { field } : { error } " )
context [ ' team_form ' ] = team_form
context [ ' team_form ' ] = team_form
elif ' proceed_to_payment ' in request . POST :
team_form = TournamentRegistrationForm ( request . POST )
if team_form . is_valid ( ) :
# Update cart with contact info
registration_cart . update_cart_contact_info (
request ,
mobile_number = team_form . cleaned_data . get ( ' mobile_number ' )
)
# Create payment session
try :
stripe . api_key = settings . STRIPE_SECRET_KEY
# Get user email if authenticated
customer_email = request . user . email if request . user . is_authenticated else None
# Create the Stripe checkout session
checkout_session_params = {
' payment_method_types ' : [ ' card ' ] ,
' line_items ' : [ {
' price_data ' : {
' currency ' : ' eur ' ,
' product_data ' : {
' name ' : f ' { tournament . broadcast_display_name ( ) } du { tournament . formatted_start_date ( ) } ' ,
' description ' : f ' Lieu { tournament . event . club . name } ' ,
} ,
' unit_amount ' : int ( team_registration . team_fee ( ) * 100 ) , # Amount in cents
# 'unit_amount': int(tournament.entry_fee * 100), # Amount in cents
} ,
' quantity ' : 2 ,
} ] ,
' mode ' : ' payment ' ,
' success_url ' : request . build_absolute_uri (
reverse ( ' tournament-payment-success ' , kwargs = { ' tournament_id ' : tournament_id } )
) ,
' cancel_url ' : request . build_absolute_uri (
# Use the correct URL name from your urls.py
reverse ( ' register_tournament ' , kwargs = { ' tournament_id ' : tournament_id } )
) ,
' metadata ' : {
' tournament_id ' : tournament_id ,
' registration_cart_id ' : cart_data [ ' cart_id ' ] ,
' user_id ' : request . user . id if request . user . is_authenticated else None ,
}
}
# Add customer_email if available
if customer_email :
checkout_session_params [ ' customer_email ' ] = customer_email
# Create the checkout session
checkout_session = stripe . checkout . Session . create ( * * checkout_session_params )
# Store checkout session ID in session
request . session [ ' stripe_checkout_session_id ' ] = checkout_session . id
request . session . modified = True
# Redirect to Stripe checkout
return redirect ( checkout_session . url )
except Exception as e :
messages . error ( request , f " Erreur lors de la création de la session de paiement: { str ( e ) } " )
else :
for field , errors in team_form . errors . items ( ) :
for error in errors :
messages . error ( request , f " { field } : { error } " )
context [ ' team_form ' ] = team_form
# Debug session content before rendering
# Debug session content before rendering
print ( " ===== SESSION DUMP BEFORE RENDER ===== " )
print ( " ===== SESSION DUMP BEFORE RENDER ===== " )
@ -939,10 +1013,103 @@ def register_tournament(request, tournament_id):
return render ( request , ' register_tournament.html ' , context )
return render ( request , ' register_tournament.html ' , context )
@login_required
def tournament_payment_success ( request , tournament_id ) :
# Get checkout session ID from session
checkout_session_id = request . session . get ( ' stripe_checkout_session_id ' )
if not checkout_session_id :
messages . error ( request , " Session de paiement introuvable. " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
try :
# Verify payment status with Stripe
stripe . api_key = settings . STRIPE_SECRET_KEY
checkout_session = stripe . checkout . Session . retrieve ( checkout_session_id )
if checkout_session . payment_status == ' paid ' :
# Check if this is a direct payment from tournament info page
team_registration_id = request . session . get ( ' team_registration_id ' )
if team_registration_id :
# This is a direct payment for an existing registration
team_registration = get_object_or_404 ( TeamRegistration , id = team_registration_id )
player_registrations = PlayerRegistration . objects . filter ( team_registration = team_registration )
for player_reg in player_registrations :
player_reg . payment_type = PlayerPaymentType . CREDIT_CARD
player_reg . registration_status = RegistrationStatus . CONFIRMED
player_reg . payment_id = checkout_session . payment_intent
player_reg . save ( )
# Mark team as paid
team_registration . set_paid ( True )
# Clear session data
if ' stripe_checkout_session_id ' in request . session :
del request . session [ ' stripe_checkout_session_id ' ]
if ' team_registration_id ' in request . session :
del request . session [ ' team_registration_id ' ]
messages . success ( request , " Paiement réussi et inscription confirmée ! " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
else :
# This is a payment during registration
# Get cart data
cart_data = registration_cart . get_registration_cart_data ( request )
# Checkout and create registration
success , result = registration_cart . checkout_registration_cart ( request )
if success :
# Get the team registration and mark as paid
team_registration = result # result is team_registration object
player_registrations = PlayerRegistration . objects . filter ( team_registration = team_registration )
for player_reg in player_registrations :
player_reg . payment_type = PlayerPaymentType . CREDIT_CARD
player_reg . registration_status = RegistrationStatus . CONFIRMED
player_reg . payment_id = checkout_session . payment_intent
player_reg . save ( )
# Mark team as paid
team_registration . set_paid ( True )
waiting_list_position = cart_data . get ( ' waiting_list_position ' , - 1 )
if is_not_sqlite_backend ( ) :
email_service = TournamentEmailService ( )
email_service . send_registration_confirmation (
request ,
get_object_or_404 ( Tournament , id = tournament_id ) ,
team_registration ,
waiting_list_position
)
# Clear session data
if ' stripe_checkout_session_id ' in request . session :
del request . session [ ' stripe_checkout_session_id ' ]
messages . success ( request , " Paiement réussi et inscription confirmée ! " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
else :
messages . error ( request , f " Paiement réussi mais erreur lors de l ' inscription: { result } " )
else :
messages . error ( request , " Le paiement n ' a pas été complété. " )
except Exception as e :
messages . error ( request , f " Erreur lors de la vérification du paiement: { str ( e ) } " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
@login_required
@login_required
def cancel_registration ( request , tournament_id ) :
def cancel_registration ( request , tournament_id ) :
""" Cancel the current registration process and clear the cart """
""" Cancel the current registration process and clear the cart """
registration_cart . clear_registration_cart ( request )
registration_cart . clear_registration_cart ( request )
try :
tournament = Tournament . objects . get ( id = tournament_id )
tournament . reserved_spots = max ( 0 , tournament . reserved_spots - 1 )
tournament . save ( )
except Tournament . DoesNotExist :
return False , " Tournoi introuvable. "
messages . info ( request , " Processus d ' inscription annulé. " )
messages . info ( request , " Processus d ' inscription annulé. " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
@ -1355,6 +1522,80 @@ def confirm_tournament_registration(request, tournament_id):
return redirect ( ' tournament_info ' , tournament_id = tournament_id )
return redirect ( ' tournament_info ' , tournament_id = tournament_id )
@login_required
def proceed_to_payment ( request , tournament_id ) :
tournament = get_object_or_404 ( Tournament , id = tournament_id )
# First check if the user is registered for this tournament
user_licence_id = request . user . licence_id
if not user_licence_id :
messages . error ( request , " Votre licence n ' est pas associée à votre compte. " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
validator = LicenseValidator ( user_licence_id )
stripped_license = validator . stripped_license
# Find the team registration
team_registration = TeamRegistration . objects . filter (
tournament = tournament ,
player_registrations__licence_id__icontains = stripped_license ,
walk_out = False
) . first ( )
if not team_registration :
messages . error ( request , " Vous n ' êtes pas inscrit à ce tournoi. " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
if team_registration . is_paid ( ) :
messages . info ( request , " Votre paiement a déjà été confirmé. " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
# Create Stripe checkout session
try :
stripe . api_key = settings . STRIPE_SECRET_KEY
# Create checkout session
checkout_session = stripe . checkout . Session . create (
payment_method_types = [ ' card ' ] ,
line_items = [ {
' price_data ' : {
' currency ' : ' eur ' ,
' product_data ' : {
' name ' : f ' { tournament . broadcast_display_name ( ) } du { tournament . formatted_start_date ( ) } ' ,
' description ' : f ' Lieu { tournament . event . club . name } ' ,
} ,
' unit_amount ' : int ( team_registration . team_fee ( ) * 100 ) , # Amount in cents
} ,
' quantity ' : 2 ,
} ] ,
mode = ' payment ' ,
success_url = request . build_absolute_uri (
reverse ( ' tournament-payment-success ' , kwargs = { ' tournament_id ' : tournament_id } )
) ,
cancel_url = request . build_absolute_uri (
reverse ( ' tournament-info ' , kwargs = { ' tournament_id ' : tournament_id } )
) ,
metadata = {
' tournament_id ' : tournament_id ,
' team_registration_id ' : str ( team_registration . id ) ,
' user_id ' : request . user . id ,
} ,
customer_email = request . user . email ,
)
# Store checkout session ID in session
request . session [ ' stripe_checkout_session_id ' ] = checkout_session . id
request . session [ ' team_registration_id ' ] = str ( team_registration . id )
request . session . modified = True
# Redirect to Stripe checkout
return redirect ( checkout_session . url )
except Exception as e :
messages . error ( request , f " Erreur lors de la création de la session de paiement: { str ( e ) } " )
return redirect ( ' tournament-info ' , tournament_id = tournament_id )
class UserListExportView ( LoginRequiredMixin , View ) :
class UserListExportView ( LoginRequiredMixin , View ) :
def get ( self , request , * args , * * kwargs ) :
def get ( self , request , * args , * * kwargs ) :
users = CustomUser . objects . order_by ( ' date_joined ' )
users = CustomUser . objects . order_by ( ' date_joined ' )