From a321c4c154b7293ad701a2a8b5ee9a60fe199c93 Mon Sep 17 00:00:00 2001 From: Raz Date: Wed, 9 Apr 2025 13:39:17 +0200 Subject: [PATCH] fix registration process --- padelclub_backend/settings.py | 1 + tournaments/middleware.py | 38 +- ...erregistration_payment_status_and_more.py} | 9 +- tournaments/models/tournament.py | 25 ++ tournaments/services/registration_cart.py | 346 ++++++++++++++++++ tournaments/signals.py | 4 +- .../templates/register_tournament.html | 8 + tournaments/urls.py | 1 + tournaments/views.py | 231 +++++++++++- 9 files changed, 648 insertions(+), 15 deletions(-) rename tournaments/migrations/{0114_playerregistration_payment_status_and_more.py => 0116_playerregistration_payment_status_and_more.py} (67%) create mode 100644 tournaments/services/registration_cart.py diff --git a/padelclub_backend/settings.py b/padelclub_backend/settings.py index e2ef565..b6c8262 100644 --- a/padelclub_backend/settings.py +++ b/padelclub_backend/settings.py @@ -64,6 +64,7 @@ MIDDLEWARE = [ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'tournaments.middleware.ReferrerMiddleware', # Add this line + 'tournaments.middleware.RegistrationCartCleanupMiddleware', ] diff --git a/tournaments/middleware.py b/tournaments/middleware.py index ad517b2..ad4b5d2 100644 --- a/tournaments/middleware.py +++ b/tournaments/middleware.py @@ -1,5 +1,6 @@ -from django.conf import settings -from django.urls import resolve, reverse +from django.urls import reverse +from django.utils import timezone +import datetime class ReferrerMiddleware: def __init__(self, get_response): @@ -17,3 +18,36 @@ class ReferrerMiddleware: response = self.get_response(request) return response + +class RegistrationCartCleanupMiddleware: + def __init__(self, get_response): + self.get_response = get_response + + def __call__(self, request): + self._check_and_clean_expired_cart(request) + response = self.get_response(request) + return response + + def _check_and_clean_expired_cart(self, request): + if 'registration_cart_expiry' in request.session: + try: + expiry_str = request.session['registration_cart_expiry'] + expiry = datetime.datetime.fromisoformat(expiry_str) + if timezone.now() > expiry: + # Clear expired cart + keys_to_delete = [ + 'registration_cart_id', + 'registration_tournament_id', + 'registration_cart_players', + 'registration_cart_expiry', + 'registration_mobile_number' + ] + for key in keys_to_delete: + if key in request.session: + del request.session[key] + request.session.modified = True + except (ValueError, TypeError): + # Invalid expiry format, clear it + if 'registration_cart_expiry' in request.session: + del request.session['registration_cart_expiry'] + request.session.modified = True diff --git a/tournaments/migrations/0114_playerregistration_payment_status_and_more.py b/tournaments/migrations/0116_playerregistration_payment_status_and_more.py similarity index 67% rename from tournaments/migrations/0114_playerregistration_payment_status_and_more.py rename to tournaments/migrations/0116_playerregistration_payment_status_and_more.py index 92fcaf2..4593c49 100644 --- a/tournaments/migrations/0114_playerregistration_payment_status_and_more.py +++ b/tournaments/migrations/0116_playerregistration_payment_status_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1 on 2025-03-29 14:28 +# Generated by Django 5.1 on 2025-04-08 08:43 from django.db import migrations, models @@ -6,7 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('tournaments', '0113_tournament_team_count_limit'), + ('tournaments', '0115_auto_20250403_1503'), ] operations = [ @@ -25,4 +25,9 @@ class Migration(migrations.Migration): name='time_to_confirm', field=models.DateTimeField(blank=True, null=True), ), + migrations.AlterField( + model_name='tournament', + name='federal_level_category', + field=models.IntegerField(choices=[(0, 'Animation'), (25, 'P25'), (100, 'P100'), (250, 'P250'), (500, 'P500'), (1000, 'P1000'), (1500, 'P1500'), (2000, 'P2000'), (1, 'Championnat')], default=100), + ), ] diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py index 5d63190..e58ed9c 100644 --- a/tournaments/models/tournament.py +++ b/tournaments/models/tournament.py @@ -1674,6 +1674,31 @@ class Tournament(BaseModel): return None + def is_user_registered(self, user): + """ + Check if a user is already registered for this tournament. + Returns True if the user is registered, False otherwise. + """ + if not user.is_authenticated or not user.licence_id: + return False + + # Validate the license format + validator = LicenseValidator(user.licence_id) + if not validator.validate_license(): + return False + + # Get the stripped license (without check letter) + stripped_license = validator.stripped_license + PlayerRegistration = apps.get_model('tournaments', 'PlayerRegistration') + + # Check if there's a player registration with this license in the tournament + # that hasn't walked out + return PlayerRegistration.objects.filter( + team_registration__tournament=self, + licence_id__icontains=stripped_license, + team_registration__walk_out=False + ).exists() + class MatchGroup: def __init__(self, name, matches, formatted_schedule, round_id=None): diff --git a/tournaments/services/registration_cart.py b/tournaments/services/registration_cart.py new file mode 100644 index 0000000..ab67176 --- /dev/null +++ b/tournaments/services/registration_cart.py @@ -0,0 +1,346 @@ +from django.utils import timezone +import uuid +import datetime +from ..models import PlayerRegistration, TeamRegistration, Tournament +from ..utils.licence_validator import LicenseValidator +from ..utils.player_search import get_player_name_from_csv + +def get_or_create_registration_cart_id(request): + """Get or create a registration cart ID in the session""" + if 'registration_cart_id' not in request.session: + request.session['registration_cart_id'] = str(uuid.uuid4()) + return request.session['registration_cart_id'] + +def get_cart_expiry(request): + """Get the cart expiry time from the session""" + if 'registration_cart_expiry' not in request.session: + # Set default expiry to 30 minutes from now + expiry = timezone.now() + datetime.timedelta(minutes=30) + request.session['registration_cart_expiry'] = expiry.isoformat() + return request.session['registration_cart_expiry'] + +def is_cart_expired(request): + """Check if the registration cart is expired""" + if 'registration_cart_expiry' not in request.session: + return False + + expiry_str = request.session['registration_cart_expiry'] + try: + expiry = datetime.datetime.fromisoformat(expiry_str) + return timezone.now() > expiry + except (ValueError, TypeError): + return True + +def reset_cart_expiry(request): + """Reset the cart expiry time""" + expiry = timezone.now() + datetime.timedelta(minutes=30) + request.session['registration_cart_expiry'] = expiry.isoformat() + request.session.modified = True + +def get_tournament_from_cart(request): + """Get the tournament ID associated with the current cart""" + return request.session.get('registration_tournament_id') + +def initialize_registration_cart(request, tournament_id): + """Initialize a new registration cart for a tournament""" + # Clear any existing cart + clear_registration_cart(request) + + # Set up the new cart + request.session['registration_cart_id'] = str(uuid.uuid4()) + request.session['registration_tournament_id'] = tournament_id + request.session['registration_cart_players'] = [] + reset_cart_expiry(request) + request.session.modified = True + +def get_registration_cart_data(request): + """Get the data for the current registration cart""" + # Ensure cart players array exists + if 'registration_cart_players' not in request.session: + request.session['registration_cart_players'] = [] + request.session.modified = True + + # Ensure tournament ID exists + if 'registration_tournament_id' not in request.session: + # If no tournament ID but we have players, this is an inconsistency + if request.session.get('registration_cart_players'): + print("WARNING: Found players but no tournament ID - clearing players") + request.session['registration_cart_players'] = [] + request.session.modified = True + + cart_data = { + 'cart_id': get_or_create_registration_cart_id(request), + 'tournament_id': request.session.get('registration_tournament_id'), + 'players': request.session.get('registration_cart_players', []), + 'expiry': get_cart_expiry(request), + 'mobile_number': request.session.get('registration_mobile_number', + request.user.phone if hasattr(request.user, 'phone') else '') + } + + # Debug: print the cart content + print(f"Cart data - Tournament ID: {cart_data['tournament_id']}") + print(f"Cart data - Players count: {len(cart_data['players'])}") + + return cart_data + +def add_player_to_cart(request, player_data): + """Add a player to the registration cart""" + if is_cart_expired(request): + return False, "Votre session d'inscription a expiré, veuillez réessayer." + + # Get cart data + tournament_id = request.session.get('registration_tournament_id') + if not tournament_id: + return False, "Pas d'inscription active." + + # Get tournament + try: + tournament = Tournament.objects.get(id=tournament_id) + except Tournament.DoesNotExist: + return False, "Tournoi introuvable." + + # Get existing players directly from session + players = request.session.get('registration_cart_players', []) + + # Debug: Initial players count + print(f"Before adding - Players in session: {len(players)}") + + # Check if we've reached the team limit (usually 2 for padel) + if len(players) >= 2: # Assuming teams of 2 for padel + return False, "Nombre maximum de joueurs déjà ajouté." + + # Process player data + licence_id = player_data.get('licence_id', '').upper() if player_data.get('licence_id') else None + first_name = player_data.get('first_name', '') + last_name = player_data.get('last_name', '').upper() + + # Handle case where user is authenticated, has no license, and license is required + if tournament.license_is_required: + # If license is required but not provided + if not licence_id: + # First player (authentication check) or partner + user_message = "Le numéro de licence est obligatoire." if len(players) == 0 else "Le numéro de licence de votre partenaire est obligatoire." + return False, user_message + + # Validate the license format + validator = LicenseValidator(licence_id) + if not validator.validate_license(): + return False, "Le numéro de licence est invalide, la lettre ne correspond pas." + + # Check if player is already registered in tournament + stripped_license = validator.stripped_license + if _is_player_already_registered(stripped_license, tournament): + return False, "Un joueur avec ce numéro de licence est déjà inscrit dans une équipe." + + # Check if this is the authenticated user trying to register as first player + if request.user.is_authenticated and len(players) == 0 and request.user.licence_id is None: + # Try to update the user's license ID in the database + try: + request.user.licence_id = validator.computed_licence_id + request.user.save() + request.user.refresh_from_db() + except: + return False, "Erreur lors de la mise à jour de votre licence: cette licence est déjà utilisée par un autre joueur." + + # Check for duplicate licenses in cart + existing_licenses = [p.get('licence_id') for p in players if p.get('licence_id')] + if licence_id and licence_id in existing_licenses: + return False, "Ce joueur est déjà dans l'équipe." + + # Process based on whether license ID was provided and tournament rules + if licence_id: + # Get federation data + fed_data, found = get_player_name_from_csv(tournament.federal_category, licence_id) + if found and fed_data: + # Use federation data (including check for eligibility) + player_register_check = tournament.player_register_check(licence_id) + if player_register_check: + return False, ", ".join(player_register_check) + + # Update player data from federation data + player_data.update({ + 'first_name': fed_data['first_name'], + 'last_name': fed_data['last_name'], + 'rank': fed_data['rank'], + 'is_woman': fed_data['is_woman'], + 'points': fed_data.get('points'), + 'assimilation': fed_data.get('assimilation'), + 'tournament_count': fed_data.get('tournament_count'), + 'ligue_name': fed_data.get('ligue_name'), + 'club_name': fed_data.get('club_name'), + 'birth_year': fed_data.get('birth_year'), + 'found_in_french_federation': True, + }) + elif tournament.license_is_required: + # License required but not found in federation data + return False, "La licence fournit n'a pas été trouvée dans la base FFT. Contactez le juge arbitre si cette licence est valide." + elif not first_name or not last_name: + # License not required or not found, but name is needed + return False, "Le prénom et le nom sont obligatoires pour les joueurs sans licence." + elif not tournament.license_is_required: + # License not required, check if name is provided + if not first_name or not last_name: + return False, "Le prénom et le nom sont obligatoires pour les joueurs sans licence." + + # Set default rank for players without a license + if player_data.get('rank') is None: + default_data, _ = get_player_name_from_csv(tournament.federal_category, None) + if default_data: + player_data['rank'] = default_data.get('rank') + player_data['is_woman'] = default_data.get('is_woman', False) + else: + # License is required but not provided + return False, "Le numéro de licence est obligatoire." + + # Add player to cart + players.append(player_data) + request.session['registration_cart_players'] = players + reset_cart_expiry(request) + request.session.modified = True + + return True, "Joueur ajouté avec succès." + +def remove_player_from_cart(request): + """Remove the last player from the cart""" + if is_cart_expired(request): + return False, "Votre session d'inscription a expiré, veuillez réessayer." + + players = request.session.get('registration_cart_players', []) + if not players: + return False, "Pas de joueur à supprimer." + + # Remove last player + players.pop() + request.session['registration_cart_players'] = players + reset_cart_expiry(request) + request.session.modified = True + + # If cart is now empty and user is authenticated with license, re-add them automatically + if not players: + add_authenticated_user_to_cart(request) + + return True, "Joueur retiré." + +def update_cart_contact_info(request, mobile_number=None): + """Update contact info for the cart""" + if is_cart_expired(request): + return False, "Votre session d'inscription a expiré, veuillez réessayer." + + if mobile_number is not None: + request.session['registration_mobile_number'] = mobile_number + + reset_cart_expiry(request) + request.session.modified = True + + return True, "Informations de contact mises à jour." + +def checkout_registration_cart(request): + """Convert cart to an actual tournament registration""" + if is_cart_expired(request): + return False, "Votre session d'inscription a expiré, veuillez réessayer." + + # Get cart data + cart_data = get_registration_cart_data(request) + tournament_id = cart_data.get('tournament_id') + players = cart_data.get('players') + mobile_number = cart_data.get('mobile_number') + + # Validate cart data + if not tournament_id: + return False, "Aucun tournoi sélectionné." + + if not players: + return False, "Aucun joueur dans l'inscription." + + # Get tournament + try: + tournament = Tournament.objects.get(id=tournament_id) + except Tournament.DoesNotExist: + return False, "Tournoi introuvable." + + # Check minimum players + if len(players) < tournament.minimum_player_per_team: + return False, f"Vous avez besoin d'au moins {tournament.minimum_player_per_team} joueurs pour vous inscrire." + + # Create team registration + team_registration = TeamRegistration.objects.create( + tournament=tournament, + registration_date=timezone.now(), + walk_out=False + ) + + # Create player registrations + for idx, player_data in enumerate(players): + PlayerRegistration.objects.create( + team_registration=team_registration, + first_name=player_data.get('first_name', ''), + last_name=player_data.get('last_name', '').upper(), + licence_id=player_data.get('licence_id'), + rank=player_data.get('rank'), + points=player_data.get('points'), + club_name=player_data.get('club_name'), + ligue_name=player_data.get('ligue_name'), + email=player_data.get('email'), + phone_number=player_data.get('phone'), + assimilation=player_data.get('assimilation'), + tournament_played=player_data.get('tournament_count'), + birthdate=str(player_data.get('birth_year', '')), + captain=(idx == 0), # First player is captain + registered_online=True, + registration_status='CONFIRMED' if tournament.get_waiting_list_position() < 0 else 'WAITING' + ) + + # Update user phone if provided + if request.user.is_authenticated and mobile_number: + request.user.phone = mobile_number + request.user.save(update_fields=['phone']) + + # Clear the cart + clear_registration_cart(request) + + return True, team_registration + +def clear_registration_cart(request): + """Clear the registration cart""" + keys_to_clear = [ + 'registration_cart_id', + 'registration_tournament_id', + 'registration_cart_players', + 'registration_cart_expiry', + 'registration_mobile_number' + ] + + for key in keys_to_clear: + if key in request.session: + del request.session[key] + + request.session.modified = True + +def _is_player_already_registered(stripped_license, tournament): + """Check if a player is already registered in the tournament""" + return PlayerRegistration.objects.filter( + team_registration__tournament=tournament, + licence_id__icontains=stripped_license, + team_registration__walk_out=False + ).exists() + +def add_authenticated_user_to_cart(request): + """ + Adds the authenticated user to the cart if they have a valid license. + Returns True if added, False otherwise. + """ + if not request.user.is_authenticated or not request.user.licence_id: + return False + + # Create player data for the authenticated user + player_data = { + 'first_name': request.user.first_name, + 'last_name': request.user.last_name, + 'licence_id': request.user.licence_id, + 'email': request.user.email, + 'phone': request.user.phone + } + + # Add the user to the cart + success, _ = add_player_to_cart(request, player_data) + return success diff --git a/tournaments/signals.py b/tournaments/signals.py index b352c49..8144283 100644 --- a/tournaments/signals.py +++ b/tournaments/signals.py @@ -109,7 +109,7 @@ def check_waiting_list(sender, instance, **kwargs): teams_out_to_warn = [] teams_in_to_warn = [] - + previous_state_teams = previous_state.teams(True) if previous_state.team_count > instance.team_count: teams_that_will_be_out = instance.teams(True)[instance.team_count:] teams_out_to_warn = [ @@ -117,7 +117,7 @@ def check_waiting_list(sender, instance, **kwargs): if team.stage != "Attente" ] elif previous_state.team_count < instance.team_count: - teams_that_will_be_in = previous_state.teams(True)[previous_state.team_count:instance.team_count] + teams_that_will_be_in = previous_state_teams[previous_state.team_count:instance.team_count] teams_in_to_warn = [ team for team in teams_that_will_be_in if team.stage == "Attente" diff --git a/tournaments/templates/register_tournament.html b/tournaments/templates/register_tournament.html index 66c4dd7..456ca64 100644 --- a/tournaments/templates/register_tournament.html +++ b/tournaments/templates/register_tournament.html @@ -26,6 +26,11 @@ Un email de confirmation a été envoyé à l'adresse associée à votre compte Padel Club ({{ user.email }}). Pensez à vérifier vos spams si vous ne recevez pas l'email. En cas de problème, contactez le juge-arbitre.

{% else %} + {% if not registration_successful %} +
+

Votre session d'inscription est active. Complétez le formulaire pour confirmer votre participation.

+
+ {% endif %} {% if team_form.errors %}
@@ -126,10 +131,13 @@ Précisez les informations du joueur :
{% endif %} + + {% if not add_player_form.user_without_licence %} {{ add_player_form.first_name.label_tag }} {{ add_player_form.first_name }} {{ add_player_form.last_name.label_tag }} {{ add_player_form.last_name }} + {% endif %} {% if tournament.license_is_required is False %} {{ add_player_form.licence_id.label_tag }} {% if tournament.license_is_required is False %}(facultatif){% endif %} diff --git a/tournaments/urls.py b/tournaments/urls.py index fde41e3..150c1dc 100644 --- a/tournaments/urls.py +++ b/tournaments/urls.py @@ -57,6 +57,7 @@ urlpatterns = [ # path('profile/', views.profile, name='profile'), # URL pattern for signup path('my-tournaments/', views.my_tournaments, name='my-tournaments'), # URL pattern for signup path('all_my_ended_tournaments/', views.all_my_ended_tournaments, name='all-my-ended-tournaments'), # URL pattern for signup + path('tournaments//cancel-registration/', views.cancel_registration, name='cancel_registration'), path('tournaments//register/', views.register_tournament, name='register_tournament'), path('tournaments//unregister/', views.unregister_tournament, name='unregister_tournament'), path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'), diff --git a/tournaments/views.py b/tournaments/views.py index a69b4f7..778aad9 100644 --- a/tournaments/views.py +++ b/tournaments/views.py @@ -6,6 +6,7 @@ from .utils.extensions import create_random_filename from api.serializers import GroupStageSerializer, MatchSerializer, PlayerRegistrationSerializer, TeamRegistrationSerializer, TeamScoreSerializer from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth import logout +from .utils.extensions import is_not_sqlite_backend from django.contrib.auth import update_session_auth_hash from django.contrib.auth.views import PasswordResetCompleteView @@ -49,13 +50,15 @@ from django.contrib.auth.decorators import login_required from django.contrib.auth.views import PasswordResetConfirmView from django.core.mail import EmailMessage from django.views.decorators.csrf import csrf_protect -from .services.tournament_registration import TournamentRegistrationService +from .services import registration_cart from .services.tournament_unregistration import TournamentUnregistrationService from django.core.exceptions import ValidationError from .forms import ( ProfileUpdateForm, SimpleCustomUserCreationForm, - SimpleForm + SimpleForm, + TournamentRegistrationForm, + AddPlayerForm ) from .utils.apns import send_push_notification from .utils.licence_validator import LicenseValidator @@ -723,15 +726,225 @@ def profile(request): @csrf_protect def register_tournament(request, tournament_id): tournament = get_object_or_404(Tournament, id=tournament_id) - service = TournamentRegistrationService(request, tournament) - service.initialize_context() - print("initialize_context") - if request.method == 'POST': - service.handle_post_request() + + # Debug session content + print("===== SESSION DUMP AT START =====") + for key, value in request.session.items(): + if key.startswith('registration_'): + print(f"{key}: {value}") + print("================================") + + # Check if tournament is open for registration + if not tournament.enable_online_registration: + messages.error(request, "L'inscription en ligne n'est pas activée pour ce tournoi.") + return redirect('tournament-info', tournament_id=tournament_id) + + # Check if user is already registered + if request.user.is_authenticated: + user_licence_id = request.user.licence_id + if user_licence_id and tournament.is_user_registered(request.user): + messages.info(request, "Vous êtes déjà inscrit à ce tournoi.") + return redirect('tournament-info', tournament_id=tournament_id) + + # Only initialize a fresh cart for GET requests + # For POST requests, use the existing cart to maintain state + if request.method == 'GET': + # ALWAYS initialize a fresh cart when entering the registration page (GET request) + # This ensures no old cart data persists + registration_cart.initialize_registration_cart(request, tournament_id) + + # Auto-add the authenticated user with license + if request.user.is_authenticated and request.user.licence_id: + player_data = { + 'first_name': request.user.first_name, + '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: - service.handle_get_request() + # For POST, ensure tournament ID is correct + current_tournament_id = registration_cart.get_tournament_from_cart(request) + if current_tournament_id != str(tournament_id): + registration_cart.initialize_registration_cart(request, tournament_id) + + # Re-add the authenticated user if they have a license + if request.user.is_authenticated and request.user.licence_id: + player_data = { + 'first_name': request.user.first_name, + '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) + + # Get cart data + cart_data = registration_cart.get_registration_cart_data(request) + + # Debug print + print(f"View - Cart Players Count: {len(cart_data['players'])}") + + # Initialize context with cart data + context = { + 'tournament': tournament, + 'current_players': cart_data['players'], + 'registration_successful': False + } - return render(request, 'register_tournament.html', service.context) + # Initialize forms + context['team_form'] = TournamentRegistrationForm(initial={ + 'email': request.user.email if request.user.is_authenticated else '', + 'mobile_number': request.user.phone if request.user.is_authenticated else cart_data.get('mobile_number', '') + }) + + # Initialize the add player form + add_player_form = AddPlayerForm() + + # Special handling for authenticated user without license + if request.user.is_authenticated and not request.user.licence_id and not cart_data['players']: + # Setup form for user without license + initial_data = { + 'first_name': request.user.first_name, + 'last_name': request.user.last_name + } + + # If license is required, only show license field initially + if tournament.license_is_required: + add_player_form = AddPlayerForm(initial=initial_data) + add_player_form.user_without_licence = True + else: + # If license not required, show all fields + add_player_form = AddPlayerForm(initial=initial_data) + elif not cart_data['players'] or len(cart_data['players']) < tournament.minimum_player_per_team: + # Regular partner addition form + add_player_form = AddPlayerForm() + + context['add_player_form'] = add_player_form + + # Handle POST requests + if request.method == 'POST': + if 'add_player' in request.POST: + add_player_form = AddPlayerForm(request.POST) + if add_player_form.is_valid(): + success, message = registration_cart.add_player_to_cart(request, add_player_form.cleaned_data) + if success: + messages.success(request, message) + # Refresh cart data + cart_data = registration_cart.get_registration_cart_data(request) + context['current_players'] = cart_data['players'] + + # Prepare a fresh form for the next player if needed + if len(cart_data['players']) < tournament.minimum_player_per_team: + context['add_player_form'] = AddPlayerForm() + else: + # Remove the form if we've reached the team limit + context['add_player_form'] = None + else: + messages.error(request, message) + context['add_player_form'] = add_player_form + else: + for field, errors in add_player_form.errors.items(): + for error in errors: + messages.error(request, f"{field}: {error}") + context['add_player_form'] = add_player_form + + elif 'remove_player' in request.POST: + success, message = registration_cart.remove_player_from_cart(request) + if success: + messages.info(request, message) + # Refresh cart data + cart_data = registration_cart.get_registration_cart_data(request) + context['current_players'] = cart_data['players'] + + # If after removing, the cart is empty and user has no license but license is required + if not cart_data['players'] and request.user.is_authenticated: + if not request.user.licence_id and tournament.license_is_required: + initial_data = { + 'first_name': request.user.first_name, + 'last_name': request.user.last_name + } + add_player_form = AddPlayerForm(initial=initial_data) + add_player_form.user_without_licence = True + else: + # This will handle re-adding the user with license + add_player_form = AddPlayerForm() + + context['add_player_form'] = add_player_form + else: + add_player_form = AddPlayerForm() + context['add_player_form'] = add_player_form + else: + messages.error(request, message) + + elif 'register_team' in request.POST: + team_form = TournamentRegistrationForm(request.POST) + if team_form.is_valid(): + # Debug print before checkout + print(f"Before checkout - Players in cart: {len(cart_data['players'])}") + + # Ensure the session data is correctly saved before proceeding + request.session.modified = True + request.session.save() + + # Update cart with contact info + registration_cart.update_cart_contact_info( + request, + mobile_number=team_form.cleaned_data.get('mobile_number') + ) + + # Get fresh cart data again after updating contact info + fresh_cart_data = registration_cart.get_registration_cart_data(request) + print(f"After contact update - Players in cart: {len(fresh_cart_data['players'])}") + + # Debug session content + print("===== SESSION DUMP BEFORE CHECKOUT =====") + for key, value in request.session.items(): + if key.startswith('registration_'): + print(f"{key}: {value}") + print("================================") + + # Checkout and create registration + success, result = registration_cart.checkout_registration_cart(request) + if success: + waiting_list_position = tournament.get_waiting_list_position() + if is_not_sqlite_backend(): + from .services.email_service import TournamentEmailService + email_service = TournamentEmailService() + email_service.send_registration_confirmation( + request, + tournament, + result, # team_registration + waiting_list_position + ) + + context['registration_successful'] = True + context['current_players'] = [] + context['add_player_form'] = None # No more adding players after success + else: + messages.error(request, result) + 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 + print("===== SESSION DUMP BEFORE RENDER =====") + for key, value in request.session.items(): + if key.startswith('registration_'): + print(f"{key}: {value}") + print("================================") + + return render(request, 'register_tournament.html', context) + +@login_required +def cancel_registration(request, tournament_id): + """Cancel the current registration process and clear the cart""" + registration_cart.clear_registration_cart(request) + messages.info(request, "Processus d'inscription annulé.") + return redirect('tournament-info', tournament_id=tournament_id) @login_required def unregister_tournament(request, tournament_id):