From 28e39be609f8fe94ba042c0abd9fc0a2b7930686 Mon Sep 17 00:00:00 2001 From: Raz Date: Wed, 9 Apr 2025 21:25:38 +0200 Subject: [PATCH] add payment for registration clean up --- ...urnament_enable_online_payment_and_more.py | 23 + ...t_enable_online_payment_refund_and_more.py | 23 + tournaments/models/team_registration.py | 4 +- tournaments/models/tournament.py | 69 +- tournaments/services/email_service.py | 2 +- tournaments/services/payment_service.py | 193 +++++ tournaments/services/registration_cart.py | 365 -------- .../services/tournament_registration.py | 777 ++++++++++-------- .../templates/register_tournament.html | 3 +- .../tournaments/tournament_info.html | 84 +- tournaments/views.py | 765 ++++++++--------- 11 files changed, 1104 insertions(+), 1204 deletions(-) create mode 100644 tournaments/migrations/0119_tournament_enable_online_payment_and_more.py create mode 100644 tournaments/migrations/0120_tournament_enable_online_payment_refund_and_more.py create mode 100644 tournaments/services/payment_service.py delete mode 100644 tournaments/services/registration_cart.py diff --git a/tournaments/migrations/0119_tournament_enable_online_payment_and_more.py b/tournaments/migrations/0119_tournament_enable_online_payment_and_more.py new file mode 100644 index 0000000..fac844a --- /dev/null +++ b/tournaments/migrations/0119_tournament_enable_online_payment_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1 on 2025-04-09 18:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tournaments', '0118_remove_playerregistration_payment_status_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='tournament', + name='enable_online_payment', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='tournament', + name='online_payment_is_mandatory', + field=models.BooleanField(default=False), + ), + ] diff --git a/tournaments/migrations/0120_tournament_enable_online_payment_refund_and_more.py b/tournaments/migrations/0120_tournament_enable_online_payment_refund_and_more.py new file mode 100644 index 0000000..9b03170 --- /dev/null +++ b/tournaments/migrations/0120_tournament_enable_online_payment_refund_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1 on 2025-04-09 19:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tournaments', '0119_tournament_enable_online_payment_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='tournament', + name='enable_online_payment_refund', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='tournament', + name='refund_date_limit', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/tournaments/models/team_registration.py b/tournaments/models/team_registration.py index 4eed0d6..b2a3d68 100644 --- a/tournaments/models/team_registration.py +++ b/tournaments/models/team_registration.py @@ -388,6 +388,6 @@ class TeamRegistration(SideStoreModel): if status == 'PAID': return 0 elif status == 'UNPAID': - return self.tournament.entry_fee * 2 + return self.tournament.team_fee() elif status == 'MIXED': - return self.tournament.entry_fee + return self.tournament.player_fee() diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py index 44c0bde..7ca313a 100644 --- a/tournaments/models/tournament.py +++ b/tournaments/models/tournament.py @@ -79,6 +79,10 @@ class Tournament(BaseModel): hide_umpire_phone = models.BooleanField(default=True) disable_ranking_federal_ruling = models.BooleanField(default=False) reserved_spots = models.IntegerField(default=0) + enable_online_payment = models.BooleanField(default=False) + online_payment_is_mandatory = models.BooleanField(default=False) + enable_online_payment_refund = models.BooleanField(default=False) + refund_date_limit = models.DateTimeField(null=True, blank=True) # Equivalent to Date? = nil def delete_dependencies(self): for team_registration in self.team_registrations.all(): @@ -1056,6 +1060,19 @@ class Tournament(BaseModel): if self.license_is_required: options.append("Licence requise") + # Options de paiement en ligne + if self.enable_online_payment: + if self.online_payment_is_mandatory: + options.append("Paiement en ligne obligatoire") + else: + options.append("Paiement en ligne disponible") + + if self.enable_online_payment_refund and self.refund_date_limit: + date = formats.date_format(self.refund_date_limit.astimezone(timezone), format='j F Y H:i') + options.append(f"Remboursement possible jusqu'au {date}") + elif self.enable_online_payment_refund: + options.append("Remboursement possible") + # Joueurs par équipe min_players = self.minimum_player_per_team max_players = self.maximum_player_per_team @@ -1675,18 +1692,14 @@ 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. - """ + def get_user_registered(self, user): if not user.is_authenticated or not user.licence_id: - return False + return None # Validate the license format validator = LicenseValidator(user.licence_id) if not validator.validate_license(): - return False + return None # Get the stripped license (without check letter) stripped_license = validator.stripped_license @@ -1698,13 +1711,49 @@ class Tournament(BaseModel): team_registration__tournament=self, licence_id__icontains=stripped_license, team_registration__walk_out=False - ).exists() + ).first() + + def is_user_registered(self, user): + return self.get_user_registered(user) is not None + + def get_user_team_registration(self, user): + user_registered = self.get_user_registered(user) + if user_registered: + return user_registered.team_registration + else: + return None def should_request_payment(self): - return True + if self.entry_fee is not None and self.entry_fee > 0 and self.enable_online_payment: + return True + else: + return False + + def is_refund_possible(self): + if self.enable_online_payment_refund: + time = timezone.now() + if self.refund_date_limit: + if time <= self.refund_date_limit: + return True + else: + return False + else: + return True + else: + return False + + def player_fee(self): + if self.entry_fee is not None and self.entry_fee > 0 and self.enable_online_payment: + return self.entry_fee + else: + return 0 def team_fee(self): - return self.entry_fee * 2 + entry_fee = self.entry_fee + if entry_fee is not None and entry_fee > 0 and self.enable_online_payment: + return self.entry_fee * self.minimum_player_per_team + else: + return 0 class MatchGroup: def __init__(self, name, matches, formatted_schedule, round_id=None): diff --git a/tournaments/services/email_service.py b/tournaments/services/email_service.py index 6e2b40a..b234b95 100644 --- a/tournaments/services/email_service.py +++ b/tournaments/services/email_service.py @@ -515,7 +515,7 @@ class TournamentEmailService: # For unpaid teams, add payment instructions payment_info = [ "\n\n⚠️ Paiement des frais d'inscription requis", - f"Les frais d'inscription de {tournament.entry_fee}€ doivent être payés pour confirmer votre participation.", + f"Les frais d'inscription de {tournament.entry_fee}€ par joueur doivent être payés pour confirmer votre participation.", "Vous pouvez effectuer le paiement en vous connectant à votre compte Padel Club.", f"Lien pour payer: https://padelclub.app/tournament/{tournament.id}/info" ] diff --git a/tournaments/services/payment_service.py b/tournaments/services/payment_service.py new file mode 100644 index 0000000..d161a92 --- /dev/null +++ b/tournaments/services/payment_service.py @@ -0,0 +1,193 @@ +from django.shortcuts import get_object_or_404, redirect +from django.conf import settings +from django.urls import reverse +from django.contrib import messages +import stripe + +from ..models import TeamRegistration, PlayerRegistration, Tournament +from ..models.player_registration import PlayerPaymentType, RegistrationStatus +from .email_service import TournamentEmailService +from .tournament_registration import RegistrationCartManager +from ..utils.extensions import is_not_sqlite_backend + +class PaymentService: + """ + Service for handling payment processing for tournament registrations + """ + + def __init__(self, request): + self.request = request + self.stripe_api_key = settings.STRIPE_SECRET_KEY + + def create_checkout_session(self, tournament_id, team_fee, cart_data=None, team_registration_id=None): + """ + Create a Stripe checkout session for tournament payment + """ + stripe.api_key = self.stripe_api_key + tournament = get_object_or_404(Tournament, id=tournament_id) + + # Get user email if authenticated + customer_email = self.request.user.email if self.request.user.is_authenticated else None + + # Determine the appropriate cancel URL based on the context + if team_registration_id: + # If we're paying for an existing registration, go back to tournament info + cancel_url = self.request.build_absolute_uri( + reverse('tournament-info', kwargs={'tournament_id': tournament_id}) + ) + else: + # If we're in the registration process, go back to registration form + cancel_url = self.request.build_absolute_uri( + reverse('register_tournament', kwargs={'tournament_id': tournament_id}) + ) + + # Common checkout session parameters + 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_fee * 100), # Amount in cents + }, + 'quantity': 1, + }], + 'mode': 'payment', + 'success_url': self.request.build_absolute_uri( + reverse('tournament-payment-success', kwargs={'tournament_id': tournament_id}) + ), + 'cancel_url': cancel_url, + 'metadata': { + 'tournament_id': str(tournament_id), # Convert UUID to string + 'user_id': str(self.request.user.id) if self.request.user.is_authenticated else None, # Convert UUID to string + 'source_page': 'tournament_info' if team_registration_id else 'register_tournament', + } + } + + # Add cart or team data to metadata based on payment context + if cart_data: + checkout_session_params['metadata']['registration_cart_id'] = str(cart_data['cart_id']) # Convert to string + elif team_registration_id: + checkout_session_params['metadata']['team_registration_id'] = str(team_registration_id) # Convert to string + self.request.session['team_registration_id'] = str(team_registration_id) # Convert to string + + # 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 and source page in session + self.request.session['stripe_checkout_session_id'] = checkout_session.id + self.request.session['payment_source_page'] = 'tournament_info' if team_registration_id else 'register_tournament' + self.request.session.modified = True + + return checkout_session + + def process_successful_payment(self, tournament_id, checkout_session): + """ + Process a successful Stripe payment + Returns a tuple (success, redirect_response) + """ + print(f"Processing payment for tournament {tournament_id}") + tournament = get_object_or_404(Tournament, id=tournament_id) + + # Check if this is a payment for an existing team registration + team_registration_id = self.request.session.get('team_registration_id') + print(f"Team registration ID from session: {team_registration_id}") + + # Track payment statuses for debugging + payment_statuses = [] + + if team_registration_id: + success = self._process_direct_payment(checkout_session) + payment_statuses.append(success) + print(f"Direct payment processing result: {success}") + else: + # This is a payment during registration process + success = self._process_registration_payment(tournament, checkout_session) + payment_statuses.append(success) + print(f"Registration payment processing result: {success}") + + # Print combined payment status + print(f"Payment statuses: {payment_statuses}") + print(any(payment_statuses)) + + # Clear checkout session ID + if 'stripe_checkout_session_id' in self.request.session: + del self.request.session['stripe_checkout_session_id'] + + return any(payment_statuses) + + def _process_direct_payment(self, checkout_session): + """Process payment for an existing team registration""" + team_registration_id = self.request.session.get('team_registration_id') + if not team_registration_id: + print("No team registration ID found in session") + return False + + try: + print(f"Looking for team registration with ID: {team_registration_id}") + team_registration = TeamRegistration.objects.get(id=team_registration_id) + success = self._update_registration_payment_info( + team_registration, + checkout_session.payment_intent + ) + + # Clean up session + if 'team_registration_id' in self.request.session: + del self.request.session['team_registration_id'] + + return success + except TeamRegistration.DoesNotExist: + print(f"Team registration not found with ID: {team_registration_id}") + return False + except Exception as e: + print(f"Error in _process_direct_payment: {str(e)}") + return False + + def _process_registration_payment(self, tournament, checkout_session): + """Process payment made during registration""" + cart_manager = RegistrationCartManager(self.request) + cart_data = cart_manager.get_cart_data() + + # Checkout and create registration + success, result = cart_manager.checkout() + if not success: + return False + + # Process payment for the new registration + team_registration = result # result is team_registration object + self._update_registration_payment_info( + team_registration, + checkout_session.payment_intent + ) + + # Send confirmation email if appropriate + waiting_list_position = cart_data.get('waiting_list_position', -1) + if is_not_sqlite_backend(): + email_service = TournamentEmailService() + email_service.send_registration_confirmation( + self.request, + tournament, + team_registration, + waiting_list_position + ) + + return True + + def _update_registration_payment_info(self, team_registration, payment_intent_id): + """Update player registrations with payment information""" + 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 = payment_intent_id + player_reg.save() + + return True diff --git a/tournaments/services/registration_cart.py b/tournaments/services/registration_cart.py deleted file mode 100644 index 82e976e..0000000 --- a/tournaments/services/registration_cart.py +++ /dev/null @@ -1,365 +0,0 @@ -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) - - try: - tournament = Tournament.objects.get(id=tournament_id) - except Tournament.DoesNotExist: - return False, "Tournoi introuvable." - - tournament.reserved_spots = max(0, tournament.reserved_spots - 1) - waiting_list_position = tournament.get_waiting_list_position() - - if waiting_list_position >= 0: - tournament.reserved_spots = 0 - else: - tournament.reserved_spots += 1 - - tournament.save() - - # Set up the new cart - request.session['registration_cart_id'] = str(uuid.uuid4()) - request.session['waiting_list_position'] = waiting_list_position - 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'), - 'waiting_list_position': request.session.get('waiting_list_position'), - '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 request.session['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) - tournament.reserved_spots = max(0, tournament.reserved_spots - 1) - tournament.save() - - 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/services/tournament_registration.py b/tournaments/services/tournament_registration.py index 019ef29..f8c13dc 100644 --- a/tournaments/services/tournament_registration.py +++ b/tournaments/services/tournament_registration.py @@ -1,372 +1,449 @@ from django.utils import timezone -from ..forms import TournamentRegistrationForm, AddPlayerForm -from ..repositories import TournamentRegistrationRepository -from .email_service import TournamentEmailService -from django.contrib import messages +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 -from tournaments.models import PlayerRegistration -from ..utils.extensions import is_not_sqlite_backend -from django.contrib.auth import get_user_model -from django.contrib.messages import get_messages -from django.db import IntegrityError - -class TournamentRegistrationService: - def __init__(self, request, tournament): + +class RegistrationCartManager: + """ + Manages the registration cart for tournament registrations. + Handles session-based cart operations, player additions/removals, + and checkout processes. + """ + + CART_EXPIRY_MINUTES = 30 + + def __init__(self, request): self.request = request - self.tournament = tournament - self.context = {} - self.repository = TournamentRegistrationRepository() - self.email_service = TournamentEmailService() - - def initialize_context(self): - self.context = { - 'tournament': self.tournament, - 'registration_successful': False, - 'team_form': None, - 'add_player_form': None, - 'current_players': self.request.session.get('team_registration', []), - } - return self.context - - def handle_post_request(self): - self.context['team_form'] = TournamentRegistrationForm(self.request.POST) - self.context['add_player_form'] = AddPlayerForm(self.request.POST) - - if 'add_player' in self.request.POST: - self.handle_add_player() - if 'remove_player' in self.request.POST: - self.handle_remove_player() - elif 'register_team' in self.request.POST: - self.handle_team_registration() - - def handle_remove_player(self): - team_registration = self.request.session.get('team_registration', []) - if team_registration: # Check if list is not empty - team_registration.pop() # Remove last element - self.request.session['team_registration'] = team_registration - self.context['current_players'] = team_registration - - def handle_add_player(self): - if not self.context['add_player_form'].is_valid(): - return - - # Clear existing messages if the form is valid - storage = get_messages(self.request) - # Iterate through the storage to clear it - for _ in storage: - pass - - player_data = self.context['add_player_form'].cleaned_data - licence_id = player_data.get('licence_id', '').upper() - - # Validate license - if not self._validate_license(licence_id): - return - - # Check for duplicate players - if self._is_duplicate_player(licence_id): - return - - # Check if player is already registered in tournament - if self._is_already_registered(licence_id): - return - - if self.request.user.is_authenticated and self.request.user.licence_id is None and len(self.context['current_players']) == 0: - if self._update_user_license(player_data.get('licence_id')) == False: - # if no licence id for authentificated user and trying to add him as first player of the team, we check his federal data - self._handle_invalid_names(licence_id, player_data) + self.session = request.session + + def get_or_create_cart_id(self): + """Get or create a registration cart ID in the session""" + if 'registration_cart_id' not in self.session: + self.session['registration_cart_id'] = str(uuid.uuid4()) # Ensure it's a string + self.session.modified = True + return self.session['registration_cart_id'] + + def get_cart_expiry(self): + """Get the cart expiry time from the session""" + if 'registration_cart_expiry' not in self.session: + # Set default expiry to 30 minutes from now + expiry = timezone.now() + datetime.timedelta(minutes=self.CART_EXPIRY_MINUTES) + self.session['registration_cart_expiry'] = expiry.isoformat() + self.session.modified = True + return self.session['registration_cart_expiry'] + + def is_cart_expired(self): + """Check if the registration cart is expired""" + if 'registration_cart_expiry' not in self.session: + return False + + expiry_str = self.session['registration_cart_expiry'] + try: + expiry = datetime.datetime.fromisoformat(expiry_str) + return timezone.now() > expiry + except (ValueError, TypeError): + return True + + def reset_cart_expiry(self): + """Reset the cart expiry time""" + expiry = timezone.now() + datetime.timedelta(minutes=self.CART_EXPIRY_MINUTES) + self.session['registration_cart_expiry'] = expiry.isoformat() + self.session.modified = True + + def get_tournament_id(self): + """Get the tournament ID associated with the current cart""" + return self.session.get('registration_tournament_id') + + def initialize_cart(self, tournament_id): + """Initialize a new registration cart for a tournament""" + # Clear any existing cart + self.clear_cart() + + try: + tournament = Tournament.objects.get(id=tournament_id) + except Tournament.DoesNotExist: + return False, "Tournoi introuvable." + + # Update tournament reserved spots + tournament.reserved_spots = max(0, tournament.reserved_spots - 1) + waiting_list_position = tournament.get_waiting_list_position() + + if waiting_list_position >= 0: + tournament.reserved_spots = 0 else: - # Handle player data - if self.context['add_player_form'].names_is_valid(): - self._handle_valid_names(player_data) - else: - self._handle_invalid_names(licence_id, player_data) - - def handle_team_registration(self): - if not self.context['team_form'].is_valid(): - return - - if self.request.user.is_authenticated: - cleaned_data = self.context['team_form'].cleaned_data - mobile_number = cleaned_data.get('mobile_number') - self.request.user.phone = mobile_number - self.request.user.save() + tournament.reserved_spots += 1 + + tournament.save() + + # Set up the new cart + self.session['registration_cart_id'] = str(uuid.uuid4()) # Ensure it's a string + self.session['waiting_list_position'] = waiting_list_position + self.session['registration_tournament_id'] = str(tournament_id) # Ensure it's a string + self.session['registration_cart_players'] = [] + self.reset_cart_expiry() + self.session.modified = True + + return True, "Cart initialized successfully" + + def get_cart_data(self): + """Get the data for the current registration cart""" + # Ensure cart players array exists + if 'registration_cart_players' not in self.session: + self.session['registration_cart_players'] = [] + self.session.modified = True + + # Ensure tournament ID exists + if 'registration_tournament_id' not in self.session: + # If no tournament ID but we have players, this is an inconsistency + if self.session.get('registration_cart_players'): + print("WARNING: Found players but no tournament ID - clearing players") + self.session['registration_cart_players'] = [] + self.session.modified = True + + # Get user phone if authenticated + user_phone = '' + if hasattr(self.request.user, 'phone'): + user_phone = self.request.user.phone + + cart_data = { + 'cart_id': self.get_or_create_cart_id(), + 'tournament_id': self.session.get('registration_tournament_id'), + 'waiting_list_position': self.session.get('waiting_list_position'), + 'players': self.session.get('registration_cart_players', []), + 'expiry': self.get_cart_expiry(), + 'mobile_number': self.session.get('registration_mobile_number', user_phone) + } - waiting_list_position = self.tournament.get_waiting_list_position() + # 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'])}") - team_registration = self.repository.create_team_registration( - self.tournament, - timezone.now().replace(microsecond=0) - ) + return cart_data + + def add_player(self, player_data): + """Add a player to the registration cart""" + if self.is_cart_expired(): + return False, "Votre session d'inscription a expiré, veuillez réessayer." + + # Get cart data + tournament_id = self.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 = self.session.get('registration_cart_players', []) + + # Check if we've reached the team limit + if len(players) >= 2: # Assuming teams of 2 for padel + return False, "Nombre maximum de joueurs déjà ajouté." - self.repository.create_player_registrations( - self.request, - team_registration, - self.request.session['team_registration'], - self.context['team_form'].cleaned_data + # 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() if player_data.get('last_name') else '' + + # Handle license validation logic + result = self._process_player_license( + tournament, licence_id, first_name, last_name, players, len(players) == 0 + ) + if not result[0]: + return result # Return the error + + # If we got here, license validation passed + 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) + self.session['registration_cart_players'] = players + self.reset_cart_expiry() + self.session.modified = True + + return True, "Joueur ajouté avec succès." + + def _process_player_license(self, tournament, licence_id, first_name, last_name, players, is_first_player): + """ + Process and validate player license + Returns (True, None) if valid, (False, error_message) if invalid + """ + # Handle case where 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 is_first_player 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 self._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 self.request.user.is_authenticated and is_first_player and self.request.user.licence_id is None: + # Try to update the user's license ID in the database + try: + self.request.user.licence_id = validator.computed_licence_id + self.request.user.save() + self.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." + + return True, None + + def remove_player(self): + """Remove the last player from the cart""" + if self.is_cart_expired(): + return False, "Votre session d'inscription a expiré, veuillez réessayer." + + players = self.session.get('registration_cart_players', []) + if not players: + return False, "Pas de joueur à supprimer." + + # Remove last player + players.pop() + self.session['registration_cart_players'] = players + self.reset_cart_expiry() + self.session.modified = True + + return True, "Joueur retiré." + + def update_contact_info(self, mobile_number=None): + """Update contact info for the cart""" + if self.is_cart_expired(): + return False, "Votre session d'inscription a expiré, veuillez réessayer." + + if mobile_number is not None: + self.session['registration_mobile_number'] = mobile_number + + self.reset_cart_expiry() + self.session.modified = True + + return True, "Informations de contact mises à jour." + + def checkout(self): + """Convert cart to an actual tournament registration""" + if self.is_cart_expired(): + return False, "Votre session d'inscription a expiré, veuillez réessayer." + + # Get cart data + cart_data = self.get_cart_data() + 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 ) - if is_not_sqlite_backend(): - self.email_service.send_registration_confirmation( - self.request, - self.tournament, - team_registration, - waiting_list_position + # 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 self.session['waiting_list_position'] < 0 else 'WAITING' ) - self.clear_session_data() - self.context['registration_successful'] = True - - def handle_get_request(self): - print("handle_get_request") - storage = get_messages(self.request) - # Iterate through the storage to clear it - for _ in storage: - pass - - self.context['add_player_form'] = AddPlayerForm() - self.context['team_form'] = self.initialize_team_form() - self.initialize_session_data() - - def add_player_to_session(self, player_data): - print("add_player_to_session", player_data) - if not self.request.session.get('team_registration'): - self.request.session['team_registration'] = [] - - self.request.session['team_registration'].append(player_data) - self.context['current_players'] = self.request.session.get('team_registration', []) - self.context['add_player_form'].first_tournament = False - self.context['add_player_form'].user_without_licence = False - self.request.session.modified = True - - def clear_session_data(self): - self.request.session['team_registration'] = [] - self.request.session.modified = True - - def initialize_team_form(self): - initial_data = {} - if self.request.user.is_authenticated: - initial_data = { - 'email': self.request.user.email, - 'mobile_number': self.request.user.phone, - } - return TournamentRegistrationForm(initial=initial_data) - - def initialize_session_data(self): - print("initialize_session_data") - self.request.session['team_registration'] = [] - if self.request.user.is_authenticated: - self._add_authenticated_user_to_session() - - def _add_authenticated_user_to_session(self): - if not self.request.user.licence_id: - self._handle_user_without_license() - return - - player_data = self._get_authenticated_user_data() - if player_data: - self.request.session['team_registration'].insert(0, player_data) - self.context['current_players'] = self.request.session.get('team_registration', []) - self.request.session.modified = True - - def _handle_user_without_license(self): + # Update user phone if provided + if self.request.user.is_authenticated and mobile_number: + self.request.user.phone = mobile_number + self.request.user.save(update_fields=['phone']) + + # Clear the cart + self.clear_cart() + tournament.reserved_spots = max(0, tournament.reserved_spots - 1) + tournament.save() + + return True, team_registration + + def clear_cart(self): + """Clear the registration cart""" + keys_to_clear = [ + 'registration_cart_id', + 'team_registration_id', + 'registration_tournament_id', + 'registration_cart_players', + 'registration_cart_expiry', + 'registration_mobile_number' + ] + + for key in keys_to_clear: + if key in self.session: + del self.session[key] + + self.session.modified = True + + def _is_player_already_registered(self, 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(self): + """ + Adds the authenticated user to the cart if they have a valid license. + Returns True if added, False otherwise. + """ + if not self.request.user.is_authenticated or not self.request.user.licence_id: + return False + + # Create player data for the authenticated user player_data = { 'first_name': self.request.user.first_name, - 'last_name': self.request.user.last_name.upper(), + 'last_name': self.request.user.last_name, + 'licence_id': self.request.user.licence_id, + 'email': self.request.user.email, + 'phone': self.request.user.phone } - self.context['add_player_form'] = AddPlayerForm(initial=player_data) - self.context['add_player_form'].user_without_licence = True - self.request.session.modified = True - def _get_authenticated_user_data(self): - user = self.request.user - validator = LicenseValidator(user.licence_id) + # Add the user to the cart + success, _ = self.add_player(player_data) + return success - player_data = { - 'first_name': user.first_name, - 'last_name': user.last_name.upper(), - 'email': user.email, - 'phone': user.phone, - 'licence_id': validator.computed_licence_id - } - data, found = get_player_name_from_csv(self.tournament.federal_category, user.licence_id) - if found and data: - player_data.update({ - 'rank': data['rank'], - 'points': data.get('points'), - 'assimilation': data.get('assimilation'), - 'tournament_count': data.get('tournament_count'), - 'ligue_name': data.get('ligue_name'), - 'club_name': data.get('club_name'), - 'birth_year': data.get('birth_year'), - 'found_in_french_federation': True, - }) - - return player_data - - def _validate_license(self, licence_id): - print("Validating license...") - validator = LicenseValidator(licence_id) - - if validator.validate_license() is False and self.tournament.license_is_required: - if not licence_id: - message = ("Le numéro de licence est obligatoire." - if not self.request.session.get('team_registration', []) - else "Le numéro de licence de votre partenaire est obligatoire.") - messages.error(self.request, message) - else: - # computed_license_key = validator.computed_license_key - # messages.error(self.request, f"Le numéro de licence est invalide, la lettre ne correspond pas. {computed_license_key}") - messages.error(self.request, "Le numéro de licence est invalide, la lettre ne correspond pas.") - print("License validation failed") - return False - return True +# For backward compatibility with existing code that uses the function-based approach +def get_or_create_registration_cart_id(request): + cart_manager = RegistrationCartManager(request) + return cart_manager.get_or_create_cart_id() - def _is_duplicate_player(self, licence_id): - existing_players = [player['licence_id'] for player in self.request.session.get('team_registration', [])] - if licence_id in existing_players: - messages.error(self.request, "Ce joueur est déjà dans l'équipe.") - return True - return False - - def _is_already_registered(self, licence_id): - validator = LicenseValidator(licence_id) - if (validator.validate_license() and - self._license_already_registered(validator.stripped_license) and - self.tournament.license_is_required): - messages.error(self.request, "Un joueur avec ce numéro de licence est déjà inscrit dans une équipe.") - return True - return False - - def _handle_valid_names(self, player_data): - print("_handle_valid_names", player_data) - if player_data.get('rank') is None: - self._set_default_rank(player_data) - - self.add_player_to_session(player_data) - self.context['add_player_form'] = AddPlayerForm() - self.context['add_player_form'].first_tournament = False - - def _handle_invalid_names(self, licence_id, player_data): - data, found = get_player_name_from_csv(self.tournament.federal_category, licence_id) - print("_handle_invalid_names get_player_name_from_csv", data, found) - if found and data: - self._update_player_data_from_csv(player_data, data) - player_check = self._player_check(player_data) - if player_check == True: - self.add_player_to_session(player_data) - self.context['add_player_form'] = AddPlayerForm() - else: - return - else: - print("_handle_first_tournament_case") - self._handle_first_tournament_case(data) - - def _set_default_rank(self, player_data): - if self.request.session.get('last_rank') is None: - data, found = get_player_name_from_csv(self.tournament.federal_category, None) - if data: - self.request.session['last_rank'] = data['rank'] - self.request.session['is_woman'] = data['is_woman'] - self.request.session.modified = True - - player_data['rank'] = self.request.session.get('last_rank', None) - player_data['is_woman'] = self.request.session.get('is_woman', False) - - def _update_user_license(self, licence_id): - if not self.request.user.is_authenticated or not licence_id: - return False +def get_cart_expiry(request): + cart_manager = RegistrationCartManager(request) + return cart_manager.get_cart_expiry() - self.context['add_player_form'].user_without_licence = False - validator = LicenseValidator(licence_id) - - if validator.validate_license(): - computed_licence_id = validator.computed_licence_id - try: - self.request.user.licence_id = computed_licence_id - self.request.user.save() - self.request.user.refresh_from_db() - self.request.session.modified = True - return True - - except IntegrityError: - # Handle the duplicate license error - error_msg = f"Ce numéro de licence ({computed_licence_id}) est déjà utilisé par un autre joueur." - messages.error(self.request, error_msg) - return False - - def _update_player_data_from_csv(self, player_data, csv_data): - print("_update_player_data_from_csv", player_data, csv_data) - player_data.update({ - 'first_name': csv_data['first_name'], - 'last_name': csv_data['last_name'], - 'rank': csv_data['rank'], - 'is_woman': csv_data['is_woman'], - 'points': csv_data.get('points'), - 'assimilation': csv_data.get('assimilation'), - 'tournament_count': csv_data.get('tournament_count'), - 'ligue_name': csv_data.get('ligue_name'), - 'club_name': csv_data.get('club_name'), - 'birth_year': csv_data.get('birth_year'), - 'found_in_french_federation': True, - 'email': None, - 'phone': None, - }) - - User = get_user_model() - - # Get the license ID from player_data - licence_id = player_data.get('licence_id') - validator = LicenseValidator(licence_id) - if validator.validate_license(): - try: - # Try to find a user with matching license - user_with_same_license = User.objects.get(licence_id__iexact=validator.computed_licence_id) - - # If found, update the email and phone - if user_with_same_license: - player_data.update({ - 'email': user_with_same_license.email, - 'phone': user_with_same_license.phone - }) - print(f"Found user with license {licence_id}, updated email and phone") - except User.DoesNotExist: - # No user found with this license, continue with None email and phone - pass - - def _handle_first_tournament_case(self, data): - print("_handle_first_tournament_case", data) - if data: - self.request.session['last_rank'] = data['rank'] - self.request.session['is_woman'] = data['is_woman'] - self.request.session.modified = True - - self.context['add_player_form'].first_tournament = True - - if not self.context['add_player_form'].names_is_valid(): - message = ("Pour confirmer votre inscription votre prénom et votre nom sont obligatoires." - if not self.request.session.get('team_registration', []) - else "Pour rajouter un partenaire, son prénom et son nom sont obligatoires.") - messages.error(self.request, message) - - def _player_check(self, player_data): - licence_id = player_data['licence_id'].upper() - validator = LicenseValidator(licence_id) - is_license_valid = validator.validate_license() - - player_register_check = self.tournament.player_register_check(licence_id) - if is_license_valid and player_register_check is not None: - for message in player_register_check: - messages.error(self.request, message) - return False +def is_cart_expired(request): + cart_manager = RegistrationCartManager(request) + return cart_manager.is_cart_expired() - return True +def reset_cart_expiry(request): + cart_manager = RegistrationCartManager(request) + cart_manager.reset_cart_expiry() - def _license_already_registered(self, stripped_license): - return PlayerRegistration.objects.filter( - team_registration__tournament=self.tournament, - licence_id__icontains=stripped_license, - team_registration__walk_out=False - ).exists() +def get_tournament_from_cart(request): + cart_manager = RegistrationCartManager(request) + return cart_manager.get_tournament_id() + +def initialize_registration_cart(request, tournament_id): + cart_manager = RegistrationCartManager(request) + return cart_manager.initialize_cart(tournament_id) + +def get_registration_cart_data(request): + cart_manager = RegistrationCartManager(request) + return cart_manager.get_cart_data() + +def add_player_to_cart(request, player_data): + cart_manager = RegistrationCartManager(request) + return cart_manager.add_player(player_data) + +def remove_player_from_cart(request): + cart_manager = RegistrationCartManager(request) + return cart_manager.remove_player() + +def update_cart_contact_info(request, mobile_number=None): + cart_manager = RegistrationCartManager(request) + return cart_manager.update_contact_info(mobile_number) + +def checkout_registration_cart(request): + cart_manager = RegistrationCartManager(request) + return cart_manager.checkout() + +def clear_registration_cart(request): + cart_manager = RegistrationCartManager(request) + cart_manager.clear_cart() + +def add_authenticated_user_to_cart(request): + cart_manager = RegistrationCartManager(request) + return cart_manager.add_authenticated_user() diff --git a/tournaments/templates/register_tournament.html b/tournaments/templates/register_tournament.html index 45b23d8..2fd3551 100644 --- a/tournaments/templates/register_tournament.html +++ b/tournaments/templates/register_tournament.html @@ -179,7 +179,8 @@ - {% else %} + {% endif %} + {% if tournament.should_request_payment is False or tournament.online_payment_is_mandatory is False or cart_data.waiting_list_position >= 0 %}