from django.core.mail import EmailMessage from enum import Enum from ..models.enums import RegistrationStatus, FederalLevelCategory from ..models.tournament import TeamSortingType from django.utils import timezone class TeamEmailType(Enum): REGISTERED = "registered" WAITING_LIST = "waiting_list" UNREGISTERED = "unregistered" OUT_OF_WAITING_LIST = "out_of_waiting_list" TOURNAMENT_CANCELED = "tournament_canceled" IN_TOURNAMENT_STRUCTURE = "in_tournament_structure" OUT_OF_TOURNAMENT_STRUCTURE = "out_of_tournament_structure" OUT_OF_WALKOUT_IS_IN = "out_of_walkout_is_in" OUT_OF_WALKOUT_WAITING_LIST = "out_of_walkout_waiting_list" WALKOUT = "walkout" UNEXPECTED_OUT_OF_TOURNAMENT = 'unexpected_out_of_tournament' REQUIRES_TIME_CONFIRMATION = 'requires_time_confirmation' def email_topic(self, category=None, time_to_confirm=None) -> str: confirmation_types = [ self.REGISTERED, self.OUT_OF_WAITING_LIST, self.IN_TOURNAMENT_STRUCTURE, self.OUT_OF_WALKOUT_IS_IN, self.REQUIRES_TIME_CONFIRMATION, ] word = "Tournoi" grammar = '' if category is not None: federal_category = FederalLevelCategory(category) word = federal_category.localized_word().capitalize() grammar = 'e' if federal_category.is_feminine_word() else '' if time_to_confirm and self in confirmation_types: return "Participation en attente de confirmation" else: subjects = { self.REGISTERED: "Participation confirmée", self.WAITING_LIST: "Liste d'attente", self.UNREGISTERED: "Désistement", self.OUT_OF_WAITING_LIST: "Participation confirmée", self.REQUIRES_TIME_CONFIRMATION: "Participation en attente de confirmation", self.TOURNAMENT_CANCELED: f"{word} annulé{grammar}", self.IN_TOURNAMENT_STRUCTURE: "Participation confirmée", self.OUT_OF_TOURNAMENT_STRUCTURE: "Participation annulée", self.OUT_OF_WALKOUT_IS_IN: "Participation confirmée", self.OUT_OF_WALKOUT_WAITING_LIST: "Liste d'attente", self.WALKOUT: "Participation annulée", self.UNEXPECTED_OUT_OF_TOURNAMENT: "Participation annulée", } return subjects.get(self, "Tournament Notification") class TournamentEmailService: @staticmethod def _convert_newlines_to_html(text): html_content = text.replace('\n', '
') return f""" {html_content} """ @staticmethod def email_subject(tournament, topic): base_subject = f"[{tournament.build_tournament_type_str()}] [{tournament.formatted_start_date()}] " + topic return base_subject @staticmethod def send_registration_confirmation(request, tournament, team_registration, waiting_list_position): if waiting_list_position >= 0: TournamentEmailService.notify_team(team_registration, tournament, TeamEmailType.WAITING_LIST) else: TournamentEmailService.notify_team(team_registration, tournament, TeamEmailType.REGISTERED) @staticmethod def _build_registration_confirmation_email_body(tournament, captain, tournament_details_str, other_player): return TournamentEmailService._build_registration_email_body(tournament, captain, tournament_details_str, other_player, False) @staticmethod def _build_waiting_list_confirmation_email_body(tournament, captain, tournament_details_str, other_player): return TournamentEmailService._build_registration_email_body(tournament, captain, tournament_details_str, other_player, True) @staticmethod def _build_registration_email_body(tournament, captain, tournament_details_str, other_player, waiting_list): inscription_date = captain.team_registration.local_registration_date().strftime("%d/%m/%Y à %H:%M") federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() tournament_prefix_of = federal_level_category.localized_prefix_of() tournament_prefix_that = federal_level_category.localized_prefix_that() body_parts = [] body_parts.append("Bonjour,\n") if waiting_list: body_parts.append(f"Votre inscription en liste d'attente {tournament_prefix_of}{tournament_word} {tournament_details_str} prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} est confirmée.") else: body_parts.append(f"Votre inscription {tournament_prefix_at}{tournament_word} {tournament_details_str} prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} est confirmée.") if tournament.team_sorting == TeamSortingType.RANK: cloture_date = tournament.local_registration_federal_limit() loc = "" if cloture_date is not None: loc = f", prévu le {cloture_date.strftime("%d/%m/%Y à %H:%M")}" body_parts.append(f"Attention, la sélection définitive se fera par poids d'équipe à la clôture des inscriptions{loc}.") absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"informations sur {tournament_prefix_that}{tournament_word}" absolute_url = f'{link_text}' body_parts.extend([ f"\nDate d'inscription: {inscription_date}", f"\nÉquipe inscrite: {captain.name()} et {other_player.name()}", f"\nVoir les {absolute_url}" ]) # Add payment information if applicable if tournament.should_request_payment(): payment_info = TournamentEmailService._build_payment_info(tournament, captain.team_registration) body_parts.append(payment_info) body_parts.extend([ "\nPour toute question, veuillez contacter votre juge-arbitre. Si vous n'êtes pas à l'origine de cette inscription, merci de le contacter rapidement.", f"\n{TournamentEmailService._format_umpire_contact(tournament)}", "\nCeci est un e-mail automatique, veuillez ne pas y répondre.", "\nCordialement,\n\nPadel Club" ]) return "\n".join(body_parts) @staticmethod def _build_unregistration_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() tournament_prefix_that = federal_level_category.localized_prefix_that() body_parts = [ "Bonjour,\n\n", f"Votre inscription {tournament_prefix_at}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} a été annulée" ] if other_player is not None: body_parts.append( f"\n\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire." ) absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"informations sur {tournament_prefix_that}{tournament_word}" absolute_url = f'{link_text}' body_parts.append( f"\n\nVoir les {absolute_url}", ) body_parts.extend([ "\n\nPour toute question, veuillez contacter votre juge-arbitre. " "Si vous n'êtes pas à l'origine de cette désinscription, merci de le contacter rapidement.", f"\n{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_out_of_waiting_list_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() body_parts = [ "Bonjour,\n\n", f"Suite au désistement d'une paire, vous êtes maintenant inscrit {tournament_prefix_at}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name}" ] absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"accéder {tournament_prefix_at}{tournament_word}" absolute_url = f'{link_text}' if other_player is not None: body_parts.append( f"\nVoici le partenaire indiqué dans l'inscription : {other_player.name()}, n'oubliez pas de le prévenir." ) confirmation_message = TournamentEmailService._build_confirmation_message(captain, tournament, absolute_url) body_parts.append(confirmation_message) body_parts.extend([ f"\n\n{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_requires_confirmation_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() body_parts = [ "Bonjour,\n\n", f"Vous n'avez toujours pas confirmé votre participation {tournament_prefix_at}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name}" ] absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"accéder {tournament_prefix_at}{tournament_word}" absolute_url = f'{link_text}' if other_player is not None: body_parts.append( f"\nVoici le partenaire indiqué dans l'inscription : {other_player.name()}, n'oubliez pas de le prévenir." ) confirmation_message = TournamentEmailService._build_confirmation_message(captain, tournament, absolute_url) body_parts.append(confirmation_message) body_parts.extend([ f"\n\n{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_tournament_cancellation_email_body(tournament, player, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_that = federal_level_category.localized_prefix_that() body_parts = [ "Bonjour,\n\n", f"{tournament_prefix_that.capitalize()}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} 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{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_in_tournament_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() tournament_prefix_of = federal_level_category.localized_prefix_of() body_parts = [ "Bonjour,\n\n", f"Suite à une modification de la taille {tournament_prefix_of}{tournament_word}, vous pouvez participer {tournament_prefix_at}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name}" ] absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"accéder {tournament_prefix_at}{tournament_word}" absolute_url = f'{link_text}' if other_player is not None: body_parts.append( f"\nVoici le partenaire indiqué dans l'inscription : {other_player.name()}, n'oubliez pas de le prévenir." ) confirmation_message = TournamentEmailService._build_confirmation_message(captain, tournament, absolute_url) body_parts.append(confirmation_message) body_parts.extend([ f"\n\n{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_out_of_tournament_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() tournament_prefix_of = federal_level_category.localized_prefix_of() tournament_prefix_that = federal_level_category.localized_prefix_that() body_parts = [ "Bonjour,\n\n", f"Suite à une modification de la taille {tournament_prefix_of}{tournament_word}, vous avez été placé en liste d'attente. Votre participation {tournament_prefix_at}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} n'est plus confirmée." ] absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"informations sur {tournament_prefix_that}{tournament_word}" absolute_url = f'{link_text}' body_parts.append(f"\n\nVoir les {absolute_url}") 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{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_walk_out_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() body_parts = [ "Bonjour,\n\n", f"Le juge-arbitre a annulé votre participation {tournament_prefix_at}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name}" ] absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"accéder {tournament_prefix_at}{tournament_word}" absolute_url = f'{link_text}' body_parts.append(f"\n\nVoir les {absolute_url}") 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{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_out_of_walkout_is_in_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() tournament_prefix_that = federal_level_category.localized_prefix_that() body_parts = [ "Bonjour,\n\n", f"Le juge-arbitre vous a ré-intégré {tournament_prefix_at}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name}" ] absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"informations sur {tournament_prefix_that}{tournament_word}" absolute_url = f'{link_text}' body_parts.append(f"\n\nVoir les {absolute_url}") 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." ) confirmation_message = TournamentEmailService._build_confirmation_message(captain, tournament, absolute_url) body_parts.append(confirmation_message) body_parts.extend([ "\n\nPour toute question, veuillez contacter votre juge-arbitre : ", f"\n{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_unexpected_out_of_tournament_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() tournament_prefix_that = federal_level_category.localized_prefix_that() body_parts = [ "Bonjour,\n\n", f"En raison d'une décision du juge-arbitre, vous avez été placé en liste d'attente. Votre participation {tournament_prefix_at}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} n'est plus confirmée." ] absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"informations sur {tournament_prefix_that}{tournament_word}" absolute_url = f'{link_text}' body_parts.append(f"\n\nVoir les {absolute_url}") 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{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod def _build_out_of_walkout_waiting_list_email_body(tournament, captain, tournament_details_str, other_player): federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_of = federal_level_category.localized_prefix_of() tournament_prefix_that = federal_level_category.localized_prefix_that() body_parts = [ "Bonjour,\n\n", ] if captain.registration_status == RegistrationStatus.CANCELED: body_parts.append("Le temps accordé pour confirmer votre inscription s'est écoulé.") body_parts.append(f"Vous avez été replacé en liste d'attente {tournament_prefix_of}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name}") else: body_parts.append(f"Le juge-arbitre vous a placé en liste d'attente {tournament_prefix_of}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name}") absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"informations sur {tournament_prefix_that}{tournament_word}" absolute_url = f'{link_text}' body_parts.append(f"\n\nVoir les {absolute_url}") 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{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) return "".join(body_parts) @staticmethod 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: creator_email = tournament.umpire_mail() if creator_email: contact_parts.append(creator_email) if not tournament.hide_umpire_phone: creator_phone = tournament.umpire_phone() if creator_phone: contact_parts.append(creator_phone) return "\n".join(contact_parts) @staticmethod def _build_confirmation_message(captain, tournament, absolute_url): """ Build a standardized confirmation message for emails. Args: captain: The player (captain) receiving the email tournament: The tournament absolute_url: The URL for confirmation/unregistration Returns: str: Formatted confirmation message """ time_to_confirm = getattr(captain, 'time_to_confirm', None) # Common URL and account info text account_info = "\nVous devez avoir un compte Padel Club." url_info = f"\n{absolute_url}" federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_at = federal_level_category.localized_prefix_at() tournament_prefix_this = federal_level_category.localized_prefix_this() # Base message varies based on whether confirmation is needed if time_to_confirm is not None: # Format the deadline time with proper timezone deadline_str = time_to_confirm.astimezone(tournament.timezone()).strftime("%d/%m/%Y à %H:%M (%Z)") # Confirmation required message action_text = f"Pour confirmer votre participation {tournament_prefix_at}{tournament_word}, cliquez sur ce lien pour {url_info} ou contactez rapidement le juge-arbitre." warning_text = f"⚠️ ATTENTION : Vous avez jusqu'au {deadline_str} pour confirmer votre participation. Passé ce délai, votre place sera automatiquement proposée à l'équipe suivante sur liste d'attente.\n\n" elif captain.registration_status == RegistrationStatus.PENDING: action_text = f"Pour confirmer votre participation {tournament_prefix_at}{tournament_word}, cliquez sur ce lien pour {url_info} ou contactez rapidement le juge-arbitre." warning_text = f"⚠️ ATTENTION : Actuellement, il n'y a pas de liste d'attente pour {tournament_prefix_this}{tournament_word}. Dès qu'une liste d'attente se formera, vous recevrez un email avec un délai précis pour confirmer votre participation.\n\n" else: # Standard message for teams already confirmed action_text = f"Si vous n'êtes plus disponible pour participer à {tournament_prefix_this}{tournament_word}, cliquez sur ce lien pour {url_info} ou contactez rapidement le juge-arbitre." warning_text = "" # Construct the complete message return f"\n\n{warning_text}{action_text}{account_info}" @staticmethod def notify(captain, other_player, tournament, message_type: TeamEmailType): print("TournamentEmailService.notify", captain.email, captain.registered_online, tournament, message_type) if not captain or not captain.registered_online or not captain.email: return tournament_details_str = tournament.build_tournament_details_str() email_body = TournamentEmailService._build_email_content( message_type, captain, tournament, tournament_details_str, other_player ) if email_body is None: return topic = message_type.email_topic(tournament.federal_level_category, captain.time_to_confirm) email_subject = TournamentEmailService.email_subject(tournament, topic) TournamentEmailService._send_email(captain.email, email_subject, email_body) @staticmethod def _build_email_content(message_type, recipient, tournament, tournament_details_str, other_player, request=None, waiting_list_position=None): if message_type == TeamEmailType.REGISTERED: body = TournamentEmailService._build_registration_confirmation_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.WAITING_LIST: body = TournamentEmailService._build_waiting_list_confirmation_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.OUT_OF_WAITING_LIST: body = TournamentEmailService._build_out_of_waiting_list_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.UNREGISTERED: body = TournamentEmailService._build_unregistration_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.TOURNAMENT_CANCELED: body = TournamentEmailService._build_tournament_cancellation_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.WALKOUT: body = TournamentEmailService._build_walk_out_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.OUT_OF_WALKOUT_IS_IN: body = TournamentEmailService._build_out_of_walkout_is_in_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.OUT_OF_WALKOUT_WAITING_LIST: body = TournamentEmailService._build_out_of_walkout_waiting_list_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.REQUIRES_TIME_CONFIRMATION: body = TournamentEmailService._build_requires_confirmation_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.UNEXPECTED_OUT_OF_TOURNAMENT: body = TournamentEmailService._build_unexpected_out_of_tournament_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.OUT_OF_TOURNAMENT_STRUCTURE: body = TournamentEmailService._build_out_of_tournament_email_body( tournament, recipient, tournament_details_str, other_player ) elif message_type == TeamEmailType.IN_TOURNAMENT_STRUCTURE: body = TournamentEmailService._build_in_tournament_email_body( tournament, recipient, tournament_details_str, other_player ) else: return None return body @staticmethod def _send_email(to, subject, body): email = EmailMessage( subject=subject, body=TournamentEmailService._convert_newlines_to_html(body), to=[to] ) email.content_subtype = "html" email.send() print("TournamentEmailService._send_email", to, subject) @staticmethod def notify_team(team, tournament, message_type: TeamEmailType): # Notify both players separately if there is no captain or the captain is unavailable players = list(team.players_sorted_by_rank) if len(players) == 2: print("TournamentEmailService.notify_team 2p", team) first_player, second_player = players TournamentEmailService.notify(first_player, second_player, tournament, message_type) if first_player.email != second_player.email: TournamentEmailService.notify(second_player, first_player, tournament, message_type) elif len(players) == 1: print("TournamentEmailService.notify_team 1p", team) # If there's only one player, just send them the notification TournamentEmailService.notify(players[0], None, tournament, message_type) @staticmethod def _build_payment_info(tournament, team_registration): """ Build payment information section for emails """ if not tournament.should_request_payment(): return "" if tournament.is_free(): return "" # Check payment status payment_status = team_registration.get_payment_status() if payment_status == 'PAID': return "\n\n✅ Le paiement de votre inscription a bien été reçu." # If the team is on the waiting list, don't mention payment if team_registration.is_in_waiting_list() >= 0: return "" # For unpaid teams, add payment instructions payment_info = [ "\n\n⚠️ Paiement des frais d'inscription requis", f"Les frais d'inscription de {tournament.entry_fee:.2f}€ par joueur doivent être payés pour confirmer votre participation.", "Vous pouvez effectuer le paiement en vous connectant à votre compte Padel Club.", f"Lien pour payer: https://padelclub.app/tournament/{tournament.id}/info" ] return "\n".join(payment_info) @staticmethod def send_payment_confirmation(team_registration, payment): """ Send a payment confirmation email to team members Args: team_registration: The team registration payment: The payment details from Stripe """ tournament = team_registration.tournament player_registrations = team_registration.players_sorted_by_rank # Calculate payment amount payment_amount = None if payment and 'amount' in payment: # Convert cents to euros payment_amount = payment['amount'] / 100 if payment_amount is None: payment_amount = tournament.team_fee() federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_that = federal_level_category.localized_prefix_that() for player in player_registrations: if not player.email or not player.registered_online: continue tournament_details_str = tournament.build_tournament_details_str() other_player = team_registration.get_other_player(player) if len(player_registrations) > 1 else None body_parts = [ "Bonjour,\n\n", f"Votre paiement pour {tournament_prefix_that}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} a été reçu avec succès." ] # Add information about the other player if available if other_player: body_parts.append( f"\n\nVous êtes inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire de la confirmation du paiement." ) # Add payment details body_parts.append( f"\n\nMontant payé : {payment_amount:.2f}€" ) payment_date = timezone.now().strftime("%d/%m/%Y") body_parts.append( f"\nDate du paiement : {payment_date}" ) absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"informations sur {tournament_prefix_that}{tournament_word}" absolute_url = f'{link_text}' body_parts.append(f"\n\nVoir les {absolute_url}") if tournament.team_sorting == TeamSortingType.RANK: cloture_date = tournament.local_registration_federal_limit().strftime("%d/%m/%Y à %H:%M") loc = "" if cloture_date is not None: loc = f", prévu le {cloture_date}" body_parts.append(f"\n\nAttention, la sélection définitive se fera par poids d'équipe à la clôture des inscriptions{loc}.") body_parts.extend([ f"\n\n{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) email_body = "".join(body_parts) email_subject = TournamentEmailService.email_subject(tournament, "Confirmation de paiement") TournamentEmailService._send_email(player.email, email_subject, email_body) @staticmethod def send_refund_confirmation(tournament, team_registration, refund_details): """ Send a refund confirmation email to team members Args: tournament: The tournament team_registration: The team registration refund_details: The refund details from Stripe """ player_registrations = team_registration.players_sorted_by_rank refund_amount = None if refund_details and 'amount' in refund_details: # Convert cents to euros refund_amount = refund_details['amount'] / 100 if refund_amount is None: refund_amount = tournament.team_fee() federal_level_category = FederalLevelCategory(tournament.federal_level_category) tournament_word = federal_level_category.localized_word() tournament_prefix_that = federal_level_category.localized_prefix_that() processed_emails = set() for player in player_registrations: if not player.email or not player.registered_online: continue if player.email in processed_emails: continue processed_emails.add(player.email) tournament_details_str = tournament.build_tournament_details_str() other_player = team_registration.get_other_player(player) if len(player_registrations) > 1 else None body_parts = [ "Bonjour,\n\n", f"Votre remboursement pour {tournament_prefix_that}{tournament_word} {tournament_details_str}, prévu le {tournament.formatted_start_date()} au club {tournament.event.club.name} a été traité avec succès." ] # Add information about the other player if available if other_player: body_parts.append( f"\n\nVous étiez inscrit avec {other_player.name()}, n'oubliez pas de prévenir votre partenaire du remboursement." ) # Add refund details body_parts.append( f"\n\nMontant remboursé : {refund_amount:.2f}€" ) refund_date = timezone.now().strftime("%d/%m/%Y") body_parts.append( f"\nDate du remboursement : {refund_date}" ) absolute_url = f"https://padelclub.app/tournament/{tournament.id}/info" link_text = f"informations sur {tournament_prefix_that}{tournament_word}" absolute_url = f'{link_text}' body_parts.append(f"\n\nVoir les {absolute_url}") body_parts.extend([ f"\n\n{TournamentEmailService._format_umpire_contact(tournament)}", "\n\nCeci est un e-mail automatique, veuillez ne pas y répondre." ]) email_body = "".join(body_parts) email_subject = TournamentEmailService.email_subject(tournament, "Confirmation de remboursement") TournamentEmailService._send_email(player.email, email_subject, email_body)