diff --git a/tournaments/migrations/0100_playerregistration_coach_and_more.py b/tournaments/migrations/0100_playerregistration_coach_and_more.py new file mode 100644 index 0000000..ae642b3 --- /dev/null +++ b/tournaments/migrations/0100_playerregistration_coach_and_more.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.11 on 2024-12-10 08:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tournaments', '0099_remove_tournament_display_entry_fee_information'), + ] + + operations = [ + migrations.AddField( + model_name='playerregistration', + name='coach', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='teamregistration', + name='unregistered', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='teamregistration', + name='unregistration_date', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/tournaments/models/__init__.py b/tournaments/models/__init__.py index ff8321d..d385a4e 100644 --- a/tournaments/models/__init__.py +++ b/tournaments/models/__init__.py @@ -2,7 +2,7 @@ from .custom_user import CustomUser from .club import Club from .court import Court from .date_interval import DateInterval -from .enums import TournamentPayment, FederalCategory, FederalLevelCategory, FederalAgeCategory, FederalMatchCategory +from .enums import TournamentPayment, FederalCategory, FederalLevelCategory, FederalAgeCategory, FederalMatchCategory, OnlineRegistrationStatus from .player_enums import PlayerSexType, PlayerDataSource, PlayerPaymentType from .event import Event from .tournament import Tournament, TeamSummon, TeamSortingType, TeamItem diff --git a/tournaments/models/enums.py b/tournaments/models/enums.py index c5099cd..255df99 100644 --- a/tournaments/models/enums.py +++ b/tournaments/models/enums.py @@ -85,3 +85,29 @@ class FederalMatchCategory(models.IntegerChoices): return 1 else: return 3 + + +class OnlineRegistrationStatus(models.IntegerChoices): + OPEN = 1, 'Open' + NOT_ENABLED = 2, 'Not Enabled' + NOT_STARTED = 3, 'Not Started' + ENDED = 4, 'Ended' + REGISTRATION_FULL = 5, 'Registration Full' + WAITING_LIST_POSSIBLE = 6, 'Waiting List Possible' + WAITING_LIST_FULL = 7, 'Waiting List Full' + IN_PROGRESS = 8, 'In Progress' + ENDED_WITH_RESULTS = 9, 'Ended with Results' + + def status_localized(self) -> str: + status_map = { + OnlineRegistrationStatus.OPEN: "Inscription ouverte", + OnlineRegistrationStatus.NOT_ENABLED: "Inscription désactivée", + OnlineRegistrationStatus.NOT_STARTED: "Inscription pas encore ouverte", + OnlineRegistrationStatus.ENDED: "Inscription terminée", + OnlineRegistrationStatus.REGISTRATION_FULL: "Inscription complète", + OnlineRegistrationStatus.WAITING_LIST_POSSIBLE: "Liste d'attente disponible", + OnlineRegistrationStatus.WAITING_LIST_FULL: "Liste d'attente complète", + OnlineRegistrationStatus.IN_PROGRESS: "Tournoi en cours", + OnlineRegistrationStatus.ENDED_WITH_RESULTS: "Tournoi terminé" + } + return status_map.get(self, "") diff --git a/tournaments/models/player_registration.py b/tournaments/models/player_registration.py index 7e9e6ec..5b1007c 100644 --- a/tournaments/models/player_registration.py +++ b/tournaments/models/player_registration.py @@ -34,6 +34,7 @@ class PlayerRegistration(models.Model): source = models.IntegerField(choices=PlayerDataSource.choices, null=True, blank=True) has_arrived = models.BooleanField(default=False) captain = models.BooleanField(default=False) + coach = models.BooleanField(default=False) def __str__(self): return self.name() diff --git a/tournaments/models/team_registration.py b/tournaments/models/team_registration.py index 6c09558..af2774a 100644 --- a/tournaments/models/team_registration.py +++ b/tournaments/models/team_registration.py @@ -29,7 +29,8 @@ class TeamRegistration(models.Model): final_ranking = models.IntegerField(null=True, blank=True) points_earned = models.IntegerField(null=True, blank=True) - + unregistered = models.BooleanField(default=False) + unregistration_date = models.DateTimeField(null=True, blank=True) def __str__(self): if self.name: @@ -115,3 +116,6 @@ class TeamRegistration(models.Model): else: # print("no date") return None + + def out_of_tournament(self): + return self.walk_out or self.unregistered diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py index 12ca9d6..bb10fd8 100644 --- a/tournaments/models/tournament.py +++ b/tournaments/models/tournament.py @@ -5,7 +5,7 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from tournaments.models import group_stage -from . import Event, TournamentPayment, FederalMatchCategory, FederalCategory, FederalLevelCategory, FederalAgeCategory +from . import Event, TournamentPayment, FederalMatchCategory, FederalCategory, FederalLevelCategory, FederalAgeCategory, OnlineRegistrationStatus import uuid from django.utils import timezone, formats from datetime import datetime, timedelta @@ -219,12 +219,19 @@ class Tournament(models.Model): return f"{len(teams)} {word}" else: return None + + registration_status = None + if self.online_register_is_enabled() is True: + registration_status = self.get_online_registration_status().status_localized() if teams is not None and len(teams) > 0: word = "inscription" if len(teams) > 1: word = word + "s" - return f"{len(teams)} {word}" + if registration_status is not None: + return f"{registration_status}\n{len(teams)} {word}" else: + if registration_status is not None: + return f"{registration_status}" return None def name_and_event(self): @@ -277,6 +284,7 @@ class Tournament(models.Model): def rankings(self): rankings = [] for team_registration in self.teamregistration_set.all(): + if team_registration.walk_out is False and team_registration.final_ranking is not None: names = team_registration.team_names() ranking = team_registration.final_ranking @@ -309,8 +317,7 @@ class Tournament(models.Model): if team_registration.registration_date is None: is_valid = True # print(f"Is valid: {is_valid}") - - if team_registration.walk_out is False: + if team_registration.out_of_tournament() is False: team = TeamItem(team_registration) # print(f"Created team: {team}") if team_registration.group_stage_position is not None: @@ -880,28 +887,117 @@ class Tournament(models.Model): return False return True + def options_online_registration(self): + options = [] + + # Date d'ouverture + if self.opening_registration_date: + date = formats.date_format(self.opening_registration_date, format='j F Y H:i') + options.append(f"Ouverture des inscriptions le {date}") + + # Date limite + if self.registration_date_limit: + date = formats.date_format(self.registration_date_limit, format='j F Y H:i') + options.append(f"Clôture des inscriptions le {date}") + + # Cible d'équipes + if self.target_team_count: + options.append(f"Maximum {self.target_team_count} équipes") + + # Liste d'attente + if self.waiting_list_limit: + options.append(f"Liste d'attente limitée à {self.waiting_list_limit} équipes") + + # Options d'inscription + if self.account_is_required: + options.append("Compte requis") + if self.license_is_required: + options.append("Licence requise") + + # Joueurs par équipe + min_players = self.minimum_player_per_team + max_players = self.maximum_player_per_team + if min_players == max_players: + options.append(f"{min_players} joueurs par équipe") + else: + options.append(f"Entre {min_players} et {max_players} joueurs par équipe") + + return options + def online_register_is_enabled(self): if self.supposedly_in_progress(): return False if self.end_date is not None: return False - now = datetime.now() + now = timezone.now() + # Check if online registration is enabled if not self.enable_online_registration: return False # Check opening registration date - if self.opening_registration_date is not None and now < self.opening_registration_date: - return False + if self.opening_registration_date is not None: + timezoned_datetime = timezone.localtime(self.opening_registration_date) + if now < timezoned_datetime: + return False # Check registration date limit - if self.registration_date_limit is not None and now > self.registration_date_limit: - return False + if self.registration_date_limit is not None: + timezoned_datetime = timezone.localtime(self.registration_date_limit) + if now > timezoned_datetime: + return False - # All conditions are satisfied + # Check target team count and waiting list limit + if self.target_team_count is not None: + current_team_count = len([tr for tr in self.teamregistration_set.all() if tr.out_of_tournament() is False]) + if current_team_count >= self.target_team_count: + if self.waiting_list_limit is not None: + waiting_list_count = current_team_count - self.target_team_count + if waiting_list_count >= self.waiting_list_limit: + return False return True + def get_online_registration_status(self): + if self.supposedly_in_progress(): + return OnlineRegistrationStatus.IN_PROGRESS + if self.end_date is not None: + return OnlineRegistrationStatus.ENDED_WITH_RESULTS + + now = timezone.now() + + if self.opening_registration_date is not None: + timezoned_datetime = timezone.localtime(self.opening_registration_date) + if now < timezoned_datetime: + return OnlineRegistrationStatus.NOT_STARTED + + if self.registration_date_limit is not None: + timezoned_datetime = timezone.localtime(self.registration_date_limit) + if now > timezoned_datetime: + return OnlineRegistrationStatus.ENDED + + if self.target_team_count is not None: + # Get all team registrations excluding walk_outs + current_team_count = len([tr for tr in self.teamregistration_set.all() if tr.out_of_tournament() is False]) + if current_team_count >= self.target_team_count: + if self.waiting_list_limit is not None: + waiting_list_count = current_team_count - self.target_team_count + if waiting_list_count >= self.waiting_list_limit: + return OnlineRegistrationStatus.WAITING_LIST_FULL + return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE + return OnlineRegistrationStatus.REGISTRATION_FULL + current_team_count = self.teamregistration_set.filter(walk_out=False).count() + if current_team_count >= self.target_team_count: + if self.waiting_list_limit is not None: + waiting_list_count = current_team_count - self.target_team_count + if waiting_list_count >= self.waiting_list_limit: + return OnlineRegistrationStatus.WAITING_LIST_FULL + return OnlineRegistrationStatus.WAITING_LIST_POSSIBLE + return OnlineRegistrationStatus.REGISTRATION_FULL + + return OnlineRegistrationStatus.OPEN + + class MatchGroup: def __init__(self, name, matches, formatted_schedule): self.name = name diff --git a/tournaments/templates/tournaments/tournament_info.html b/tournaments/templates/tournaments/tournament_info.html index 5beae08..40e7516 100644 --- a/tournaments/templates/tournaments/tournament_info.html +++ b/tournaments/templates/tournaments/tournament_info.html @@ -48,23 +48,37 @@ {% if tournament.online_register_is_enabled %}
-
+
-
@@ -114,7 +128,7 @@