diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py index ff334c5..68c45e6 100644 --- a/tournaments/models/tournament.py +++ b/tournaments/models/tournament.py @@ -75,6 +75,7 @@ class Tournament(models.Model): minimum_player_per_team = models.IntegerField(default=2) maximum_player_per_team = models.IntegerField(default=2) information = models.CharField(max_length=4000, null=True, blank=True) + _being_deleted = False # Class attribute def __str__(self): if self.name: @@ -1093,12 +1094,17 @@ class Tournament(models.Model): def build_tournament_details_str(self): tournament_details = [] + name_str = self.build_name_details_str() + if self.federal_level_category > 0: tournament_details.append(self.level()) if self.category(): tournament_details.append(self.category()) if self.age(): tournament_details.append(self.age()) + if len(name_str) > 0: + tournament_details.append(name_str) + return " ".join(filter(None, tournament_details)) def build_name_details_str(self): @@ -1180,6 +1186,12 @@ class Tournament(models.Model): return waiting_teams[0].team_registration return None + + def delete(self, *args, **kwargs): + # Mark this tournament as being deleted + self._being_deleted = True + super().delete(*args, **kwargs) + class MatchGroup: def __init__(self, name, matches, formatted_schedule): self.name = name diff --git a/tournaments/services/email_service.py b/tournaments/services/email_service.py index 41e69bc..e64587c 100644 --- a/tournaments/services/email_service.py +++ b/tournaments/services/email_service.py @@ -17,11 +17,9 @@ class TournamentEmailService: @staticmethod def send_registration_confirmation(request, tournament, team_registration, waiting_list_position): tournament_details_str = tournament.build_tournament_details_str() - name_str = tournament.build_name_details_str() email_subject = TournamentEmailService._build_email_subject( tournament_details_str, - name_str, waiting_list_position ) @@ -30,7 +28,6 @@ class TournamentEmailService: tournament, team_registration, tournament_details_str, - name_str, waiting_list_position ) @@ -44,15 +41,14 @@ class TournamentEmailService: email.send() @staticmethod - def _build_email_subject(tournament_details_str, name_str, waiting_list_position): - base_subject = f"Confirmation d'inscription au tournoi {tournament_details_str} {name_str}" + def _build_email_subject(tournament_details_str, waiting_list_position): + base_subject = f"Confirmation d'inscription au tournoi {tournament_details_str}" if waiting_list_position >= 0: - base_subject = f"En liste d'attente du tournoi {tournament_details_str} {name_str}" + base_subject = f"En liste d'attente du tournoi {tournament_details_str}" return base_subject @staticmethod - def _build_email_body(request, tournament, team_registration, tournament_details_str, - name_str, waiting_list_position): + def _build_email_body(request, tournament, team_registration, tournament_details_str, waiting_list_position): inscription_date = team_registration.local_registration_date().strftime("%d/%m/%Y à %H:%M") team_members = [player.name() for player in team_registration.playerregistration_set.all()] team_members_str = " et ".join(team_members) @@ -61,9 +57,9 @@ class TournamentEmailService: body_parts.append("Bonjour,\n") if waiting_list_position >= 0: - body_parts.append(f"Votre inscription en liste d'attente du tournoi {tournament_details_str} {name_str} est confirmée.") + body_parts.append(f"Votre inscription en liste d'attente du tournoi {tournament_details_str} est confirmée.") else: - body_parts.append(f"Votre inscription au tournoi {tournament_details_str} {name_str} est confirmée.") + body_parts.append(f"Votre inscription au tournoi {tournament_details_str} est confirmée.") absolute_url = f"{request.build_absolute_uri(f'/tournament/{tournament.id}/')}" link_text = "informations sur le tournoi" @@ -85,14 +81,12 @@ class TournamentEmailService: @staticmethod def send_unregistration_confirmation(captain, tournament, other_player): tournament_details_str = tournament.build_tournament_details_str() - name_str = tournament.build_name_details_str() - email_subject = f"Confirmation de désistement du tournoi {tournament_details_str} {name_str}" + email_subject = f"Confirmation de désistement du tournoi {tournament_details_str}" email_body = TournamentEmailService._build_unregistration_email_body( tournament, captain, tournament_details_str, - name_str, other_player ) @@ -110,7 +104,6 @@ class TournamentEmailService: tournament, other_player, tournament_details_str, - name_str, captain ) @@ -126,14 +119,12 @@ class TournamentEmailService: @staticmethod def send_out_of_waiting_list_confirmation(captain, tournament, other_player): tournament_details_str = tournament.build_tournament_details_str() - name_str = tournament.build_name_details_str() - email_subject = f"Participation au tournoi {tournament_details_str} {name_str}" + email_subject = f"Participation au tournoi {tournament_details_str}" email_body = TournamentEmailService._buil_out_of_waiting_list_email_body( tournament, captain, tournament_details_str, - name_str, other_player ) @@ -151,7 +142,6 @@ class TournamentEmailService: tournament, other_player, tournament_details_str, - name_str, captain ) @@ -165,10 +155,10 @@ class TournamentEmailService: email.send() @staticmethod - def _build_unregistration_email_body(tournament, captain, tournament_details_str, name_str, other_player): + def _build_unregistration_email_body(tournament, captain, tournament_details_str, other_player): body_parts = [ - "Bonjour,\n", - f"Votre inscription au tournoi {tournament_details_str} {name_str}, prévu le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name} a été annulée" + "Bonjour,\n\n", + f"Votre inscription au tournoi {tournament_details_str}, prévu le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name} a été annulée" ] if other_player is not None: @@ -186,10 +176,10 @@ class TournamentEmailService: return "".join(body_parts) @staticmethod - def _buil_out_of_waiting_list_email_body(tournament, captain, tournament_details_str, name_str, other_player): + def _buil_out_of_waiting_list_email_body(tournament, captain, tournament_details_str, other_player): body_parts = [ - "Bonjour,\n", - f"Suite au désistement d'une paire, vous êtes maintenant inscrit au tournoi {tournament_details_str} {name_str}, prévu le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name}" + "Bonjour,\n\n", + f"Suite au désistement d'une paire, vous êtes maintenant inscrit au tournoi {tournament_details_str}, prévu le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name}" ] absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" @@ -212,3 +202,44 @@ class TournamentEmailService: ]) return "".join(body_parts) + + @staticmethod + def send_tournament_cancellation_notification(player, tournament, other_player): + tournament_details_str = tournament.build_tournament_details_str() + + email_subject = f"Annulation du tournoi {tournament_details_str}" + email_body = TournamentEmailService._build_tournament_cancellation_email_body( + tournament, + player, + tournament_details_str, + other_player + ) + + email = EmailMessage( + subject=email_subject, + body=TournamentEmailService._convert_newlines_to_html(email_body), + to=[player.email] + ) + + email.content_subtype = "html" + email.send() + + @staticmethod + def _build_tournament_cancellation_email_body(tournament, player, tournament_details_str, other_player): + body_parts = [ + "Bonjour,\n\n", + f"Le tournoi {tournament_details_str}, prévu le {tournament.start_date.strftime('%d/%m/%Y')} au club {tournament.event.club.name} a été annulé par le juge-arbitre." + ] + + if other_player is not None: + body_parts.append( + f"\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire." + ) + + body_parts.extend([ + "\n\nPour toute question, veuillez contacter votre juge-arbitre:", + f"\n{tournament.event.creator.full_name()}\n{tournament.event.creator.email}", + "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." + ]) + + return "".join(body_parts) diff --git a/tournaments/signals.py b/tournaments/signals.py index 9dddf3b..bc61cc3 100644 --- a/tournaments/signals.py +++ b/tournaments/signals.py @@ -3,6 +3,7 @@ import string from django.db.models.signals import post_save, pre_delete from django.dispatch import receiver from django.conf import settings +from tournaments.models.tournament import Tournament from tournaments.models.unregistered_player import UnregisteredPlayer from django.utils import timezone @@ -61,14 +62,21 @@ def send_discord_message(webhook_url, content): @receiver(pre_delete, sender=TeamRegistration) def unregister_team(sender, instance, **kwargs): team_registration = instance - tournament=instance.tournament + tournament = instance.tournament + + # Skip creating unregistration records if tournament is being deleted + if not tournament or tournament._state.adding or hasattr(tournament, '_being_deleted'): + return + first_waiting_list_team = tournament.first_waiting_list_team() - print("Unregistering team from tournament") + + # Create unregistered team record unregistered_team = UnregisteredTeam.objects.create( tournament=tournament, unregistration_date=timezone.now(), ) + # Create unregistered player records and track captain/other player captain = None other_player = None for player in team_registration.playerregistration_set.all(): @@ -76,6 +84,7 @@ def unregister_team(sender, instance, **kwargs): captain = player else: other_player = player + UnregisteredPlayer.objects.create( unregistered_team=unregistered_team, first_name=player.first_name, @@ -83,6 +92,7 @@ def unregister_team(sender, instance, **kwargs): licence_id=player.licence_id, ) + # Handle waiting list notifications if first_waiting_list_team: waiting_captain = None waiting_other_player = None @@ -92,16 +102,54 @@ def unregister_team(sender, instance, **kwargs): else: waiting_other_player = player - if waiting_captain is not None and waiting_captain.registered_online == True and waiting_captain.email is not None: + if waiting_captain and waiting_captain.registered_online and waiting_captain.email: TournamentEmailService.send_out_of_waiting_list_confirmation( waiting_captain, tournament, waiting_other_player ) - if captain is not None and captain.registered_online == True and captain.email is not None: + # Send unregistration confirmation + if captain and captain.registered_online and captain.email: TournamentEmailService.send_unregistration_confirmation( captain, tournament, other_player ) + +@receiver(pre_delete, sender=Tournament) +def notify_players_of_tournament_cancellation(sender, instance, **kwargs): + tournament = instance + + # Get all team registrations + team_registrations = tournament.teamregistration_set.all() + + for team_registration in team_registrations: + captain = None + other_player = None + + # Get players who registered online and have email + for player in team_registration.playerregistration_set.all(): + if not player.registered_online: + continue + + if player.captain: + captain = player + else: + other_player = player + + # Send email to captain + if captain: + TournamentEmailService.send_tournament_cancellation_notification( + captain, + tournament, + other_player + ) + + # Send email to other player if they exist and registered online + if other_player and other_player.registered_online and other_player.email: + TournamentEmailService.send_tournament_cancellation_notification( + other_player, + tournament, + captain + )