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. 34
      tournaments/models/tournament.py
  6. 1
      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
@ -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',

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

@ -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(

@ -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:
@ -1478,19 +1474,19 @@ class Tournament(BaseModel):
def umpire_contact(self):
if self.umpire_custom_contact is not None:
print(self.umpire_custom_contact)
return self.umpire_custom_contact
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

@ -340,6 +340,7 @@ class TournamentEmailService:
def _format_umpire_contact(tournament):
contact_parts = []
creator_full_name = tournament.umpire_contact()
if creator_full_name:
contact_parts.append(creator_full_name)
if not tournament.hide_umpire_mail:

@ -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"
]

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

@ -21,7 +21,7 @@
{% endif %}
{% if tournament.display_matches %}
{% 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 %}
{% endif %}
</nav>

Loading…
Cancel
Save