timetoconfirm
Raz 7 months ago
parent a19afb2299
commit 3f95477066
  1. 2
      tournaments/models/__init__.py
  2. 92
      tournaments/models/team_registration.py
  3. 52
      tournaments/models/tournament.py
  4. 89
      tournaments/tasks.py
  5. 18
      tournaments/templates/tournaments/tournament_info.html
  6. 11
      tournaments/views.py

@ -4,7 +4,7 @@ from .custom_user import CustomUser
from .club import Club
from .court import Court
from .date_interval import DateInterval
from .enums import UserOrigin, TournamentPayment, FederalCategory, FederalLevelCategory, FederalAgeCategory, FederalMatchCategory, OnlineRegistrationStatus, ModelOperation
from .enums import UserOrigin, TournamentPayment, FederalCategory, FederalLevelCategory, FederalAgeCategory, FederalMatchCategory, OnlineRegistrationStatus, RegistrationStatus, ModelOperation
from .player_enums import PlayerSexType, PlayerDataSource, PlayerPaymentType
from .event import Event
from .tournament import Tournament, TeamSummon, TeamSortingType, TeamItem

@ -4,6 +4,7 @@ import uuid
from django.utils import timezone
from .enums import RegistrationStatus
from .player_enums import PlayerPaymentType
from ..services.email_service import TournamentEmailService, TeamEmailType
class TeamRegistration(SideStoreModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
@ -407,3 +408,94 @@ class TeamRegistration(SideStoreModel):
return self.tournament.team_fee()
elif status == 'MIXED':
return self.tournament.player_fee()
def is_confirmation_expired(self):
"""
Check if the confirmation deadline has expired.
Returns:
bool: True if expired, False if still valid or no deadline exists
"""
deadline = self.get_confirmation_deadline()
if not deadline:
return False
current_time = timezone.now()
return deadline < current_time
def format_confirmation_deadline(self):
"""
Format the confirmation deadline in a human-readable format.
Returns:
str: Formatted deadline, or None if no deadline exists
"""
deadline = self.get_confirmation_deadline()
if not deadline:
return None
if self.tournament and self.tournament.timezone():
deadline = deadline.astimezone(self.tournament.timezone())
return deadline.strftime("%d/%m/%Y à %H:%M")
def check_confirmation_deadline(self, tournament_context=None):
"""
Check if the confirmation deadline for this team has expired and perform necessary actions.
Args:
tournament_context (dict, optional): Pre-calculated tournament context to avoid redundant calls.
If None, will calculate on-demand.
"""
now = timezone.now()
tournament = self.tournament
if not tournament:
return
# Use provided context or calculate if not provided
if tournament_context is None:
teams = tournament.teams(True)
waiting_list_teams = tournament.waiting_list_teams(teams)
ttc = tournament.calculate_time_to_confirm(len(waiting_list_teams)) if waiting_list_teams is not None else None
first_waiting_list_team = tournament.first_waiting_list_team(teams)
is_online_registration_irrevelant = tournament.is_online_registration_irrevelant()
else:
ttc = tournament_context.get('ttc')
first_waiting_list_team = tournament_context.get('first_waiting_list_team')
is_online_registration_irrevelant = tournament_context.get('is_online_registration_irrevelant', False)
# Get all players in this team
team_players = self.player_registrations.filter(registered_online=True)
should_update_team = False
should_send_mail = False
for team_player in team_players:
if is_online_registration_irrevelant:
team_player.registration_status = RegistrationStatus.CANCELED
team_player.save()
elif team_player.time_to_confirm is None and first_waiting_list_team is not None:
self.set_time_to_confirm(ttc)
should_send_mail = True
print(team_player, "team_player.time_to_confirm is None and", ttc)
elif team_player.time_to_confirm is not None and now > team_player.time_to_confirm:
if first_waiting_list_team is not None:
team_player.registration_status = RegistrationStatus.CANCELED
self.registration_date = now
should_update_team = True
team_player.time_to_confirm = None
team_player.save()
print(team_player, "time_to_confirm = ", team_player.time_to_confirm)
if should_update_team:
self.save()
print(f"Team {self} confirmation expired in tournament {tournament.id}")
if should_send_mail:
TournamentEmailService.notify_team(
self,
tournament,
TeamEmailType.REQUIRES_TIME_CONFIRMATION
)

@ -1,6 +1,7 @@
from zoneinfo import ZoneInfo
from django.db import models
from . import BaseModel, Event, TournamentPayment, FederalMatchCategory, FederalCategory, FederalLevelCategory, FederalAgeCategory, OnlineRegistrationStatus
from . import BaseModel, Event, TournamentPayment, FederalMatchCategory, FederalCategory, FederalLevelCategory, FederalAgeCategory, OnlineRegistrationStatus, RegistrationStatus
import uuid
from django.utils import timezone, formats
from datetime import datetime, timedelta, time
@ -1812,6 +1813,55 @@ class Tournament(BaseModel):
"""Get the commission rate for this tournament, falling back to the umpire default if not set"""
return 1.00 # Fallback default
def check_all_confirmation_deadlines(self):
"""
Check all confirmation deadlines for teams in this tournament.
Send notification emails as needed.
Returns:
int: Number of teams processed
"""
# Calculate these values once for the tournament
teams = self.teams(True)
waiting_list_teams = self.waiting_list_teams(teams)
ttc = self.calculate_time_to_confirm(len(waiting_list_teams)) if waiting_list_teams is not None else None
first_waiting_list_team = self.first_waiting_list_team(teams)
# Tournament context dict to pass to each team check
tournament_context = {
'ttc': ttc,
'first_waiting_list_team': first_waiting_list_team,
'is_online_registration_irrevelant': self.is_online_registration_irrevelant()
}
# Find players with expired confirmation deadlines in this tournament
PlayerRegistration = apps.get_model('tournaments', 'PlayerRegistration')
expired_confirmations = PlayerRegistration.objects.filter(
registration_status=RegistrationStatus.PENDING,
registered_online=True,
team_registration__tournament=self
).select_related('team_registration')
processed_teams = set() # To avoid processing the same team multiple times
teams_processed = 0
for player in expired_confirmations:
team_registration = player.team_registration
# Skip if we've already processed this team
if team_registration.id in processed_teams:
continue
processed_teams.add(team_registration.id)
teams_processed += 1
# Process in a transaction to ensure atomic operations
team_registration.check_confirmation_deadline(tournament_context)
return teams_processed
class MatchGroup:
def __init__(self, name, matches, formatted_schedule, round_id=None):

@ -3,9 +3,8 @@ from django.utils import timezone
from django.db import transaction
from django.conf import settings
from .models import PlayerRegistration
from .models import Tournament
from .models.enums import RegistrationStatus
from .services.email_service import TournamentEmailService, TeamEmailType
@background(schedule=settings.BACKGROUND_SCHEDULED_TASK_INTERVAL * 60) # Run every 30 minutes (30*60 seconds)
def background_task_check_confirmation_deadlines():
@ -21,81 +20,15 @@ def check_confirmation_deadlines():
now = timezone.now()
print(f"[{now}] Running confirmation deadline check...")
# Find players with expired confirmation deadlines
expired_confirmations = PlayerRegistration.objects.filter(
registration_status=RegistrationStatus.PENDING,
registered_online=True,
team_registration__isnull=False
).select_related('team_registration', 'team_registration__tournament')
# Get all tournaments with online registrations
tournaments = Tournament.objects.filter(
team_registrations__player_registrations__registration_status=RegistrationStatus.PENDING,
team_registrations__player_registrations__registered_online=True
).distinct()
print(f"Found {expired_confirmations.count()} expired confirmations")
total_processed = 0
for tournament in tournaments:
processed = tournament.check_all_confirmation_deadlines()
total_processed += processed
# Process each expired confirmation
processed_teams = set() # To avoid processing the same team multiple times
for player in expired_confirmations:
team_registration = player.team_registration
# Skip if we've already processed this team
if team_registration.id in processed_teams:
continue
processed_teams.add(team_registration.id)
tournament = team_registration.tournament
if not tournament:
continue
teams = tournament.teams(True)
waiting_list_teams = tournament.waiting_list_teams(teams)
if waiting_list_teams is not None:
ttc = tournament.calculate_time_to_confirm(len(waiting_list_teams))
else:
ttc = None
first_waiting_list_team = tournament.first_waiting_list_team(teams)
# Process in a transaction to ensure atomic operations
with transaction.atomic():
# Get all players in this team and mark them as expired
team_players = PlayerRegistration.objects.filter(
team_registration=team_registration,
registered_online=True
)
should_update_team = False
should_send_mail = False
is_online_registration_irrevelant = team_registration.tournament.is_online_registration_irrevelant()
for team_player in team_players:
if is_online_registration_irrevelant:
team_player.registration_status = RegistrationStatus.CANCELED
team_player.save()
elif team_player.time_to_confirm is None and first_waiting_list_team is not None:
team_registration.set_time_to_confirm(ttc)
team_player.save()
should_send_mail = True
print(team_player, "team_player.time_to_confirm is None and", ttc)
elif team_player.time_to_confirm is not None and now > team_player.time_to_confirm:
if first_waiting_list_team is not None:
team_player.registration_status = RegistrationStatus.CANCELED
team_registration.registration_date = now
should_update_team = True
team_player.time_to_confirm = None
team_player.save()
print(team_player, "time_to_confirm = ", team_player.time_to_confirm)
# elif team_player.time_to_confirm is not None and team_player.time_to_confirm > ttc:
# team_player.registration_status = RegistrationStatus.PENDING
# team_player.time_to_confirm = ttc
# team_player.save()
# should_update_team = True
if should_send_mail:
TournamentEmailService.notify_team(
team_registration,
tournament,
TeamEmailType.REQUIRES_TIME_CONFIRMATION
)
if should_update_team:
team_registration.save()
print(f"Team {team_registration} confirmation expired in tournament {tournament.id}")
print(f"Processed confirmation deadlines for {total_processed} teams")

@ -52,29 +52,19 @@
{% if team.needs_confirmation %}
<h4 class="semibold">Confirmation requise</h4>
<div>Une place dans le tournoi a été libérée !</div>
{% if tournament.should_request_payment and tournament.online_payment_is_mandatory %}
<div>Vous devez payer votre inscription pour confirmer votre participation.</div>
{% endif %}
{% if team.get_confirmation_deadline %}
{% timezone tournament.timezone %}
{% with time_to_confirm=team.get_confirmation_deadline %}
{% now "Y-m-d H:i:s" as current_time_str %}
{% if time_to_confirm %}
{% if time_to_confirm|date:"Y-m-d H:i:s" > current_time_str %}
<div>Vous devez confirmer votre participation avant le : </div>
<p class="semibold alert">{{ time_to_confirm|date:"d/m/Y à H:i" }}</p>
<p>Temps restant: <span class="countdown-timer">{{ time_to_confirm|timeuntil }}</span></p>
{% else %}
{% if team.is_confirmation_expired %}
<p class="alert alert-danger">
Le délai de confirmation est expiré. Votre place a été proposée à une autre équipe.
</p>
{% else %}
<div>Vous devez confirmer votre participation avant le : </div>
<p class="semibold alert">{{ team.format_confirmation_deadline }}</p>
{% endif %}
{% endif %}
{% endwith %}
{% endtimezone %}
{% endif %}
{% endif %}
{% if team.call_date %}

@ -1076,6 +1076,12 @@ def confirm_tournament_registration(request, tournament_id):
return redirect('tournament-info', tournament_id=tournament_id)
team_registration = team_registrations.first()
if team_registration.is_confirmation_expired():
team_registration.check_confirmation_deadline()
messages.error(request, "Le délai de confirmation est expiré. Vous ne pouvez plus confirmer votre participation.")
return redirect('tournament-info', tournament_id=tournament_id)
# Confirm registration
team_registration.confirm_registration()
@ -1094,6 +1100,11 @@ def proceed_to_payment(request, tournament_id):
messages.error(request, "Aucune inscription trouvée pour ce tournoi.")
return redirect('tournament-info', tournament_id=tournament_id)
if team.is_confirmation_expired():
team.check_confirmation_deadline()
messages.error(request, "Le délai de confirmation est expiré. Vous ne pouvez plus régler votre participation.")
return redirect('tournament-info', tournament_id=tournament_id)
if team.is_paid():
messages.info(request, "Votre inscription est déjà payée.")
return redirect('tournament-info', tournament_id=tournament_id)

Loading…
Cancel
Save