diff --git a/tournaments/migrations/0113_tournament_team_count_limit.py b/tournaments/migrations/0113_tournament_team_count_limit.py new file mode 100644 index 0000000..2b113cb --- /dev/null +++ b/tournaments/migrations/0113_tournament_team_count_limit.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1 on 2025-03-29 08:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tournaments', '0112_tournament_disable_ranking_federal_ruling_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='tournament', + name='team_count_limit', + field=models.BooleanField(default=True), + ), + ] diff --git a/tournaments/migrations/0113_playerregistration_payment_status_and_more.py b/tournaments/migrations/0114_playerregistration_payment_status_and_more.py similarity index 69% rename from tournaments/migrations/0113_playerregistration_payment_status_and_more.py rename to tournaments/migrations/0114_playerregistration_payment_status_and_more.py index edd28b1..92fcaf2 100644 --- a/tournaments/migrations/0113_playerregistration_payment_status_and_more.py +++ b/tournaments/migrations/0114_playerregistration_payment_status_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1 on 2025-03-28 07:54 +# Generated by Django 5.1 on 2025-03-29 14:28 from django.db import migrations, models @@ -6,7 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('tournaments', '0112_tournament_disable_ranking_federal_ruling_and_more'), + ('tournaments', '0113_tournament_team_count_limit'), ] operations = [ @@ -18,7 +18,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='playerregistration', name='registration_status', - field=models.CharField(choices=[('PENDING', 'Pending'), ('PAID', 'Paid'), ('CANCELED', 'Canceled')], default='PENDING', max_length=20), + field=models.CharField(choices=[('WAITING', 'Waiting'), ('PENDING', 'Pending'), ('CONFIRMED', 'Confirmed'), ('PAID', 'Paid'), ('CANCELED', 'Canceled')], default='WAITING', max_length=20), ), migrations.AddField( model_name='playerregistration', diff --git a/tournaments/models/match.py b/tournaments/models/match.py index 15194b8..302bf17 100644 --- a/tournaments/models/match.py +++ b/tournaments/models/match.py @@ -59,7 +59,8 @@ class Match(SideStoreModel): def court_name(self, index): club = None - if self.tournament().event: + tournament = self.tournament() + if tournament and tournament.event: club = self.tournament().event.club if club: diff --git a/tournaments/models/round.py b/tournaments/models/round.py index 35d1815..6d89a8c 100644 --- a/tournaments/models/round.py +++ b/tournaments/models/round.py @@ -47,13 +47,19 @@ class Round(SideStoreModel): if self.index == 0: return "Finale" elif self.index == 1: - return "Demis" + return "Demie" elif self.index == 2: - return "Quarts" + return "Quart" else: squared = 2 ** self.index return f"{squared}ème" + def plural_name(self): + name = self.name() + if self.parent is None and self.index > 0: + return f'{name}s' + return name + def ranking_matches(self, hide_empty_matches): matches = [] for child in self.children.all(): @@ -165,7 +171,7 @@ class Round(SideStoreModel): if first_half_matches: - name = self.name() + name = self.plural_name() if parent_round and first_half_matches[0].name is not None: name = first_half_matches[0].name match_group = self.tournament.create_match_group( diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py index 8da031e..7710f75 100644 --- a/tournaments/models/tournament.py +++ b/tournaments/models/tournament.py @@ -67,6 +67,7 @@ class Tournament(BaseModel): initial_seed_round = models.IntegerField(default=0) initial_seed_count = models.IntegerField(default=0) enable_online_registration = models.BooleanField(default=False) # Equivalent to Bool = false + team_count_limit = models.BooleanField(default=True) registration_date_limit = models.DateTimeField(null=True, blank=True) # Equivalent to Date? = nil opening_registration_date = models.DateTimeField(null=True, blank=True) # Equivalent to Date? = nil waiting_list_limit = models.IntegerField(null=True, blank=True) # Equivalent to Int? = nil @@ -534,7 +535,7 @@ class Tournament(BaseModel): if round and matches: matches.sort(key=lambda m: m.index) - group = self.create_match_group(round.name(), matches) + group = self.create_match_group(round.plural_name(), matches) groups.append(group) ranking_matches = round.ranking_matches(hide_empty_matches) @@ -1039,7 +1040,7 @@ class Tournament(BaseModel): return plural_format("jour", self.day_duration) def has_club_address(self): - if self.event.club: + if self.event and self.event.club: return self.event.club.has_address() else: return False @@ -1052,21 +1053,22 @@ class Tournament(BaseModel): def options_online_registration(self): options = [] + timezone = self.timezone() # Date d'ouverture if self.opening_registration_date: - date = formats.date_format(timezone.localtime(self.opening_registration_date), format='j F Y H:i') + date = formats.date_format(self.opening_registration_date.astimezone(timezone), 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(timezone.localtime(self.registration_date_limit), format='j F Y H:i') + date = formats.date_format(self.registration_date_limit.astimezone(timezone), format='j F Y H:i') options.append(f"Clôture des inscriptions le {date}") options.append(self.get_selection_status_localized) # Cible d'équipes - if self.team_count: + if self.team_count_limit is True: options.append(f"Maximum {self.team_count} équipes") # Liste d'attente @@ -1154,7 +1156,7 @@ class Tournament(BaseModel): if self.team_sorting == TeamSortingType.RANK: return OnlineRegistrationStatus.OPEN - if self.team_count is not None: + if self.team_count_limit is True: # Get all team registrations excluding walk_outs current_team_count = self.team_registrations.exclude(walk_out=True).count() if current_team_count >= self.team_count: @@ -1187,16 +1189,13 @@ class Tournament(BaseModel): def get_waiting_list_position(self): current_time = timezone.now() - current_time = current_time.astimezone(self.timezone()) local_registration_federal_limit = self.local_registration_federal_limit() if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None: if current_time < local_registration_federal_limit: return -1 - else: - return 0 # If no target team count exists, no one goes to waiting list - if self.team_count is None: + if self.team_count_limit is False: return -1 # Get count of active teams (not walked out) @@ -1278,7 +1277,6 @@ class Tournament(BaseModel): current_year += 1 user_age = current_year - int(birth_year) - print("user_age", user_age) # Check age category restrictions if self.federal_age_category == FederalAgeCategory.A11_12 and user_age > 12: @@ -1312,11 +1310,12 @@ class Tournament(BaseModel): return FederalLevelCategory.min_player_rank(self.federal_level_category, self.federal_category, self.federal_age_category) def local_registration_federal_limit(self): + timezone = self.timezone() if self.registration_date_limit is not None: - return self.registration_date_limit + return self.registration_date_limit.astimezone(timezone) if self.closed_registration_date is not None: - return self.closed_registration_date + return self.closed_registration_date.astimezone(timezone) local_start_date = self.local_start_date() @@ -1335,11 +1334,9 @@ class Tournament(BaseModel): def waiting_list_teams(self, teams): current_time = timezone.now() - current_time = current_time.astimezone(self.timezone()) local_registration_federal_limit = self.local_registration_federal_limit() if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None: if current_time < local_registration_federal_limit: - print("current_time < local_registration_federal_limit") return None if len(teams)<=self.team_count: @@ -1349,7 +1346,6 @@ class Tournament(BaseModel): def first_waiting_list_team(self, teams): waiting_list_team = self.waiting_list_teams(teams) - print("waiting_list_team", waiting_list_team) if waiting_list_team is None: return None if len(waiting_list_team) > 0: @@ -1476,21 +1472,21 @@ class Tournament(BaseModel): else: return True - def umpire_contact(self): + def umpire_contact(self): if self.umpire_custom_contact is not None: - print(self.umpire_custom_contact) return self.umpire_custom_contact - return self.event.creator.full_name() + if self.event and self.event.creator: + return self.event.creator.full_name() + else: + return None def umpire_mail(self): if self.umpire_custom_mail is not None: - print(self.umpire_custom_mail) return self.umpire_custom_mail return self.event.creator.email def umpire_phone(self): if self.umpire_custom_phone is not None: - print(self.umpire_custom_phone) return self.umpire_custom_phone return self.event.creator.phone diff --git a/tournaments/services/email_service.py b/tournaments/services/email_service.py index fa4ba04..3d14cf9 100644 --- a/tournaments/services/email_service.py +++ b/tournaments/services/email_service.py @@ -340,7 +340,8 @@ class TournamentEmailService: def _format_umpire_contact(tournament): contact_parts = [] creator_full_name = tournament.umpire_contact() - contact_parts.append(creator_full_name) + if creator_full_name: + contact_parts.append(creator_full_name) if not tournament.hide_umpire_mail: creator_email = tournament.umpire_mail() diff --git a/tournaments/signals.py b/tournaments/signals.py index 8950193..bc0f33c 100644 --- a/tournaments/signals.py +++ b/tournaments/signals.py @@ -117,21 +117,17 @@ 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_to_remove_count = previous_state.team_count - instance.team_count - sorted_teams = sorted( - [team for team in previous_state_teams if team.stage != "Attente" and not (team.wildcard_bracket or team.wildcard_groupstage)], - key=lambda t: ( - t.registration_date is None, t.registration_date or datetime.min, t.initial_weight, t.team_registration.id - ) if previous_state.team_sorting == TeamSortingType.INSCRIPTION_DATE else - (t.initial_weight, t.team_registration.id) - ) - teams_out_to_warn = sorted_teams[-teams_to_remove_count:] + teams_that_will_be_out = instance.teams(True)[instance.team_count:] + teams_out_to_warn = [ + team for team in teams_that_will_be_out + if team.stage != "Attente" + ] elif previous_state.team_count < instance.team_count: - slice_start = instance.team_count - previous_state.team_count + teams_that_will_be_in = previous_state.teams(True)[previous_state.team_count:instance.team_count] teams_in_to_warn = [ - team for team in previous_state_teams[slice_start:] + 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 59f9d6d..c8349d1 100644 --- a/tournaments/templates/register_tournament.html +++ b/tournaments/templates/register_tournament.html @@ -26,6 +26,22 @@ 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 team_form.errors %} +
+ {% if team_form.non_field_errors %} + {% for error in team_form.non_field_errors %} +

{{ error }}

+ {% endfor %} + {% endif %} + + {% for field in team_form %} + {% for error in field.errors %} +

{{ error }}

+ {% endfor %} + {% endfor %} +
+ {% endif %}
{% csrf_token %} @@ -109,15 +125,15 @@ {% endif %}
- {% if form.errors %} + {% if add_player_form.errors %}
- {% if form.non_field_errors %} - {% for error in form.non_field_errors %} + {% if add_player_form.non_field_errors %} + {% for error in add_player_form.non_field_errors %}

{{ error }}

{% endfor %} {% endif %} - {% for field in form %} + {% for field in add_player_form %} {% for error in field.errors %}

{{ error }}

{% endfor %} diff --git a/tournaments/templates/tournaments/matches.html b/tournaments/templates/tournaments/matches.html index 90bdb5e..915e48e 100644 --- a/tournaments/templates/tournaments/matches.html +++ b/tournaments/templates/tournaments/matches.html @@ -21,7 +21,7 @@ {% endif %} {% if tournament.display_matches %} {% for round in rounds %} - {{ round.name }} + {{ round.plural_name }} {% endfor %} {% endif %}