post merge main

timetoconfirm
Raz 8 months ago
commit 37748596c3
  1. 18
      tournaments/migrations/0113_tournament_team_count_limit.py
  2. 6
      tournaments/migrations/0114_playerregistration_payment_status_and_more.py
  3. 3
      tournaments/models/match.py
  4. 12
      tournaments/models/round.py
  5. 38
      tournaments/models/tournament.py
  6. 3
      tournaments/services/email_service.py
  7. 20
      tournaments/signals.py
  8. 24
      tournaments/templates/register_tournament.html
  9. 2
      tournaments/templates/tournaments/matches.html

@ -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),
),
]

@ -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 from django.db import migrations, models
@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('tournaments', '0112_tournament_disable_ranking_federal_ruling_and_more'), ('tournaments', '0113_tournament_team_count_limit'),
] ]
operations = [ operations = [
@ -18,7 +18,7 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='playerregistration', model_name='playerregistration',
name='registration_status', 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( migrations.AddField(
model_name='playerregistration', model_name='playerregistration',

@ -59,7 +59,8 @@ class Match(SideStoreModel):
def court_name(self, index): def court_name(self, index):
club = None club = None
if self.tournament().event: tournament = self.tournament()
if tournament and tournament.event:
club = self.tournament().event.club club = self.tournament().event.club
if club: if club:

@ -47,13 +47,19 @@ class Round(SideStoreModel):
if self.index == 0: if self.index == 0:
return "Finale" return "Finale"
elif self.index == 1: elif self.index == 1:
return "Demis" return "Demie"
elif self.index == 2: elif self.index == 2:
return "Quarts" return "Quart"
else: else:
squared = 2 ** self.index squared = 2 ** self.index
return f"{squared}ème" 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): def ranking_matches(self, hide_empty_matches):
matches = [] matches = []
for child in self.children.all(): for child in self.children.all():
@ -165,7 +171,7 @@ class Round(SideStoreModel):
if first_half_matches: if first_half_matches:
name = self.name() name = self.plural_name()
if parent_round and first_half_matches[0].name is not None: if parent_round and first_half_matches[0].name is not None:
name = first_half_matches[0].name name = first_half_matches[0].name
match_group = self.tournament.create_match_group( match_group = self.tournament.create_match_group(

@ -67,6 +67,7 @@ class Tournament(BaseModel):
initial_seed_round = models.IntegerField(default=0) initial_seed_round = models.IntegerField(default=0)
initial_seed_count = models.IntegerField(default=0) initial_seed_count = models.IntegerField(default=0)
enable_online_registration = models.BooleanField(default=False) # Equivalent to Bool = false 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 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 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 waiting_list_limit = models.IntegerField(null=True, blank=True) # Equivalent to Int? = nil
@ -534,7 +535,7 @@ class Tournament(BaseModel):
if round and matches: if round and matches:
matches.sort(key=lambda m: m.index) 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) groups.append(group)
ranking_matches = round.ranking_matches(hide_empty_matches) ranking_matches = round.ranking_matches(hide_empty_matches)
@ -1039,7 +1040,7 @@ class Tournament(BaseModel):
return plural_format("jour", self.day_duration) return plural_format("jour", self.day_duration)
def has_club_address(self): def has_club_address(self):
if self.event.club: if self.event and self.event.club:
return self.event.club.has_address() return self.event.club.has_address()
else: else:
return False return False
@ -1052,21 +1053,22 @@ class Tournament(BaseModel):
def options_online_registration(self): def options_online_registration(self):
options = [] options = []
timezone = self.timezone()
# Date d'ouverture # Date d'ouverture
if self.opening_registration_date: 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}") options.append(f"Ouverture des inscriptions le {date}")
# Date limite # Date limite
if self.registration_date_limit: 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(f"Clôture des inscriptions le {date}")
options.append(self.get_selection_status_localized) options.append(self.get_selection_status_localized)
# Cible d'équipes # Cible d'équipes
if self.team_count: if self.team_count_limit is True:
options.append(f"Maximum {self.team_count} équipes") options.append(f"Maximum {self.team_count} équipes")
# Liste d'attente # Liste d'attente
@ -1154,7 +1156,7 @@ class Tournament(BaseModel):
if self.team_sorting == TeamSortingType.RANK: if self.team_sorting == TeamSortingType.RANK:
return OnlineRegistrationStatus.OPEN return OnlineRegistrationStatus.OPEN
if self.team_count is not None: if self.team_count_limit is True:
# Get all team registrations excluding walk_outs # Get all team registrations excluding walk_outs
current_team_count = self.team_registrations.exclude(walk_out=True).count() current_team_count = self.team_registrations.exclude(walk_out=True).count()
if current_team_count >= self.team_count: if current_team_count >= self.team_count:
@ -1187,16 +1189,13 @@ class Tournament(BaseModel):
def get_waiting_list_position(self): def get_waiting_list_position(self):
current_time = timezone.now() current_time = timezone.now()
current_time = current_time.astimezone(self.timezone())
local_registration_federal_limit = self.local_registration_federal_limit() local_registration_federal_limit = self.local_registration_federal_limit()
if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None: if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None:
if current_time < local_registration_federal_limit: if current_time < local_registration_federal_limit:
return -1 return -1
else:
return 0
# If no target team count exists, no one goes to waiting list # 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 return -1
# Get count of active teams (not walked out) # Get count of active teams (not walked out)
@ -1278,7 +1277,6 @@ class Tournament(BaseModel):
current_year += 1 current_year += 1
user_age = current_year - int(birth_year) user_age = current_year - int(birth_year)
print("user_age", user_age)
# Check age category restrictions # Check age category restrictions
if self.federal_age_category == FederalAgeCategory.A11_12 and user_age > 12: 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) return FederalLevelCategory.min_player_rank(self.federal_level_category, self.federal_category, self.federal_age_category)
def local_registration_federal_limit(self): def local_registration_federal_limit(self):
timezone = self.timezone()
if self.registration_date_limit is not None: 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: 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() local_start_date = self.local_start_date()
@ -1335,11 +1334,9 @@ class Tournament(BaseModel):
def waiting_list_teams(self, teams): def waiting_list_teams(self, teams):
current_time = timezone.now() current_time = timezone.now()
current_time = current_time.astimezone(self.timezone())
local_registration_federal_limit = self.local_registration_federal_limit() local_registration_federal_limit = self.local_registration_federal_limit()
if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None: if self.team_sorting == TeamSortingType.RANK and local_registration_federal_limit is not None:
if current_time < local_registration_federal_limit: if current_time < local_registration_federal_limit:
print("current_time < local_registration_federal_limit")
return None return None
if len(teams)<=self.team_count: if len(teams)<=self.team_count:
@ -1349,7 +1346,6 @@ class Tournament(BaseModel):
def first_waiting_list_team(self, teams): def first_waiting_list_team(self, teams):
waiting_list_team = self.waiting_list_teams(teams) waiting_list_team = self.waiting_list_teams(teams)
print("waiting_list_team", waiting_list_team)
if waiting_list_team is None: if waiting_list_team is None:
return None return None
if len(waiting_list_team) > 0: if len(waiting_list_team) > 0:
@ -1476,21 +1472,21 @@ class Tournament(BaseModel):
else: else:
return True return True
def umpire_contact(self): def umpire_contact(self):
if self.umpire_custom_contact is not None: if self.umpire_custom_contact is not None:
print(self.umpire_custom_contact)
return 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): def umpire_mail(self):
if self.umpire_custom_mail is not None: if self.umpire_custom_mail is not None:
print(self.umpire_custom_mail)
return self.umpire_custom_mail return self.umpire_custom_mail
return self.event.creator.email return self.event.creator.email
def umpire_phone(self): def umpire_phone(self):
if self.umpire_custom_phone is not None: if self.umpire_custom_phone is not None:
print(self.umpire_custom_phone)
return self.umpire_custom_phone return self.umpire_custom_phone
return self.event.creator.phone return self.event.creator.phone

@ -340,7 +340,8 @@ class TournamentEmailService:
def _format_umpire_contact(tournament): def _format_umpire_contact(tournament):
contact_parts = [] contact_parts = []
creator_full_name = tournament.umpire_contact() 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: if not tournament.hide_umpire_mail:
creator_email = tournament.umpire_mail() creator_email = tournament.umpire_mail()

@ -117,21 +117,17 @@ def check_waiting_list(sender, instance, **kwargs):
teams_out_to_warn = [] teams_out_to_warn = []
teams_in_to_warn = [] teams_in_to_warn = []
previous_state_teams = previous_state.teams(True)
if previous_state.team_count > instance.team_count: if previous_state.team_count > instance.team_count:
teams_to_remove_count = previous_state.team_count - instance.team_count teams_that_will_be_out = instance.teams(True)[instance.team_count:]
sorted_teams = sorted( teams_out_to_warn = [
[team for team in previous_state_teams if team.stage != "Attente" and not (team.wildcard_bracket or team.wildcard_groupstage)], team for team in teams_that_will_be_out
key=lambda t: ( if team.stage != "Attente"
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:]
elif previous_state.team_count < instance.team_count: 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 = [ 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" if team.stage == "Attente"
] ]

@ -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. 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.
</p> </p>
{% else %} {% else %}
{% if team_form.errors %}
<div class="alert alert-error">
{% if team_form.non_field_errors %}
{% for error in team_form.non_field_errors %}
<p>{{ error }}</p>
{% endfor %}
{% endif %}
{% for field in team_form %}
{% for error in field.errors %}
<p>{{ error }}</p>
{% endfor %}
{% endfor %}
</div>
{% endif %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}
@ -109,15 +125,15 @@
{% endif %} {% endif %}
<div class="margin10"> <div class="margin10">
{% if form.errors %} {% if add_player_form.errors %}
<div class="alert alert-error"> <div class="alert alert-error">
{% if form.non_field_errors %} {% if add_player_form.non_field_errors %}
{% for error in form.non_field_errors %} {% for error in add_player_form.non_field_errors %}
<p>{{ error }}</p> <p>{{ error }}</p>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% for field in form %} {% for field in add_player_form %}
{% for error in field.errors %} {% for error in field.errors %}
<p>{{ error }}</p> <p>{{ error }}</p>
{% endfor %} {% endfor %}

@ -21,7 +21,7 @@
{% endif %} {% endif %}
{% if tournament.display_matches %} {% if tournament.display_matches %}
{% for round in rounds %} {% for round in rounds %}
<a href="{% url 'tournament' tournament.id %}?round={{ round.id }}" class="mybox topmargin5">{{ round.name }}</a> <a href="{% url 'tournament' tournament.id %}?round={{ round.id }}" class="mybox topmargin5">{{ round.plural_name }}</a>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
</nav> </nav>

Loading…
Cancel
Save