diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index c82270b..ce7bd0a 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: TFJM\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2024-02-11 23:19+0100\n"
+"POT-Creation-Date: 2024-02-12 22:29+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emmy D'Anello
L'équipe {trigram} a {nb_missing_payments} paiements manquants. Chaque " -"membre de l'équipe doit avoir un paiement valide (ou envoyer une notification " -"de bourse) pour participer au tournoi.
Les participant⋅es qui n'ont pas " -"encore payé sont : {participants}.
" +"membre de l'équipe doit avoir un paiement valide (ou envoyer une " +"notification de bourse) pour participer au tournoi.Les participant⋅es " +"qui n'ont pas encore payé sont : {participants}.
" #: participation/models.py:477 msgid "Missing payments" @@ -1088,10 +1088,9 @@ msgstr "Rejoindre" #: participation/templates/participation/team_detail.html:192 #: participation/templates/participation/tournament_form.html:12 #: participation/templates/participation/update_team.html:12 -#: registration/templates/registration/payment_form.html:49 #: registration/templates/registration/update_user.html:16 -#: registration/templates/registration/user_detail.html:179 -#: registration/templates/registration/user_detail.html:216 +#: registration/templates/registration/user_detail.html:186 +#: registration/templates/registration/user_detail.html:223 msgid "Update" msgstr "Modifier" @@ -1157,11 +1156,11 @@ msgstr "Envoyer une solution" #: registration/templates/registration/upload_parental_authorization.html:17 #: registration/templates/registration/upload_photo_authorization.html:18 #: registration/templates/registration/upload_vaccine_sheet.html:13 -#: registration/templates/registration/user_detail.html:189 -#: registration/templates/registration/user_detail.html:194 -#: registration/templates/registration/user_detail.html:199 -#: registration/templates/registration/user_detail.html:204 -#: registration/templates/registration/user_detail.html:209 +#: registration/templates/registration/user_detail.html:196 +#: registration/templates/registration/user_detail.html:201 +#: registration/templates/registration/user_detail.html:206 +#: registration/templates/registration/user_detail.html:211 +#: registration/templates/registration/user_detail.html:216 msgid "Upload" msgstr "Téléverser" @@ -1499,7 +1498,7 @@ msgid "Invalidate" msgstr "Invalider" #: participation/templates/participation/team_detail.html:186 -#: participation/views.py:325 +#: participation/views.py:323 msgid "Upload motivation letter" msgstr "Envoyer la lettre de motivation" @@ -1508,7 +1507,7 @@ msgid "Update team" msgstr "Modifier l'équipe" #: participation/templates/participation/team_detail.html:196 -#: participation/views.py:434 +#: participation/views.py:432 msgid "Leave team" msgstr "Quitter l'équipe" @@ -1642,7 +1641,7 @@ msgstr "Vous êtes déjà dans une équipe." msgid "Join team" msgstr "Rejoindre une équipe" -#: participation/views.py:152 participation/views.py:472 +#: participation/views.py:152 participation/views.py:470 msgid "You don't participate, so you don't have any team." msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe." @@ -1678,95 +1677,95 @@ msgstr "Vous n'êtes pas un⋅e organisateur⋅rice du tournoi." msgid "This team has no pending validation." msgstr "L'équipe n'a pas de validation en attente." -#: participation/views.py:268 +#: participation/views.py:266 msgid "You must specify if you validate the registration or not." msgstr "Vous devez spécifier si vous validez l'inscription ou non." -#: participation/views.py:303 +#: participation/views.py:301 #, python-brace-format msgid "Update team {trigram}" msgstr "Mise à jour de l'équipe {trigram}" -#: participation/views.py:364 participation/views.py:420 +#: participation/views.py:362 participation/views.py:418 #, python-brace-format msgid "Motivation letter of {team}.{ext}" msgstr "Lettre de motivation de {team}.{ext}" -#: participation/views.py:395 +#: participation/views.py:393 #, python-brace-format msgid "Photo authorization of {participant}.{ext}" msgstr "Autorisation de droit à l'image de {participant}.{ext}" -#: participation/views.py:401 +#: participation/views.py:399 #, python-brace-format msgid "Parental authorization of {participant}.{ext}" msgstr "Autorisation parentale de {participant}.{ext}" -#: participation/views.py:408 +#: participation/views.py:406 #, python-brace-format msgid "Health sheet of {participant}.{ext}" msgstr "Fiche sanitaire de {participant}.{ext}" -#: participation/views.py:414 +#: participation/views.py:412 #, python-brace-format msgid "Vaccine sheet of {participant}.{ext}" msgstr "Carnet de vaccination de {participant}.{ext}" -#: participation/views.py:424 +#: participation/views.py:422 #, python-brace-format msgid "Photo authorizations of team {trigram}.zip" msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip" -#: participation/views.py:442 +#: participation/views.py:440 msgid "The team is already validated or the validation is pending." msgstr "La validation de l'équipe est déjà faite ou en cours." -#: participation/views.py:486 +#: participation/views.py:484 msgid "The team is not validated yet." msgstr "L'équipe n'est pas encore validée." -#: participation/views.py:500 +#: participation/views.py:498 #, python-brace-format msgid "Participation of team {trigram}" msgstr "Participation de l'équipe {trigram}" -#: participation/views.py:636 +#: participation/views.py:634 msgid "You can't upload a solution after the deadline." msgstr "Vous ne pouvez pas envoyer de solution après la date limite." -#: participation/views.py:744 +#: participation/views.py:742 #, python-brace-format msgid "Solutions for pool {pool} of tournament {tournament}.zip" msgstr "Solutions pour la poule {pool} du tournoi {tournament}.zip" -#: participation/views.py:745 +#: participation/views.py:743 #, python-brace-format msgid "Syntheses for pool {pool} of tournament {tournament}.zip" msgstr "Notes de synthèses pour la poule {pool} du tournoi {tournament}.zip" -#: participation/views.py:763 +#: participation/views.py:761 #, python-brace-format msgid "Jurys of {pool}" msgstr "Juré⋅es de la {pool}" -#: participation/views.py:790 +#: participation/views.py:788 msgid "New TFJM² jury account" msgstr "Nouveau compte de juré⋅e pour le TFJM²" -#: participation/views.py:803 +#: participation/views.py:801 #, python-brace-format msgid "The jury {name} has been successfully added!" msgstr "{name} a été ajouté⋅e avec succès en tant que juré⋅e !" -#: participation/views.py:840 +#: participation/views.py:838 msgid "The following user is not registered as a jury:" msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e :" -#: participation/views.py:854 +#: participation/views.py:852 msgid "Notes were successfully uploaded." msgstr "Les notes ont bien été envoyées." -#: participation/views.py:1518 +#: participation/views.py:1516 msgid "You can't upload a synthesis after the deadline." msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite." @@ -1780,9 +1779,9 @@ msgstr "prénom" msgid "last name" msgstr "nom de famille" -#: registration/admin.py:105 -msgid "registration type" -msgstr "type d'inscription" +#: registration/admin.py:106 +msgid "concerned people" +msgstr "personnes concernées" #: registration/forms.py:22 msgid "role" @@ -1792,7 +1791,7 @@ msgstr "rôle" msgid "participant" msgstr "participant⋅e" -#: registration/forms.py:25 registration/models.py:415 +#: registration/forms.py:25 registration/models.py:416 msgid "coach" msgstr "encadrant⋅e" @@ -1801,8 +1800,8 @@ msgid "Pending" msgstr "En attente" #: registration/forms.py:245 -msgid "You must upload your scholarship attestation." -msgstr "Vous devez envoyer votre attestation de bourse." +msgid "You must upload your receipt." +msgstr "Vous devez envoyer votre justificatif." #: registration/models.py:36 msgid "Grant Animath to contact me in the future about other actions" @@ -1828,11 +1827,11 @@ msgstr "" "avez reçu par mail. Vous pouvez renvoyer un mail en cliquant sur ce lien." -#: registration/models.py:118 registration/models.py:503 +#: registration/models.py:118 msgid "registration" msgstr "inscription" -#: registration/models.py:119 +#: registration/models.py:119 registration/models.py:503 msgid "registrations" msgstr "inscriptions" @@ -2027,7 +2026,7 @@ msgstr "" msgid "Vaccine sheet" msgstr "Carnet de vaccination" -#: registration/models.py:368 +#: registration/models.py:369 #, python-brace-format msgid "" "You have to pay {amount} € for your registration, or send a scholarship " @@ -2038,27 +2037,27 @@ msgstr "" "notification de bourse ou un justificatif de paiement. Vous pouvez le faire " "sur la page de paiement." -#: registration/models.py:374 registration/models.py:383 +#: registration/models.py:375 registration/models.py:384 msgid "Payment" msgstr "Paiement" -#: registration/models.py:380 +#: registration/models.py:381 msgid "Your payment is under approval." msgstr "Votre paiement est en cours de validation." -#: registration/models.py:392 +#: registration/models.py:393 msgid "student registration" msgstr "inscription d'élève" -#: registration/models.py:393 +#: registration/models.py:394 msgid "student registrations" msgstr "inscriptions d'élève" -#: registration/models.py:404 +#: registration/models.py:405 msgid "most recent degree in mathematics, computer science or physics" msgstr "Dernier diplôme obtenu en mathématiques, informatique ou physique" -#: registration/models.py:405 +#: registration/models.py:406 msgid "" "Your most recent degree in maths, computer science or physics, or your last " "entrance exam (CAPES, Agrégation,…)" @@ -2066,23 +2065,23 @@ msgstr "" "Votre dernier diplôme en mathématiques, informatique ou physique, ou votre " "dernier concours obtenu (CAPES, Agrégation, …)" -#: registration/models.py:410 registration/models.py:432 +#: registration/models.py:411 registration/models.py:433 msgid "professional activity" msgstr "activité professionnelle" -#: registration/models.py:423 +#: registration/models.py:424 msgid "coach registration" msgstr "inscription d'encadrant⋅e" -#: registration/models.py:424 +#: registration/models.py:425 msgid "coach registrations" msgstr "inscriptions d'encadrant⋅es" -#: registration/models.py:436 +#: registration/models.py:437 msgid "administrator" msgstr "administrateur⋅rice" -#: registration/models.py:437 +#: registration/models.py:438 msgid "" "An administrator has all rights. Please don't give this right to all juries " "and volunteers." @@ -2090,15 +2089,15 @@ msgstr "" "Un⋅e administrateur⋅rice a tous les droits. Merci de ne pas donner ce droit " "à toustes les juré⋅es et bénévoles." -#: registration/models.py:447 +#: registration/models.py:448 msgid "admin" msgstr "admin" -#: registration/models.py:447 +#: registration/models.py:448 msgid "volunteer" msgstr "bénévole" -#: registration/models.py:460 +#: registration/models.py:461 msgid "" "Registrations for tournament {tournament} are closing on {date:%Y-%m-%d %H:" "%M}. There are for now {validated_teams} validated teams (+ {pending_teams} " @@ -2108,11 +2107,11 @@ msgstr "" "%M}. Il y a pour l'instant {validated_teams} équipes validées (+ " "{pending_teams} en attente) sur {max_teams} attendues." -#: registration/models.py:468 +#: registration/models.py:469 msgid "Registrations" msgstr "Inscriptions" -#: registration/models.py:475 +#: registration/models.py:476 #, python-brace-format msgid "" "The team {trigram} requested to be validated for the tournament of " @@ -2123,68 +2122,98 @@ msgstr "" "Vous pouvez vérifier le statut de l'équipe sur la page de " "l'équipe." -#: registration/models.py:490 +#: registration/models.py:491 msgid "volunteer registration" msgstr "inscription de bénévole" -#: registration/models.py:491 +#: registration/models.py:492 msgid "volunteer registrations" msgstr "inscriptions de bénévoles" #: registration/models.py:507 +msgid "grouped" +msgstr "groupé" + +#: registration/models.py:509 +msgid "" +"If set to true, then one payment is made for the full team, for example if " +"the school pays for all." +msgstr "" +"Si vrai, alors un seul paiement est fait pour toute l'équipe, par exemple si " +"le lycée paie pour tout le monde." + +#: registration/models.py:514 +msgid "total amount" +msgstr "montant total" + +#: registration/models.py:515 +msgid "Corresponds to the total required amount to pay, in euros." +msgstr "Correspond au montant total à payer, en euros." + +#: registration/models.py:520 +msgid "for final tournament" +msgstr "pour la finale" + +#: registration/models.py:525 msgid "type" msgstr "type" -#: registration/models.py:510 +#: registration/models.py:528 msgid "No payment" msgstr "Pas de paiement" -#: registration/models.py:512 +#: registration/models.py:530 msgid "Scholarship" msgstr "Notification de bourse" -#: registration/models.py:513 +#: registration/models.py:531 msgid "Bank transfer" msgstr "Virement bancaire" -#: registration/models.py:514 +#: registration/models.py:532 msgid "Other (please indicate)" msgstr "Autre (veuillez spécifier)" -#: registration/models.py:515 +#: registration/models.py:533 msgid "The tournament is free" msgstr "Le tournoi est gratuit" -#: registration/models.py:522 -msgid "scholarship file" -msgstr "Notification de bourse" +#: registration/models.py:540 +msgid "Hello Asso checkout intent ID" +msgstr "ID de l'intention de paiement Hello Asso" -#: registration/models.py:523 -msgid "only if you have a scholarship." -msgstr "Nécessaire seulement si vous déclarez être boursier." +#: registration/models.py:547 +msgid "receipt" +msgstr "justificatif" -#: registration/models.py:530 +#: registration/models.py:548 +msgid "only if you have a scholarship or if you chose a bank transfer." +msgstr "" +"Nécessaire seulement si vous déclarez être boursièr⋅e ou si vous payez par " +"virement bancaire." + +#: registration/models.py:555 msgid "additional information" msgstr "informations additionnelles" -#: registration/models.py:531 +#: registration/models.py:556 msgid "To help us to find your payment." msgstr "Pour nous aider à retrouver votre paiement, si nécessaire." -#: registration/models.py:537 +#: registration/models.py:562 msgid "payment valid" msgstr "paiement valide" -#: registration/models.py:546 +#: registration/models.py:571 #, python-brace-format -msgid "Payment of {registration}" -msgstr "Paiement de {registration}" +msgid "Payment of {registrations}" +msgstr "Paiements de {registration}" -#: registration/models.py:549 +#: registration/models.py:574 msgid "payment" msgstr "paiement" -#: registration/models.py:550 +#: registration/models.py:575 msgid "payments" msgstr "paiements" @@ -2349,56 +2378,6 @@ msgstr "" msgid "Reset my password" msgstr "Réinitialiser mon mot de passe" -#: registration/templates/registration/payment_form.html:10 -#, python-format -msgid "" -"The price of the tournament is %(price)s €. The participation fee is offered " -"for coaches and for students who have a scholarship. If so, please send us " -"your scholarship attestation." -msgstr "" -"Le prix du tournoi est de %(price)s €. Les frais de participation sont " -"offerts pour les encadrant⋅es et les élèves boursièr⋅es. Si c'est le cas, " -"merci de nous transmettre votre notification de bourse." - -#: registration/templates/registration/payment_form.html:17 -msgid "" -"You can pay with a credit card through our Hello Asso page. To make the validation of the " -"payment easier, please use the same e-mail " -"address that you use on this platform. The payment verification will " -"be checked automatically under 10 minutes, you don't necessary need to fill " -"this form." -msgstr "" -"Vous pouvez payer par carte bancaire sur notre page Hello Asso. Pour rendre la validation du " -"paiement plus facile, merci d'utiliser la même " -"adresse e-mail que vous utilisez sur cette plateforme. La " -"vérification du paiement sera faite automatiquement sous 10 minutes, vous " -"n'avez pas nécessairement besoin de remplir ce formulaire." - -#: registration/templates/registration/payment_form.html:27 -msgid "" -"You can also send a bank transfer to the bank account of Animath. You must " -"put in the reference of the transfer the mention \"TFJMpu\" followed by the " -"last name and the first name of the student." -msgstr "" -"Vous pouvez également faire un virement bancaire sur le compte d'Animath. " -"Vous devez alors mettre dans la référence du transfert la mention \"TFJMpu\" " -"suivie du nom et du prénom de l'élève." - -#: registration/templates/registration/payment_form.html:39 -msgid "" -"If any payment mean is available to you, please contact us at contact@tfjm.org " -"to find a solution to your difficulties." -msgstr "" -"Si aucun moyen de paiement ne vous convient, merci de nous contecter à " -"l'adresse contact@tfjm.org pour que nous puissions trouver une solution à " -"vos difficultés." - #: registration/templates/registration/signup.html:5 #: registration/templates/registration/signup.html:12 #: registration/templates/registration/signup.html:19 registration/views.py:44 @@ -2533,49 +2512,53 @@ msgstr "Administrateur⋅rice :" msgid "Grant Animath to contact me in the future about other actions:" msgstr "Autorise Animath à recontacter à propos d'autres actions :" -#: registration/templates/registration/user_detail.html:149 +#: registration/templates/registration/user_detail.html:150 msgid "Payment information:" msgstr "Informations de paiement :" -#: registration/templates/registration/user_detail.html:151 +#: registration/templates/registration/user_detail.html:152 msgid "yes,no,pending" msgstr "oui,non,en attente" -#: registration/templates/registration/user_detail.html:155 -#: registration/templates/registration/user_detail.html:158 +#: registration/templates/registration/user_detail.html:156 +#: registration/templates/registration/user_detail.html:159 msgid "valid:" msgstr "valide :" -#: registration/templates/registration/user_detail.html:162 -#: registration/templates/registration/user_detail.html:215 +#: registration/templates/registration/user_detail.html:163 +#: registration/templates/registration/user_detail.html:222 msgid "Update payment" msgstr "Modifier le paiement" -#: registration/templates/registration/user_detail.html:168 +#: registration/templates/registration/user_detail.html:171 msgid "Download scholarship attestation" msgstr "Télécharger l'attestation de bourse" -#: registration/templates/registration/user_detail.html:181 +#: registration/templates/registration/user_detail.html:173 +msgid "Download bank transfer receipt" +msgstr "Télécharger le justificatif de virement bancaire" + +#: registration/templates/registration/user_detail.html:188 msgid "Impersonate" msgstr "Impersonifier" -#: registration/templates/registration/user_detail.html:188 +#: registration/templates/registration/user_detail.html:195 #: registration/views.py:313 msgid "Upload photo authorization" msgstr "Téléverser l'autorisation de droit à l'image" -#: registration/templates/registration/user_detail.html:193 +#: registration/templates/registration/user_detail.html:200 #: registration/views.py:334 msgid "Upload health sheet" msgstr "Téléverser la fiche sanitaire" -#: registration/templates/registration/user_detail.html:198 +#: registration/templates/registration/user_detail.html:205 #: registration/views.py:355 msgid "Upload vaccine sheet" msgstr "Téléverser le carnet de vaccination" -#: registration/templates/registration/user_detail.html:203 -#: registration/templates/registration/user_detail.html:208 +#: registration/templates/registration/user_detail.html:210 +#: registration/templates/registration/user_detail.html:215 #: registration/views.py:376 msgid "Upload parental authorization" msgstr "Téléverser l'autorisation parentale" @@ -2614,27 +2597,27 @@ msgstr "Détails de l'utilisateur⋅rice {user}" msgid "Update user {user}" msgstr "Mise à jour de l'utilisateur⋅rice {user}" -#: registration/views.py:494 +#: registration/views.py:492 #, python-brace-format msgid "Photo authorization of {student}.{ext}" msgstr "Autorisation de droit à l'image de {student}.{ext}" -#: registration/views.py:517 +#: registration/views.py:515 #, python-brace-format msgid "Health sheet of {student}.{ext}" msgstr "Fiche sanitaire de {student}.{ext}" -#: registration/views.py:540 +#: registration/views.py:538 #, python-brace-format msgid "Vaccine sheet of {student}.{ext}" msgstr "Carnet de vaccination de {student}.{ext}" -#: registration/views.py:563 +#: registration/views.py:561 #, python-brace-format msgid "Parental authorization of {student}.{ext}" msgstr "Autorisation parentale de {student}.{ext}" -#: registration/views.py:585 +#: registration/views.py:583 #, python-brace-format msgid "Scholarship attestation of {user}.{ext}" msgstr "Notification de bourse de {user}.{ext}" diff --git a/participation/models.py b/participation/models.py index ca983fd..9512010 100644 --- a/participation/models.py +++ b/participation/models.py @@ -14,7 +14,7 @@ from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.text import format_lazy from django.utils.translation import gettext_lazy as _ -from registration.models import VolunteerRegistration, Payment +from registration.models import Payment, VolunteerRegistration from tfjm.lists import get_sympa_client @@ -465,14 +465,15 @@ class Participation(models.Model): def important_informations(self): informations = [] - missing_payments = Payment.objects.filter(registration__in=self.team.participants.all(), valid=False) + missing_payments = Payment.objects.filter(registrations__in=self.team.participants.all(), valid=False) if missing_payments.exists(): text = _("The team {trigram} has {nb_missing_payments} missing payments. Each member of the team " "must have a valid payment (or send a scholarship notification) " "to participate to the tournament.
" "Participants that have not paid yet are: {participants}.
") content = format_lazy(text, trigram=self.team.trigram, nb_missing_payments=missing_payments.count(), - participants=", ".join(str(p.registration) for p in missing_payments.all())) + participants=", ".join(", ".join(str(r) for r in p.registrations.all()) + for p in missing_payments.all())) informations.append({ 'title': _("Missing payments"), 'type': "danger", diff --git a/participation/views.py b/participation/views.py index ef86d41..5b2735d 100644 --- a/participation/views.py +++ b/participation/views.py @@ -30,7 +30,7 @@ from odf.opendocument import OpenDocumentSpreadsheet from odf.style import Style, TableCellProperties, TableColumnProperties, TextProperties from odf.table import CoveredTableCell, Table, TableCell, TableColumn, TableRow from odf.text import P -from registration.models import StudentRegistration, VolunteerRegistration +from registration.models import Payment, StudentRegistration, VolunteerRegistration from tfjm.lists import get_sympa_client from tfjm.views import AdminMixin, VolunteerMixin @@ -246,16 +246,20 @@ class TeamDetailView(LoginRequiredMixin, FormMixin, ProcessFormView, DetailView) mail_html = render_to_string("participation/mails/team_validated.html", mail_context) send_mail("[TFJM²] Équipe validée", mail_plain, None, [self.object.email], html_message=mail_html) - if self.object.participation.tournament.price == 0: - for registration in self.object.participants.all(): - registration.payment.type = "free" - registration.payment.valid = True - registration.payment.save() - else: - for coach in self.object.coaches.all(): - coach.payment.type = "free" - coach.payment.valid = True - coach.payment.save() + for student in self.object.students.all(): + payment_qs = Payment.objects.filter(registrations=student) + if payment_qs.exists(): + payment = payment_qs.get() + else: + payment = Payment.objects.create() + payment.registrations.add(student) + payment.save() + payment.amount = self.object.participation.tournament.price + if payment.amount == 0: + payment.type = "free" + payment.valid = True + payment.save() + elif "invalidate" in self.request.POST: self.object.participation.valid = None self.object.participation.save() diff --git a/registration/admin.py b/registration/admin.py index 0ac81ef..ec32bc3 100644 --- a/registration/admin.py +++ b/registration/admin.py @@ -97,11 +97,12 @@ class VolunteerRegistrationAdmin(PolymorphicChildModelAdmin): @admin.register(Payment) class PaymentAdmin(ModelAdmin): - list_display = ('registration', 'registration_type', 'type', 'valid', ) - search_fields = ('registration__user__last_name', 'registration__user__first_name', 'registration__user__email',) - list_filter = ('registration__team__participation__valid', 'type', 'type', 'valid',) - autocomplete_fields = ('registration',) + list_display = ('id', 'concerned_people', 'grouped', 'type', 'valid', ) + search_fields = ('registrations__user__last_name', 'registrations__user__first_name', 'registrations__user__email',) + list_filter = ('registrations__team__participation__valid', 'type', + 'grouped', 'valid', 'registrations__polymorphic_ctype',) + autocomplete_fields = ('registrations',) - @admin.display(description=_('registration type'), ordering='registration__polymorphic_ctype') - def registration_type(self, record: Payment): - return record.registration.get_real_instance().type + @admin.display(description=_('concerned people')) + def concerned_people(self, record: Payment): + return ", ".join(f"{reg.user.first_name} {reg.user.last_name}" for reg in record.registrations.all()) diff --git a/registration/apps.py b/registration/apps.py index 9e5146f..4bf3921 100644 --- a/registration/apps.py +++ b/registration/apps.py @@ -12,11 +12,8 @@ class RegistrationConfig(AppConfig): name = 'registration' def ready(self): - from registration.signals import create_admin_registration, create_payment, \ + from registration.signals import create_admin_registration, \ set_username, send_email_link pre_save.connect(set_username, "auth.User") pre_save.connect(send_email_link, "auth.User") post_save.connect(create_admin_registration, "auth.User") - post_save.connect(create_payment, "registration.Registration") - post_save.connect(create_payment, "registration.StudentRegistration") - post_save.connect(create_payment, "registration.CoachRegistration") diff --git a/registration/forms.py b/registration/forms.py index 9fed38b..3d09225 100644 --- a/registration/forms.py +++ b/registration/forms.py @@ -227,25 +227,25 @@ class PaymentForm(forms.ModelForm): super().__init__(*args, **kwargs) self.fields["valid"].widget.choices[0] = ('unknown', _("Pending")) - def clean_scholarship_file(self): + def clean_receipt(self): print(self.files) - if "scholarship_file" in self.files: - file = self.files["scholarship_file"] + if "receipt" in self.files: + file = self.files["receipt"] if file.size > 2e6: raise ValidationError(_("The uploaded file size must be under 2 Mo.")) if file.content_type not in ["application/pdf", "image/png", "image/jpeg"]: raise ValidationError(_("The uploaded file must be a PDF, PNG of JPEG file.")) - return self.cleaned_data["scholarship_file"] + return self.cleaned_data["receipt"] def clean(self): cleaned_data = super().clean() - if "type" in cleaned_data and cleaned_data["type"] == "scholarship" \ - and "scholarship_file" not in self.files and not self.instance.scholarship_file: - self.add_error("scholarship_file", _("You must upload your scholarship attestation.")) + if "type" in cleaned_data and cleaned_data['type'] in ["scholarship", "bank_transfer"] \ + and "receipt" not in self.files and not self.instance.scholarship_file: + self.add_error("receipt", _("You must upload your receipt.")) return cleaned_data class Meta: model = Payment - fields = ('type', 'scholarship_file', 'additional_information', 'valid',) + fields = ('type', 'receipt', 'additional_information', 'valid',) diff --git a/registration/migrations/0011_remove_payment_registration_and_more.py b/registration/migrations/0011_remove_payment_registration_and_more.py new file mode 100644 index 0000000..6de8358 --- /dev/null +++ b/registration/migrations/0011_remove_payment_registration_and_more.py @@ -0,0 +1,76 @@ +# Generated by Django 5.0.1 on 2024-02-12 20:40 + +import registration.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registration", "0010_coachregistration_last_degree"), + ] + + operations = [ + migrations.RemoveField( + model_name="payment", + name="registration", + ), + migrations.RemoveField( + model_name="payment", + name="scholarship_file", + ), + migrations.AddField( + model_name="payment", + name="amount", + field=models.PositiveSmallIntegerField( + default=0, + help_text="Corresponds to the total required amount to pay, in euros.", + verbose_name="total amount", + ), + ), + migrations.AddField( + model_name="payment", + name="checkout_intent_id", + field=models.IntegerField( + blank=True, + default=None, + null=True, + verbose_name="Hello Asso checkout intent ID", + ), + ), + migrations.AddField( + model_name="payment", + name="final", + field=models.BooleanField( + default=False, verbose_name="for final tournament" + ), + ), + migrations.AddField( + model_name="payment", + name="grouped", + field=models.BooleanField( + default=False, + help_text="If set to true, then one payment is made for the full team, for example if the school pays for all.", + verbose_name="grouped", + ), + ), + migrations.AddField( + model_name="payment", + name="receipt", + field=models.FileField( + blank=True, + default="", + help_text="only if you have a scholarship or if you chose a bank transfer.", + upload_to=registration.models.get_scholarship_filename, + verbose_name="receipt", + ), + ), + migrations.AddField( + model_name="payment", + name="registrations", + field=models.ManyToManyField( + related_name="payments", + to="registration.participantregistration", + verbose_name="registrations", + ), + ), + ] diff --git a/registration/models.py b/registration/models.py index cb34b32..87f95ee 100644 --- a/registration/models.py +++ b/registration/models.py @@ -364,27 +364,28 @@ class StudentRegistration(ParticipantRegistration): }) if self.team and self.team.participation.valid: - if self.payment.valid is False: - text = _("You have to pay {amount} € for your registration, or send a scholarship " - "notification or a payment proof. " - "You can do it on the payment page.") - url = reverse_lazy("registration:update_payment", args=(self.payment.id,)) - content = format_lazy(text, amount=self.team.participation.tournament.price, url=url) - informations.append({ - 'title': _("Payment"), - 'type': "danger", - 'priority': 3, - 'content': content, - }) - elif self.payment.valid is None: - text = _("Your payment is under approval.") - content = text - informations.append({ - 'title': _("Payment"), - 'type': "warning", - 'priority': 3, - 'content': content, - }) + for payment in self.payments.all(): + if payment.valid is False: + text = _("You have to pay {amount} € for your registration, or send a scholarship " + "notification or a payment proof. " + "You can do it on the payment page.") + url = reverse_lazy("registration:update_payment", args=(payment.id,)) + content = format_lazy(text, amount=payment.amount, url=url) + informations.append({ + 'title': _("Payment"), + 'type': "danger", + 'priority': 3, + 'content': content, + }) + elif self.payment.valid is None: + text = _("Your payment is under approval.") + content = text + informations.append({ + 'title': _("Payment"), + 'type': "warning", + 'priority': 3, + 'content': content, + }) return informations @@ -496,11 +497,28 @@ def get_scholarship_filename(instance, filename): class Payment(models.Model): - registration = models.OneToOneField( + registrations = models.ManyToManyField( ParticipantRegistration, - on_delete=models.CASCADE, - related_name="payment", - verbose_name=_("registration"), + related_name="payments", + verbose_name=_("registrations"), + ) + + grouped = models.BooleanField( + verbose_name=_("grouped"), + default=False, + help_text=_("If set to true, then one payment is made for the full team, " + "for example if the school pays for all."), + ) + + amount = models.PositiveSmallIntegerField( + verbose_name=_("total amount"), + help_text=_("Corresponds to the total required amount to pay, in euros."), + default=0, + ) + + final = models.BooleanField( + verbose_name=_("for final tournament"), + default=False, ) type = models.CharField( @@ -518,9 +536,16 @@ class Payment(models.Model): default="", ) - scholarship_file = models.FileField( - verbose_name=_("scholarship file"), - help_text=_("only if you have a scholarship."), + checkout_intent_id = models.IntegerField( + verbose_name=_("Hello Asso checkout intent ID"), + blank=True, + null=True, + default=None, + ) + + receipt = models.FileField( + verbose_name=_("receipt"), + help_text=_("only if you have a scholarship or if you chose a bank transfer."), upload_to=get_scholarship_filename, blank=True, default="", @@ -540,10 +565,10 @@ class Payment(models.Model): ) def get_absolute_url(self): - return reverse_lazy("registration:user_detail", args=(self.registration.user.id,)) + return reverse_lazy("registration:update_payment", args=(self.pk,)) def __str__(self): - return _("Payment of {registration}").format(registration=self.registration) + return _("Payment of {registrations}").format(registrations=", ".join(map(str, self.registrations.all()))) class Meta: verbose_name = _("payment") diff --git a/registration/signals.py b/registration/signals.py index eb11750..eda4107 100644 --- a/registration/signals.py +++ b/registration/signals.py @@ -4,7 +4,7 @@ from django.contrib.auth.models import User from tfjm.lists import get_sympa_client -from .models import Payment, Registration, VolunteerRegistration +from .models import Registration, VolunteerRegistration def set_username(instance, **_): @@ -41,16 +41,3 @@ def create_admin_registration(instance, **_): """ if instance.is_superuser: VolunteerRegistration.objects.get_or_create(user=instance, admin=True) - - -def create_payment(instance: Registration, raw, **_): - """ - When a user is saved, create the associated payment. - For a free tournament, the payment is valid. - """ - if instance.participates and not raw: - payment = Payment.objects.get_or_create(registration=instance)[0] - if instance.team and instance.team.participation.valid and instance.team.participation.tournament.price == 0: - payment.valid = True - payment.type = "free" - payment.save() diff --git a/registration/templates/registration/user_detail.html b/registration/templates/registration/user_detail.html index 1f740ac..05cec5a 100644 --- a/registration/templates/registration/user_detail.html +++ b/registration/templates/registration/user_detail.html @@ -143,35 +143,42 @@ {% if user_object.registration.participates and user_object.registration.team.participation.valid %} -