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):