Update GSheets for ETEAM
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
parent
44302a9ff4
commit
d13ae89267
|
@ -7,7 +7,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TFJM\n"
|
"Project-Id-Version: TFJM\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-07-05 11:45+0200\n"
|
"POT-Creation-Date: 2024-07-05 16:44+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
|
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -78,8 +78,8 @@ msgstr "Type de permission nécessaire pour écrire un message dans un canal."
|
||||||
|
|
||||||
#: chat/models.py:62 draw/admin.py:53 draw/admin.py:71 draw/admin.py:88
|
#: chat/models.py:62 draw/admin.py:53 draw/admin.py:71 draw/admin.py:88
|
||||||
#: draw/models.py:27 participation/admin.py:79 participation/admin.py:144
|
#: draw/models.py:27 participation/admin.py:79 participation/admin.py:144
|
||||||
#: participation/admin.py:176 participation/models.py:727
|
#: participation/admin.py:176 participation/models.py:781
|
||||||
#: participation/models.py:751 participation/models.py:1060
|
#: participation/models.py:805 participation/models.py:1114
|
||||||
#: registration/models.py:763
|
#: registration/models.py:763
|
||||||
#: registration/templates/registration/payment_form.html:53
|
#: registration/templates/registration/payment_form.html:53
|
||||||
msgid "tournament"
|
msgid "tournament"
|
||||||
|
@ -95,7 +95,7 @@ msgstr ""
|
||||||
|
|
||||||
#: chat/models.py:73 draw/models.py:446 draw/models.py:473
|
#: chat/models.py:73 draw/models.py:446 draw/models.py:473
|
||||||
#: participation/admin.py:140 participation/admin.py:160
|
#: participation/admin.py:140 participation/admin.py:160
|
||||||
#: participation/models.py:1563 participation/models.py:1572
|
#: participation/models.py:1642 participation/models.py:1651
|
||||||
#: participation/tables.py:84
|
#: participation/tables.py:84
|
||||||
msgid "pool"
|
msgid "pool"
|
||||||
msgstr "poule"
|
msgstr "poule"
|
||||||
|
@ -109,7 +109,7 @@ msgstr ""
|
||||||
|
|
||||||
#: chat/models.py:84 draw/templates/draw/tournament_content.html:277
|
#: chat/models.py:84 draw/templates/draw/tournament_content.html:277
|
||||||
#: participation/admin.py:172 participation/models.py:261
|
#: participation/admin.py:172 participation/models.py:261
|
||||||
#: participation/models.py:742
|
#: participation/models.py:796
|
||||||
#: participation/templates/participation/tournament_harmonize.html:15
|
#: participation/templates/participation/tournament_harmonize.html:15
|
||||||
#: registration/models.py:158 registration/models.py:754
|
#: registration/models.py:158 registration/models.py:754
|
||||||
#: registration/tables.py:39
|
#: registration/tables.py:39
|
||||||
|
@ -265,11 +265,11 @@ msgid "teams"
|
||||||
msgstr "équipes"
|
msgstr "équipes"
|
||||||
|
|
||||||
#: draw/admin.py:92 draw/models.py:245 draw/models.py:465
|
#: draw/admin.py:92 draw/models.py:245 draw/models.py:465
|
||||||
#: participation/models.py:1064
|
#: participation/models.py:1118
|
||||||
msgid "round"
|
msgid "round"
|
||||||
msgstr "tour"
|
msgstr "tour"
|
||||||
|
|
||||||
#: draw/apps.py:10 draw/consumers.py:1037 tfjm/templates/navbar.html:68
|
#: draw/apps.py:10 draw/consumers.py:1038 tfjm/templates/navbar.html:68
|
||||||
msgid "Draw"
|
msgid "Draw"
|
||||||
msgstr "Tirage au sort"
|
msgstr "Tirage au sort"
|
||||||
|
|
||||||
|
@ -309,9 +309,9 @@ msgstr "Le tirage au sort du tournoi {tournament} a commencé !"
|
||||||
msgid "The draw for the tournament {tournament} will start."
|
msgid "The draw for the tournament {tournament} will start."
|
||||||
msgstr "Le tirage au sort du tournoi {tournament} va commencer."
|
msgstr "Le tirage au sort du tournoi {tournament} va commencer."
|
||||||
|
|
||||||
#: draw/consumers.py:256 draw/consumers.py:282 draw/consumers.py:691
|
#: draw/consumers.py:256 draw/consumers.py:282 draw/consumers.py:692
|
||||||
#: draw/consumers.py:909 draw/consumers.py:999 draw/consumers.py:1021
|
#: draw/consumers.py:910 draw/consumers.py:1000 draw/consumers.py:1022
|
||||||
#: draw/consumers.py:1112 draw/templates/draw/tournament_content.html:5
|
#: draw/consumers.py:1113 draw/templates/draw/tournament_content.html:5
|
||||||
msgid "The draw has not started yet."
|
msgid "The draw has not started yet."
|
||||||
msgstr "Le tirage au sort n'a pas encore commencé."
|
msgstr "Le tirage au sort n'a pas encore commencé."
|
||||||
|
|
||||||
|
@ -320,8 +320,8 @@ msgstr "Le tirage au sort n'a pas encore commencé."
|
||||||
msgid "The draw for the tournament {tournament} is aborted."
|
msgid "The draw for the tournament {tournament} is aborted."
|
||||||
msgstr "Le tirage au sort du tournoi {tournament} est annulé."
|
msgstr "Le tirage au sort du tournoi {tournament} est annulé."
|
||||||
|
|
||||||
#: draw/consumers.py:309 draw/consumers.py:330 draw/consumers.py:625
|
#: draw/consumers.py:309 draw/consumers.py:330 draw/consumers.py:626
|
||||||
#: draw/consumers.py:696 draw/consumers.py:914
|
#: draw/consumers.py:697 draw/consumers.py:915
|
||||||
msgid "This is not the time for this."
|
msgid "This is not the time for this."
|
||||||
msgstr "Ce n'est pas le moment pour cela."
|
msgstr "Ce n'est pas le moment pour cela."
|
||||||
|
|
||||||
|
@ -362,21 +362,21 @@ msgstr ""
|
||||||
"de dés, par ordre croissant. Pour le deuxième tour, les ordres de passage "
|
"de dés, par ordre croissant. Pour le deuxième tour, les ordres de passage "
|
||||||
"sont déterminés à partir des ordres de passage du premier tour."
|
"sont déterminés à partir des ordres de passage du premier tour."
|
||||||
|
|
||||||
#: draw/consumers.py:614 draw/consumers.py:754 draw/consumers.py:831
|
#: draw/consumers.py:615 draw/consumers.py:755 draw/consumers.py:832
|
||||||
#: draw/consumers.py:865 draw/consumers.py:990 draw/consumers.py:1088
|
#: draw/consumers.py:866 draw/consumers.py:991 draw/consumers.py:1089
|
||||||
msgid "Your turn!"
|
msgid "Your turn!"
|
||||||
msgstr "À votre tour !"
|
msgstr "À votre tour !"
|
||||||
|
|
||||||
#: draw/consumers.py:615 draw/consumers.py:755 draw/consumers.py:991
|
#: draw/consumers.py:616 draw/consumers.py:756 draw/consumers.py:992
|
||||||
#: draw/consumers.py:1089
|
#: draw/consumers.py:1090
|
||||||
msgid "It's your turn to draw a problem!"
|
msgid "It's your turn to draw a problem!"
|
||||||
msgstr "C'est à vous de tirer un problème !"
|
msgstr "C'est à vous de tirer un problème !"
|
||||||
|
|
||||||
#: draw/consumers.py:635 draw/consumers.py:706 draw/consumers.py:924
|
#: draw/consumers.py:636 draw/consumers.py:707 draw/consumers.py:925
|
||||||
msgid "This is not your turn."
|
msgid "This is not your turn."
|
||||||
msgstr "Ce n'est pas votre tour."
|
msgstr "Ce n'est pas votre tour."
|
||||||
|
|
||||||
#: draw/consumers.py:713
|
#: draw/consumers.py:714
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"The team <strong>{trigram}</strong> accepted the problem <string>{problem}</"
|
"The team <strong>{trigram}</strong> accepted the problem <string>{problem}</"
|
||||||
|
@ -385,33 +385,33 @@ msgstr ""
|
||||||
"L'équipe <strong>{trigram}</strong> a accepté le problème <strong>{problem}</"
|
"L'équipe <strong>{trigram}</strong> a accepté le problème <strong>{problem}</"
|
||||||
"strong> : {problem_name}. "
|
"strong> : {problem_name}. "
|
||||||
|
|
||||||
#: draw/consumers.py:717
|
#: draw/consumers.py:718
|
||||||
msgid "One team more can accept this problem."
|
msgid "One team more can accept this problem."
|
||||||
msgstr "Une équipe de plus peut accepter ce problème."
|
msgstr "Une équipe de plus peut accepter ce problème."
|
||||||
|
|
||||||
#: draw/consumers.py:719
|
#: draw/consumers.py:720
|
||||||
msgid "No team can accept this problem anymore."
|
msgid "No team can accept this problem anymore."
|
||||||
msgstr "Aucune autre équipe ne peut accepter ce problème."
|
msgstr "Aucune autre équipe ne peut accepter ce problème."
|
||||||
|
|
||||||
#: draw/consumers.py:813
|
#: draw/consumers.py:814
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The draw of the pool {pool} is ended. The summary is below."
|
msgid "The draw of the pool {pool} is ended. The summary is below."
|
||||||
msgstr "Le tirage de la poule {pool} est terminé. Le résumé est ci-dessous."
|
msgstr "Le tirage de la poule {pool} est terminé. Le résumé est ci-dessous."
|
||||||
|
|
||||||
#: draw/consumers.py:832 draw/consumers.py:866
|
#: draw/consumers.py:833 draw/consumers.py:867
|
||||||
msgid "It's your turn to launch the dice!"
|
msgid "It's your turn to launch the dice!"
|
||||||
msgstr "C'est à vous de lancer le dé !"
|
msgstr "C'est à vous de lancer le dé !"
|
||||||
|
|
||||||
#: draw/consumers.py:852
|
#: draw/consumers.py:853
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The draw of the round {round} is ended."
|
msgid "The draw of the round {round} is ended."
|
||||||
msgstr "Le tirage au sort du tour {round} est annulé."
|
msgstr "Le tirage au sort du tour {round} est annulé."
|
||||||
|
|
||||||
#: draw/consumers.py:895
|
#: draw/consumers.py:896
|
||||||
msgid "The draw of the first round is ended."
|
msgid "The draw of the first round is ended."
|
||||||
msgstr "Le tirage au sort du premier tour est terminé."
|
msgstr "Le tirage au sort du premier tour est terminé."
|
||||||
|
|
||||||
#: draw/consumers.py:938
|
#: draw/consumers.py:939
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"The team <strong>{trigram}</strong> refused the problem <strong>{problem}</"
|
"The team <strong>{trigram}</strong> refused the problem <strong>{problem}</"
|
||||||
|
@ -420,26 +420,26 @@ msgstr ""
|
||||||
"L'équipe <strong>{trigram}</strong> a refusé le problème <strong>{problem}</"
|
"L'équipe <strong>{trigram}</strong> a refusé le problème <strong>{problem}</"
|
||||||
"strong> : {problem_name}."
|
"strong> : {problem_name}."
|
||||||
|
|
||||||
#: draw/consumers.py:942
|
#: draw/consumers.py:943
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "It remains {remaining} refusals without penalty."
|
msgid "It remains {remaining} refusals without penalty."
|
||||||
msgstr "Il reste {remaining} refus sans pénalité."
|
msgstr "Il reste {remaining} refus sans pénalité."
|
||||||
|
|
||||||
#: draw/consumers.py:945
|
#: draw/consumers.py:946
|
||||||
msgid "This problem was already refused by this team."
|
msgid "This problem was already refused by this team."
|
||||||
msgstr "Ce problème a déjà été refusé par cette équipe."
|
msgstr "Ce problème a déjà été refusé par cette équipe."
|
||||||
|
|
||||||
#: draw/consumers.py:947
|
#: draw/consumers.py:948
|
||||||
msgid "It adds a 25% penalty on the coefficient of the oral defense."
|
msgid "It adds a 25% penalty on the coefficient of the oral defense."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Cela ajoute une pénalité de 25 % sur le coefficient de l'oral de la "
|
"Cela ajoute une pénalité de 25 % sur le coefficient de l'oral de la "
|
||||||
"défense."
|
"défense."
|
||||||
|
|
||||||
#: draw/consumers.py:1024
|
#: draw/consumers.py:1025
|
||||||
msgid "This is only available for the final tournament."
|
msgid "This is only available for the final tournament."
|
||||||
msgstr "Cela n'est possible que pour la finale."
|
msgstr "Cela n'est possible que pour la finale."
|
||||||
|
|
||||||
#: draw/consumers.py:1028
|
#: draw/consumers.py:1029
|
||||||
msgid ""
|
msgid ""
|
||||||
"The draw of the round 2 is starting. The passage order is determined from "
|
"The draw of the round 2 is starting. The passage order is determined from "
|
||||||
"the ranking of the first round, in order to mix the teams between the two "
|
"the ranking of the first round, in order to mix the teams between the two "
|
||||||
|
@ -449,7 +449,7 @@ msgstr ""
|
||||||
"partir du classement du premier tour, afin de mélanger les équipes entre les "
|
"partir du classement du premier tour, afin de mélanger les équipes entre les "
|
||||||
"deux jours."
|
"deux jours."
|
||||||
|
|
||||||
#: draw/consumers.py:1038
|
#: draw/consumers.py:1039
|
||||||
msgid "The draw of the second round is starting!"
|
msgid "The draw of the second round is starting!"
|
||||||
msgstr "Le tirage au sort du deuxième tour commence !"
|
msgstr "Le tirage au sort du deuxième tour commence !"
|
||||||
|
|
||||||
|
@ -626,7 +626,7 @@ msgid "The current pool where teams select their problems."
|
||||||
msgstr "La poule en cours, où les équipes choisissent leurs problèmes"
|
msgstr "La poule en cours, où les équipes choisissent leurs problèmes"
|
||||||
|
|
||||||
#: draw/models.py:239
|
#: draw/models.py:239
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The number of the round must be between 1 and {nb}."
|
msgid "The number of the round must be between 1 and {nb}."
|
||||||
msgstr "Le numéro du tour doit être entre 1 et {nb}."
|
msgstr "Le numéro du tour doit être entre 1 et {nb}."
|
||||||
|
|
||||||
|
@ -634,7 +634,7 @@ msgstr "Le numéro du tour doit être entre 1 et {nb}."
|
||||||
msgid "rounds"
|
msgid "rounds"
|
||||||
msgstr "tours"
|
msgstr "tours"
|
||||||
|
|
||||||
#: draw/models.py:268 participation/models.py:1072
|
#: draw/models.py:268 participation/models.py:1126
|
||||||
msgid "letter"
|
msgid "letter"
|
||||||
msgstr "lettre"
|
msgstr "lettre"
|
||||||
|
|
||||||
|
@ -672,12 +672,12 @@ msgstr "L'instance complète de la poule."
|
||||||
msgid "Pool {letter}{number}"
|
msgid "Pool {letter}{number}"
|
||||||
msgstr "Poule {letter}{number}"
|
msgstr "Poule {letter}{number}"
|
||||||
|
|
||||||
#: draw/models.py:447 participation/models.py:1564
|
#: draw/models.py:447 participation/models.py:1643
|
||||||
msgid "pools"
|
msgid "pools"
|
||||||
msgstr "poules"
|
msgstr "poules"
|
||||||
|
|
||||||
#: draw/models.py:459 participation/models.py:1050 participation/models.py:1754
|
#: draw/models.py:459 participation/models.py:1104 participation/models.py:1862
|
||||||
#: participation/models.py:1784 participation/models.py:1826
|
#: participation/models.py:1892 participation/models.py:1934
|
||||||
msgid "participation"
|
msgid "participation"
|
||||||
msgstr "participation"
|
msgstr "participation"
|
||||||
|
|
||||||
|
@ -701,8 +701,9 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
|
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
|
||||||
|
|
||||||
#: draw/models.py:496 draw/models.py:519 participation/models.py:1586
|
#: draw/models.py:496 draw/models.py:519 participation/models.py:1234
|
||||||
#: participation/models.py:1791
|
#: participation/models.py:1665 participation/models.py:1899
|
||||||
|
#: participation/views.py:1487 participation/views.py:1752
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Problem #{problem}"
|
msgid "Problem #{problem}"
|
||||||
msgstr "Problème n°{problem}"
|
msgstr "Problème n°{problem}"
|
||||||
|
@ -913,31 +914,31 @@ msgstr "Changelog de type \"{action}\" pour le modèle {model} le {timestamp}"
|
||||||
msgid "valid"
|
msgid "valid"
|
||||||
msgstr "valide"
|
msgstr "valide"
|
||||||
|
|
||||||
#: participation/admin.py:87 participation/models.py:763
|
#: participation/admin.py:87 participation/models.py:817
|
||||||
msgid "selected for final"
|
msgid "selected for final"
|
||||||
msgstr "sélectionnée pour la finale"
|
msgstr "sélectionnée pour la finale"
|
||||||
|
|
||||||
#: participation/admin.py:124 participation/admin.py:188
|
#: participation/admin.py:124 participation/admin.py:188
|
||||||
#: participation/models.py:1593 participation/tables.py:114
|
#: participation/models.py:1672 participation/tables.py:114
|
||||||
msgid "defender"
|
msgid "defender"
|
||||||
msgstr "défenseur⋅se"
|
msgstr "défenseur⋅se"
|
||||||
|
|
||||||
#: participation/admin.py:128 participation/models.py:1600
|
#: participation/admin.py:128 participation/models.py:1679
|
||||||
#: participation/models.py:1838
|
#: participation/models.py:1946
|
||||||
msgid "opponent"
|
msgid "opponent"
|
||||||
msgstr "opposant⋅e"
|
msgstr "opposant⋅e"
|
||||||
|
|
||||||
#: participation/admin.py:132 participation/models.py:1607
|
#: participation/admin.py:132 participation/models.py:1686
|
||||||
#: participation/models.py:1839
|
#: participation/models.py:1947
|
||||||
msgid "reviewer"
|
msgid "reviewer"
|
||||||
msgstr "rapporteur⋅rice"
|
msgstr "rapporteur⋅rice"
|
||||||
|
|
||||||
#: participation/admin.py:136 participation/models.py:1614
|
#: participation/admin.py:136 participation/models.py:1693
|
||||||
#: participation/models.py:1840
|
#: participation/models.py:1948
|
||||||
msgid "observer"
|
msgid "observer"
|
||||||
msgstr "observateur⋅rice"
|
msgstr "observateur⋅rice"
|
||||||
|
|
||||||
#: participation/admin.py:192 participation/models.py:1789
|
#: participation/admin.py:192 participation/models.py:1897
|
||||||
msgid "problem"
|
msgid "problem"
|
||||||
msgstr "numéro de problème"
|
msgstr "numéro de problème"
|
||||||
|
|
||||||
|
@ -961,7 +962,7 @@ msgstr "Aucune équipe n'a été trouvée avec ce code d'accès."
|
||||||
msgid "The team is already validated or the validation is pending."
|
msgid "The team is already validated or the validation is pending."
|
||||||
msgstr "La validation de l'équipe est déjà faite ou en cours."
|
msgstr "La validation de l'équipe est déjà faite ou en cours."
|
||||||
|
|
||||||
#: participation/forms.py:94 participation/forms.py:366
|
#: participation/forms.py:94 participation/forms.py:367
|
||||||
#: registration/forms.py:126 registration/forms.py:148
|
#: registration/forms.py:126 registration/forms.py:148
|
||||||
#: registration/forms.py:170 registration/forms.py:192
|
#: registration/forms.py:170 registration/forms.py:192
|
||||||
#: registration/forms.py:214 registration/forms.py:236
|
#: registration/forms.py:214 registration/forms.py:236
|
||||||
|
@ -989,7 +990,7 @@ msgstr "Message à adresser à l'équipe :"
|
||||||
msgid "The uploaded file size must be under 5 Mo."
|
msgid "The uploaded file size must be under 5 Mo."
|
||||||
msgstr "Le fichier envoyé doit peser moins de 5 Mo."
|
msgstr "Le fichier envoyé doit peser moins de 5 Mo."
|
||||||
|
|
||||||
#: participation/forms.py:178 participation/forms.py:368
|
#: participation/forms.py:178 participation/forms.py:369
|
||||||
msgid "The uploaded file must be a PDF file."
|
msgid "The uploaded file must be a PDF file."
|
||||||
msgstr "Le fichier envoyé doit être au format PDF."
|
msgstr "Le fichier envoyé doit être au format PDF."
|
||||||
|
|
||||||
|
@ -1017,24 +1018,24 @@ msgstr ""
|
||||||
"Ce fichier contient des éléments non-UTF-8 et non-ISO-8859-1. Merci "
|
"Ce fichier contient des éléments non-UTF-8 et non-ISO-8859-1. Merci "
|
||||||
"d'envoyer votre tableur au format CSV."
|
"d'envoyer votre tableur au format CSV."
|
||||||
|
|
||||||
#: participation/forms.py:327
|
#: participation/forms.py:328
|
||||||
msgid "The following note is higher of the maximum expected value:"
|
msgid "The following note is higher of the maximum expected value:"
|
||||||
msgstr "La note suivante est supérieure au maximum attendu :"
|
msgstr "La note suivante est supérieure au maximum attendu :"
|
||||||
|
|
||||||
#: participation/forms.py:333
|
#: participation/forms.py:334
|
||||||
msgid "The following user was not found:"
|
msgid "The following user was not found:"
|
||||||
msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :"
|
msgstr "L'utilisateur⋅rice suivant n'a pas été trouvé :"
|
||||||
|
|
||||||
#: participation/forms.py:349
|
#: participation/forms.py:350
|
||||||
msgid "The defender, the opponent and the reviewer must be different."
|
msgid "The defender, the opponent and the reviewer must be different."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Les équipes défenseuse, opposante et rapportrice doivent être différent⋅es."
|
"Les équipes défenseuse, opposante et rapportrice doivent être différent⋅es."
|
||||||
|
|
||||||
#: participation/forms.py:353
|
#: participation/forms.py:354
|
||||||
msgid "This defender did not work on this problem."
|
msgid "This defender did not work on this problem."
|
||||||
msgstr "Ce⋅tte défenseur⋅se ne travaille pas sur ce problème."
|
msgstr "Ce⋅tte défenseur⋅se ne travaille pas sur ce problème."
|
||||||
|
|
||||||
#: participation/forms.py:372
|
#: participation/forms.py:373
|
||||||
msgid "The PDF file must not have more than 2 pages."
|
msgid "The PDF file must not have more than 2 pages."
|
||||||
msgstr "Le fichier PDF ne doit pas avoir plus de 2 pages."
|
msgstr "Le fichier PDF ne doit pas avoir plus de 2 pages."
|
||||||
|
|
||||||
|
@ -1287,36 +1288,100 @@ msgstr "finale"
|
||||||
msgid "Google Sheet ID"
|
msgid "Google Sheet ID"
|
||||||
msgstr "ID de la feuille Google Sheets"
|
msgstr "ID de la feuille Google Sheets"
|
||||||
|
|
||||||
#: participation/models.py:728 registration/admin.py:125
|
#: participation/models.py:473 participation/models.py:474
|
||||||
|
#: participation/models.py:476 participation/models.py:714
|
||||||
|
msgid "Final ranking"
|
||||||
|
msgstr "Classement final"
|
||||||
|
|
||||||
|
#: participation/models.py:481 participation/models.py:551
|
||||||
|
#: participation/models.py:1309 participation/views.py:1726
|
||||||
|
msgid "Team"
|
||||||
|
msgstr "Équipe"
|
||||||
|
|
||||||
|
#: participation/models.py:481
|
||||||
|
msgid "Scores day 1"
|
||||||
|
msgstr "Scores jour 1"
|
||||||
|
|
||||||
|
#: participation/models.py:481
|
||||||
|
msgid "Tweaks day 1"
|
||||||
|
msgstr "Ajustements 1"
|
||||||
|
|
||||||
|
#: participation/models.py:481
|
||||||
|
msgid "Scores day 2"
|
||||||
|
msgstr "Scores jour 2"
|
||||||
|
|
||||||
|
#: participation/models.py:481
|
||||||
|
msgid "Tweaks day 2"
|
||||||
|
msgstr "Ajustements 2"
|
||||||
|
|
||||||
|
#: participation/models.py:482
|
||||||
|
msgid "Total D1 + D2"
|
||||||
|
msgstr "Total J1 + J2"
|
||||||
|
|
||||||
|
#: participation/models.py:482
|
||||||
|
msgid "Scores day 3"
|
||||||
|
msgstr "Scores jour 3"
|
||||||
|
|
||||||
|
#: participation/models.py:482
|
||||||
|
msgid "Tweaks day 3"
|
||||||
|
msgstr "Ajustements 3"
|
||||||
|
|
||||||
|
#: participation/models.py:484 participation/models.py:1309
|
||||||
|
#: participation/views.py:1733
|
||||||
|
msgid "Total"
|
||||||
|
msgstr "Total"
|
||||||
|
|
||||||
|
#: participation/models.py:484 participation/models.py:551
|
||||||
|
#: participation/models.py:1309
|
||||||
|
#: participation/templates/participation/tournament_harmonize.html:14
|
||||||
|
#: participation/views.py:1736
|
||||||
|
msgid "Rank"
|
||||||
|
msgstr "Rang"
|
||||||
|
|
||||||
|
#: participation/models.py:551 participation/models.py:716
|
||||||
|
msgid "Score"
|
||||||
|
msgstr "Score"
|
||||||
|
|
||||||
|
#: participation/models.py:551
|
||||||
|
msgid "Mention"
|
||||||
|
msgstr "Mention"
|
||||||
|
|
||||||
|
#: participation/models.py:696 participation/models.py:1572
|
||||||
|
msgid "Don't update the table structure for a better automated integration."
|
||||||
|
msgstr ""
|
||||||
|
"Ne pas mettre à jour la structure de la table pour une meilleure intégration "
|
||||||
|
"automatisée."
|
||||||
|
|
||||||
|
#: participation/models.py:782 registration/admin.py:125
|
||||||
msgid "tournaments"
|
msgid "tournaments"
|
||||||
msgstr "tournois"
|
msgstr "tournois"
|
||||||
|
|
||||||
#: participation/models.py:757
|
#: participation/models.py:811
|
||||||
msgid "valid team"
|
msgid "valid team"
|
||||||
msgstr "équipe valide"
|
msgstr "équipe valide"
|
||||||
|
|
||||||
#: participation/models.py:758
|
#: participation/models.py:812
|
||||||
msgid "The participation got the validation of the organizers."
|
msgid "The participation got the validation of the organizers."
|
||||||
msgstr "La participation a été validée par les organisateur⋅rices."
|
msgstr "La participation a été validée par les organisateur⋅rices."
|
||||||
|
|
||||||
#: participation/models.py:764
|
#: participation/models.py:818
|
||||||
msgid "The team is selected for the final tournament."
|
msgid "The team is selected for the final tournament."
|
||||||
msgstr "L'équipe est sélectionnée pour la finale."
|
msgstr "L'équipe est sélectionnée pour la finale."
|
||||||
|
|
||||||
#: participation/models.py:768
|
#: participation/models.py:822
|
||||||
msgid "mention"
|
msgid "mention"
|
||||||
msgstr "mention"
|
msgstr "mention"
|
||||||
|
|
||||||
#: participation/models.py:775
|
#: participation/models.py:829
|
||||||
msgid "mention (final)"
|
msgid "mention (final)"
|
||||||
msgstr "Mention (pour la finale) :"
|
msgstr "Mention (pour la finale) :"
|
||||||
|
|
||||||
#: participation/models.py:785
|
#: participation/models.py:839
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Participation of the team {name} ({trigram})"
|
msgid "Participation of the team {name} ({trigram})"
|
||||||
msgstr "Participation de l'équipe {name} ({trigram})"
|
msgstr "Participation de l'équipe {name} ({trigram})"
|
||||||
|
|
||||||
#: participation/models.py:792
|
#: participation/models.py:846
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>The team {trigram} has {nb_missing_payments} missing payments. Each "
|
"<p>The team {trigram} has {nb_missing_payments} missing payments. Each "
|
||||||
|
@ -1329,11 +1394,11 @@ msgstr ""
|
||||||
"notification de bourse) pour participer au tournoi.</p><p>Les participant⋅es "
|
"notification de bourse) pour participer au tournoi.</p><p>Les participant⋅es "
|
||||||
"qui n'ont pas encore payé sont : {participants}.</p>"
|
"qui n'ont pas encore payé sont : {participants}.</p>"
|
||||||
|
|
||||||
#: participation/models.py:800
|
#: participation/models.py:854
|
||||||
msgid "Missing payments"
|
msgid "Missing payments"
|
||||||
msgstr "Paiements manquants"
|
msgstr "Paiements manquants"
|
||||||
|
|
||||||
#: participation/models.py:817
|
#: participation/models.py:871
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>The solutions for the tournament of {tournament} are due on the {date:%Y-"
|
"<p>The solutions for the tournament of {tournament} are due on the {date:%Y-"
|
||||||
"%m-%d %H:%M}.</p><p>You have currently sent <strong>{nb_solutions}</strong> "
|
"%m-%d %H:%M}.</p><p>You have currently sent <strong>{nb_solutions}</strong> "
|
||||||
|
@ -1348,11 +1413,11 @@ msgstr ""
|
||||||
"pouvez envoyer vos solutions sur <a href='{url}'>votre page de "
|
"pouvez envoyer vos solutions sur <a href='{url}'>votre page de "
|
||||||
"participation</a>.</p>"
|
"participation</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:827 participation/models.py:841
|
#: participation/models.py:881 participation/models.py:895
|
||||||
msgid "Solutions due"
|
msgid "Solutions due"
|
||||||
msgstr "Rendu des solutions"
|
msgstr "Rendu des solutions"
|
||||||
|
|
||||||
#: participation/models.py:833
|
#: participation/models.py:887
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>The solutions for the tournament of {tournament} are due on the {date:%Y-"
|
"<p>The solutions for the tournament of {tournament} are due on the {date:%Y-"
|
||||||
"%m-%d %H:%M}.</p><p>Remember that you can only fix minor changes to your "
|
"%m-%d %H:%M}.</p><p>Remember that you can only fix minor changes to your "
|
||||||
|
@ -1365,7 +1430,7 @@ msgstr ""
|
||||||
"parties.</p><p>Vous pouvez envoyer vos solutions sur <a href='{url}'>votre "
|
"parties.</p><p>Vous pouvez envoyer vos solutions sur <a href='{url}'>votre "
|
||||||
"page de participation</a>.</p>"
|
"page de participation</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:847 registration/models.py:607
|
#: participation/models.py:901 registration/models.py:607
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>The draw of the solutions for the tournament {tournament} is planned on "
|
"<p>The draw of the solutions for the tournament {tournament} is planned on "
|
||||||
"the {date:%Y-%m-%d %H:%M}. You can join it on <a href='{url}'>this link</a>."
|
"the {date:%Y-%m-%d %H:%M}. You can join it on <a href='{url}'>this link</a>."
|
||||||
|
@ -1375,11 +1440,11 @@ msgstr ""
|
||||||
"{date:%d/%m/%Y %H:%M}. Vous pouvez y participer sur <a href='{url}'>ce lien</"
|
"{date:%d/%m/%Y %H:%M}. Vous pouvez y participer sur <a href='{url}'>ce lien</"
|
||||||
"a>.</p>"
|
"a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:853 registration/models.py:614
|
#: participation/models.py:907 registration/models.py:614
|
||||||
msgid "Draw of solutions"
|
msgid "Draw of solutions"
|
||||||
msgstr "Tirage au sort des solutions"
|
msgstr "Tirage au sort des solutions"
|
||||||
|
|
||||||
#: participation/models.py:865
|
#: participation/models.py:919
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>The solutions draw is ended. You can check the result on <a "
|
"<p>The solutions draw is ended. You can check the result on <a "
|
||||||
|
@ -1391,8 +1456,8 @@ msgstr ""
|
||||||
"tour, vous défendrez <a href='{solution_url}'>votre solution du problème "
|
"tour, vous défendrez <a href='{solution_url}'>votre solution du problème "
|
||||||
"{problem}</a>.</p>"
|
"{problem}</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:874 participation/models.py:932
|
#: participation/models.py:928 participation/models.py:986
|
||||||
#: participation/models.py:991
|
#: participation/models.py:1045
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>You will oppose the solution of the team {opponent} on the <a "
|
"<p>You will oppose the solution of the team {opponent} on the <a "
|
||||||
|
@ -1403,8 +1468,8 @@ msgstr ""
|
||||||
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
||||||
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:883 participation/models.py:941
|
#: participation/models.py:937 participation/models.py:995
|
||||||
#: participation/models.py:1000
|
#: participation/models.py:1054
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>You will report the solution of the team {reviewer} on the <a "
|
"<p>You will report the solution of the team {reviewer} on the <a "
|
||||||
|
@ -1415,8 +1480,8 @@ msgstr ""
|
||||||
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
||||||
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:893 participation/models.py:951
|
#: participation/models.py:947 participation/models.py:1005
|
||||||
#: participation/models.py:1010
|
#: participation/models.py:1064
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>You will observe the solution of the team {observer} on the <a "
|
"<p>You will observe the solution of the team {observer} on the <a "
|
||||||
|
@ -1427,11 +1492,11 @@ msgstr ""
|
||||||
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
|
||||||
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:913 registration/models.py:629
|
#: participation/models.py:967 registration/models.py:629
|
||||||
msgid "First round"
|
msgid "First round"
|
||||||
msgstr "Premier tour"
|
msgstr "Premier tour"
|
||||||
|
|
||||||
#: participation/models.py:925
|
#: participation/models.py:979
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>For the second round, you will defend <a href='{solution_url}'>your "
|
"<p>For the second round, you will defend <a href='{solution_url}'>your "
|
||||||
|
@ -1440,12 +1505,12 @@ msgstr ""
|
||||||
"<p>Pour le second tour, vous défendrez <a href='{solution_url}'>votre "
|
"<p>Pour le second tour, vous défendrez <a href='{solution_url}'>votre "
|
||||||
"solution du problème {problem}</a>.</p>"
|
"solution du problème {problem}</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:971 participation/models.py:1030
|
#: participation/models.py:1025 participation/models.py:1084
|
||||||
#: registration/models.py:640
|
#: registration/models.py:640
|
||||||
msgid "Second round"
|
msgid "Second round"
|
||||||
msgstr "Second tour"
|
msgstr "Second tour"
|
||||||
|
|
||||||
#: participation/models.py:984
|
#: participation/models.py:1038
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>For the third round, you will defend <a href='{solution_url}'>your "
|
"<p>For the third round, you will defend <a href='{solution_url}'>your "
|
||||||
|
@ -1454,7 +1519,7 @@ msgstr ""
|
||||||
"<p>Pour le troisième tour, vous défendrez <a href='{solution_url}'>votre "
|
"<p>Pour le troisième tour, vous défendrez <a href='{solution_url}'>votre "
|
||||||
"solution du problème {problem}</a>.</p>"
|
"solution du problème {problem}</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:1036
|
#: participation/models.py:1090
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"<p>The tournament {tournament} is ended. You can check the results on the <a "
|
"<p>The tournament {tournament} is ended. You can check the results on the <a "
|
||||||
|
@ -1463,57 +1528,57 @@ msgstr ""
|
||||||
"<p>Le tournoi {tournament} est terminé. Vous pouvez consulter les résultats "
|
"<p>Le tournoi {tournament} est terminé. Vous pouvez consulter les résultats "
|
||||||
"sur la <a href='{url}'>page du tournoi</a>.</p>"
|
"sur la <a href='{url}'>page du tournoi</a>.</p>"
|
||||||
|
|
||||||
#: participation/models.py:1041
|
#: participation/models.py:1095
|
||||||
msgid "Tournament ended"
|
msgid "Tournament ended"
|
||||||
msgstr "Tournoi terminé"
|
msgstr "Tournoi terminé"
|
||||||
|
|
||||||
#: participation/models.py:1051 participation/models.py:1094
|
#: participation/models.py:1105 participation/models.py:1148
|
||||||
msgid "participations"
|
msgid "participations"
|
||||||
msgstr "participations"
|
msgstr "participations"
|
||||||
|
|
||||||
#: participation/models.py:1066 participation/models.py:1067
|
#: participation/models.py:1120 participation/models.py:1121
|
||||||
#: participation/models.py:1068
|
#: participation/models.py:1122
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Round {round}"
|
msgid "Round {round}"
|
||||||
msgstr "Tour {round}"
|
msgstr "Tour {round}"
|
||||||
|
|
||||||
#: participation/models.py:1082
|
#: participation/models.py:1136
|
||||||
msgid "room"
|
msgid "room"
|
||||||
msgstr "salle"
|
msgstr "salle"
|
||||||
|
|
||||||
#: participation/models.py:1084
|
#: participation/models.py:1138
|
||||||
msgid "Room 1"
|
msgid "Room 1"
|
||||||
msgstr "Salle 1"
|
msgstr "Salle 1"
|
||||||
|
|
||||||
#: participation/models.py:1085
|
#: participation/models.py:1139
|
||||||
msgid "Room 2"
|
msgid "Room 2"
|
||||||
msgstr "Salle 2"
|
msgstr "Salle 2"
|
||||||
|
|
||||||
#: participation/models.py:1088
|
#: participation/models.py:1142
|
||||||
msgid "For 5-teams pools only"
|
msgid "For 5-teams pools only"
|
||||||
msgstr "Pour les poules de 5 équipe uniquement"
|
msgstr "Pour les poules de 5 équipe uniquement"
|
||||||
|
|
||||||
#: participation/models.py:1100
|
#: participation/models.py:1154
|
||||||
msgid "juries"
|
msgid "juries"
|
||||||
msgstr "jurys"
|
msgstr "jurys"
|
||||||
|
|
||||||
#: participation/models.py:1109
|
#: participation/models.py:1163
|
||||||
msgid "president of the jury"
|
msgid "president of the jury"
|
||||||
msgstr "président⋅e du jury"
|
msgstr "président⋅e du jury"
|
||||||
|
|
||||||
#: participation/models.py:1116
|
#: participation/models.py:1170
|
||||||
msgid "BigBlueButton URL"
|
msgid "BigBlueButton URL"
|
||||||
msgstr "Lien BigBlueButton"
|
msgstr "Lien BigBlueButton"
|
||||||
|
|
||||||
#: participation/models.py:1117
|
#: participation/models.py:1171
|
||||||
msgid "The link of the BBB visio for this pool."
|
msgid "The link of the BBB visio for this pool."
|
||||||
msgstr "Le lien du salon BBB pour cette poule."
|
msgstr "Le lien du salon BBB pour cette poule."
|
||||||
|
|
||||||
#: participation/models.py:1122
|
#: participation/models.py:1176
|
||||||
msgid "results available"
|
msgid "results available"
|
||||||
msgstr "résultats disponibles"
|
msgstr "résultats disponibles"
|
||||||
|
|
||||||
#: participation/models.py:1123
|
#: participation/models.py:1177
|
||||||
msgid ""
|
msgid ""
|
||||||
"Check this case when results become accessible to teams. They stay "
|
"Check this case when results become accessible to teams. They stay "
|
||||||
"accessible to you. Only averages are given."
|
"accessible to you. Only averages are given."
|
||||||
|
@ -1522,33 +1587,61 @@ msgstr ""
|
||||||
"Ils restent toujours accessibles pour vous. Seules les moyennes sont "
|
"Ils restent toujours accessibles pour vous. Seules les moyennes sont "
|
||||||
"communiquées."
|
"communiquées."
|
||||||
|
|
||||||
#: participation/models.py:1155
|
#: participation/models.py:1209
|
||||||
msgid "The president of the jury must be part of the jury."
|
msgid "The president of the jury must be part of the jury."
|
||||||
msgstr "Læ président⋅e du jury doit faire partie du jury."
|
msgstr "Læ président⋅e du jury doit faire partie du jury."
|
||||||
|
|
||||||
#: participation/models.py:1544
|
#: participation/models.py:1235 participation/models.py:1309
|
||||||
|
#: participation/views.py:1481 participation/views.py:1730
|
||||||
|
msgid "Problem"
|
||||||
|
msgstr "Problème"
|
||||||
|
|
||||||
|
#: participation/models.py:1245 participation/views.py:1530
|
||||||
|
#: participation/views.py:1531
|
||||||
|
msgid "Juree"
|
||||||
|
msgstr "Juré⋅e"
|
||||||
|
|
||||||
|
#: participation/models.py:1268 participation/models.py:1588
|
||||||
|
#: participation/models.py:1610 participation/views.py:1600
|
||||||
|
msgid "Average"
|
||||||
|
msgstr "Moyenne"
|
||||||
|
|
||||||
|
#: participation/models.py:1274 participation/views.py:1619
|
||||||
|
msgid "Coefficient"
|
||||||
|
msgstr "Coefficien"
|
||||||
|
|
||||||
|
#: participation/models.py:1275 participation/views.py:1662
|
||||||
|
msgid "Subtotal"
|
||||||
|
msgstr "Sous-total"
|
||||||
|
|
||||||
|
#: participation/models.py:1535
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Input must be a valid integer between {min_note} and {max_note}."
|
||||||
|
msgstr "L'entrée doit être un entier valide entre {min_note} et {max_note}."
|
||||||
|
|
||||||
|
#: participation/models.py:1623
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The jury {jury} is not part of the jury for this pool."
|
msgid "The jury {jury} is not part of the jury for this pool."
|
||||||
msgstr "{jury} ne fait pas partie du jury pour cette poule."
|
msgstr "{jury} ne fait pas partie du jury pour cette poule."
|
||||||
|
|
||||||
#: participation/models.py:1557
|
#: participation/models.py:1636
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Pool {code} for tournament {tournament} with teams {teams}"
|
msgid "Pool {code} for tournament {tournament} with teams {teams}"
|
||||||
msgstr "Poule {code} du tournoi {tournament} avec les équipes {teams}"
|
msgstr "Poule {code} du tournoi {tournament} avec les équipes {teams}"
|
||||||
|
|
||||||
#: participation/models.py:1577
|
#: participation/models.py:1656
|
||||||
msgid "position"
|
msgid "position"
|
||||||
msgstr "position"
|
msgstr "position"
|
||||||
|
|
||||||
#: participation/models.py:1584
|
#: participation/models.py:1663
|
||||||
msgid "defended solution"
|
msgid "defended solution"
|
||||||
msgstr "solution défendue"
|
msgstr "solution défendue"
|
||||||
|
|
||||||
#: participation/models.py:1622
|
#: participation/models.py:1701
|
||||||
msgid "penalties"
|
msgid "penalties"
|
||||||
msgstr "pénalités"
|
msgstr "pénalités"
|
||||||
|
|
||||||
#: participation/models.py:1624
|
#: participation/models.py:1703
|
||||||
msgid ""
|
msgid ""
|
||||||
"Number of penalties for the defender. The defender will loose a 0.5 "
|
"Number of penalties for the defender. The defender will loose a 0.5 "
|
||||||
"coefficient per penalty."
|
"coefficient per penalty."
|
||||||
|
@ -1556,128 +1649,128 @@ msgstr ""
|
||||||
"Nombre de pénalités pour l'équipe défenseuse. Elle perd un coefficient 0.5 "
|
"Nombre de pénalités pour l'équipe défenseuse. Elle perd un coefficient 0.5 "
|
||||||
"sur sa présentation orale par pénalité."
|
"sur sa présentation orale par pénalité."
|
||||||
|
|
||||||
#: participation/models.py:1721 participation/models.py:1724
|
#: participation/models.py:1829 participation/models.py:1832
|
||||||
#: participation/models.py:1727 participation/models.py:1730
|
#: participation/models.py:1835 participation/models.py:1838
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Team {trigram} is not registered in the pool."
|
msgid "Team {trigram} is not registered in the pool."
|
||||||
msgstr "L'équipe {trigram} n'est pas inscrite dans la poule."
|
msgstr "L'équipe {trigram} n'est pas inscrite dans la poule."
|
||||||
|
|
||||||
#: participation/models.py:1735
|
#: participation/models.py:1843
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Passage of {defender} for problem {problem}"
|
msgid "Passage of {defender} for problem {problem}"
|
||||||
msgstr "Passage de {defender} pour le problème {problem}"
|
msgstr "Passage de {defender} pour le problème {problem}"
|
||||||
|
|
||||||
#: participation/models.py:1739 participation/models.py:1748
|
#: participation/models.py:1847 participation/models.py:1856
|
||||||
#: participation/models.py:1833 participation/models.py:1876
|
#: participation/models.py:1941 participation/models.py:1984
|
||||||
msgid "passage"
|
msgid "passage"
|
||||||
msgstr "passage"
|
msgstr "passage"
|
||||||
|
|
||||||
#: participation/models.py:1740
|
#: participation/models.py:1848
|
||||||
msgid "passages"
|
msgid "passages"
|
||||||
msgstr "passages"
|
msgstr "passages"
|
||||||
|
|
||||||
#: participation/models.py:1759
|
#: participation/models.py:1867
|
||||||
msgid "difference"
|
msgid "difference"
|
||||||
msgstr "différence"
|
msgstr "différence"
|
||||||
|
|
||||||
#: participation/models.py:1760
|
#: participation/models.py:1868
|
||||||
msgid "Score to add/remove on the final score"
|
msgid "Score to add/remove on the final score"
|
||||||
msgstr "Score à ajouter/retrancher au score final"
|
msgstr "Score à ajouter/retrancher au score final"
|
||||||
|
|
||||||
#: participation/models.py:1767
|
#: participation/models.py:1875
|
||||||
msgid "tweak"
|
msgid "tweak"
|
||||||
msgstr "harmonisation"
|
msgstr "harmonisation"
|
||||||
|
|
||||||
#: participation/models.py:1768
|
#: participation/models.py:1876
|
||||||
msgid "tweaks"
|
msgid "tweaks"
|
||||||
msgstr "harmonisations"
|
msgstr "harmonisations"
|
||||||
|
|
||||||
#: participation/models.py:1796
|
#: participation/models.py:1904
|
||||||
msgid "solution for the final tournament"
|
msgid "solution for the final tournament"
|
||||||
msgstr "solution pour la finale"
|
msgstr "solution pour la finale"
|
||||||
|
|
||||||
#: participation/models.py:1801 participation/models.py:1845
|
#: participation/models.py:1909 participation/models.py:1953
|
||||||
msgid "file"
|
msgid "file"
|
||||||
msgstr "fichier"
|
msgstr "fichier"
|
||||||
|
|
||||||
#: participation/models.py:1811
|
#: participation/models.py:1919
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Solution of team {team} for problem {problem}"
|
msgid "Solution of team {team} for problem {problem}"
|
||||||
msgstr "Solution de l'équipe {team} pour le problème {problem}"
|
msgstr "Solution de l'équipe {team} pour le problème {problem}"
|
||||||
|
|
||||||
#: participation/models.py:1813
|
#: participation/models.py:1921
|
||||||
msgid "for final"
|
msgid "for final"
|
||||||
msgstr "pour la finale"
|
msgstr "pour la finale"
|
||||||
|
|
||||||
#: participation/models.py:1816
|
#: participation/models.py:1924
|
||||||
msgid "solution"
|
msgid "solution"
|
||||||
msgstr "solution"
|
msgstr "solution"
|
||||||
|
|
||||||
#: participation/models.py:1817
|
#: participation/models.py:1925
|
||||||
msgid "solutions"
|
msgid "solutions"
|
||||||
msgstr "solutions"
|
msgstr "solutions"
|
||||||
|
|
||||||
#: participation/models.py:1851
|
#: participation/models.py:1959
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
|
msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Note de synthèse de l'équipe {team} en tant que {type} pour le problème "
|
"Note de synthèse de l'équipe {team} en tant que {type} pour le problème "
|
||||||
"{problem} de {defender}"
|
"{problem} de {defender}"
|
||||||
|
|
||||||
#: participation/models.py:1859
|
#: participation/models.py:1967
|
||||||
msgid "synthesis"
|
msgid "synthesis"
|
||||||
msgstr "note de synthèse"
|
msgstr "note de synthèse"
|
||||||
|
|
||||||
#: participation/models.py:1860
|
#: participation/models.py:1968
|
||||||
msgid "syntheses"
|
msgid "syntheses"
|
||||||
msgstr "notes de synthèse"
|
msgstr "notes de synthèse"
|
||||||
|
|
||||||
#: participation/models.py:1869
|
#: participation/models.py:1977
|
||||||
msgid "jury"
|
msgid "jury"
|
||||||
msgstr "jury"
|
msgstr "jury"
|
||||||
|
|
||||||
#: participation/models.py:1881
|
#: participation/models.py:1989
|
||||||
msgid "defender writing note"
|
msgid "defender writing note"
|
||||||
msgstr "note d'écrit défenseur⋅se"
|
msgstr "note d'écrit défenseur⋅se"
|
||||||
|
|
||||||
#: participation/models.py:1887
|
#: participation/models.py:1995
|
||||||
msgid "defender oral note"
|
msgid "defender oral note"
|
||||||
msgstr "note d'oral défenseur⋅se"
|
msgstr "note d'oral défenseur⋅se"
|
||||||
|
|
||||||
#: participation/models.py:1893
|
#: participation/models.py:2001
|
||||||
msgid "opponent writing note"
|
msgid "opponent writing note"
|
||||||
msgstr "note d'écrit opposant⋅e"
|
msgstr "note d'écrit opposant⋅e"
|
||||||
|
|
||||||
#: participation/models.py:1899
|
#: participation/models.py:2007
|
||||||
msgid "opponent oral note"
|
msgid "opponent oral note"
|
||||||
msgstr "note d'oral opposant⋅e"
|
msgstr "note d'oral opposant⋅e"
|
||||||
|
|
||||||
#: participation/models.py:1905
|
#: participation/models.py:2013
|
||||||
msgid "reviewer writing note"
|
msgid "reviewer writing note"
|
||||||
msgstr "note d'écrit rapporteur⋅rice"
|
msgstr "note d'écrit rapporteur⋅rice"
|
||||||
|
|
||||||
#: participation/models.py:1911
|
#: participation/models.py:2019
|
||||||
msgid "reviewer oral note"
|
msgid "reviewer oral note"
|
||||||
msgstr "note d'oral du rapporteur⋅rice"
|
msgstr "note d'oral du rapporteur⋅rice"
|
||||||
|
|
||||||
#: participation/models.py:1917
|
#: participation/models.py:2025
|
||||||
msgid "observer writing note"
|
msgid "observer writing note"
|
||||||
msgstr "note d'écrit de l'observateur⋅rice"
|
msgstr "note d'écrit de l'observateur⋅rice"
|
||||||
|
|
||||||
#: participation/models.py:1923
|
#: participation/models.py:2031
|
||||||
msgid "observer oral note"
|
msgid "observer oral note"
|
||||||
msgstr "note d'oral de l'observateur⋅rice"
|
msgstr "note d'oral de l'observateur⋅rice"
|
||||||
|
|
||||||
#: participation/models.py:1988
|
#: participation/models.py:2096
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Notes of {jury} for {passage}"
|
msgid "Notes of {jury} for {passage}"
|
||||||
msgstr "Notes de {jury} pour le {passage}"
|
msgstr "Notes de {jury} pour le {passage}"
|
||||||
|
|
||||||
#: participation/models.py:1991
|
#: participation/models.py:2099
|
||||||
msgid "note"
|
msgid "note"
|
||||||
msgstr "note"
|
msgstr "note"
|
||||||
|
|
||||||
#: participation/models.py:1992
|
#: participation/models.py:2100
|
||||||
msgid "notes"
|
msgid "notes"
|
||||||
msgstr "notes"
|
msgstr "notes"
|
||||||
|
|
||||||
|
@ -1718,8 +1811,8 @@ msgstr "Pas d'équipe définie"
|
||||||
#: participation/tables.py:147
|
#: participation/tables.py:147
|
||||||
#: participation/templates/participation/note_form.html:14
|
#: participation/templates/participation/note_form.html:14
|
||||||
#: participation/templates/participation/passage_detail.html:15
|
#: participation/templates/participation/passage_detail.html:15
|
||||||
#: participation/templates/participation/passage_detail.html:168
|
#: participation/templates/participation/passage_detail.html:176
|
||||||
#: participation/templates/participation/passage_detail.html:174
|
#: participation/templates/participation/passage_detail.html:182
|
||||||
#: participation/templates/participation/pool_detail.html:13
|
#: participation/templates/participation/pool_detail.html:13
|
||||||
#: participation/templates/participation/pool_detail.html:152
|
#: participation/templates/participation/pool_detail.html:152
|
||||||
#: participation/templates/participation/team_detail.html:185
|
#: participation/templates/participation/team_detail.html:185
|
||||||
|
@ -1807,7 +1900,7 @@ msgid "Upload solution"
|
||||||
msgstr "Envoyer une solution"
|
msgstr "Envoyer une solution"
|
||||||
|
|
||||||
#: participation/templates/participation/participation_detail.html:65
|
#: participation/templates/participation/participation_detail.html:65
|
||||||
#: participation/templates/participation/passage_detail.html:180
|
#: participation/templates/participation/passage_detail.html:188
|
||||||
#: participation/templates/participation/pool_detail.html:157
|
#: participation/templates/participation/pool_detail.html:157
|
||||||
#: participation/templates/participation/team_detail.html:245
|
#: participation/templates/participation/team_detail.html:245
|
||||||
#: participation/templates/participation/upload_motivation_letter.html:13
|
#: participation/templates/participation/upload_motivation_letter.html:13
|
||||||
|
@ -1870,12 +1963,12 @@ msgid "No synthesis was uploaded yet."
|
||||||
msgstr "Aucune note de synthèse n'a encore été envoyée."
|
msgstr "Aucune note de synthèse n'a encore été envoyée."
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:61
|
#: participation/templates/participation/passage_detail.html:61
|
||||||
#: participation/templates/participation/passage_detail.html:173
|
#: participation/templates/participation/passage_detail.html:181
|
||||||
msgid "Update notes"
|
msgid "Update notes"
|
||||||
msgstr "Modifier les notes"
|
msgstr "Modifier les notes"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:66
|
#: participation/templates/participation/passage_detail.html:66
|
||||||
#: participation/templates/participation/passage_detail.html:179
|
#: participation/templates/participation/passage_detail.html:187
|
||||||
msgid "Upload synthesis"
|
msgid "Upload synthesis"
|
||||||
msgstr "Envoyer une note de synthèse"
|
msgstr "Envoyer une note de synthèse"
|
||||||
|
|
||||||
|
@ -1887,51 +1980,51 @@ msgstr "Détails des notes"
|
||||||
msgid "Average points for the defender writing"
|
msgid "Average points for the defender writing"
|
||||||
msgstr "Moyenne de l'écrit de l'équipe défenseuse"
|
msgstr "Moyenne de l'écrit de l'équipe défenseuse"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:88
|
#: participation/templates/participation/passage_detail.html:90
|
||||||
msgid "Average points for the defender oral"
|
msgid "Average points for the defender oral"
|
||||||
msgstr "Moyenne de l'oral de l'équipe défenseuse"
|
msgstr "Moyenne de l'oral de l'équipe défenseuse"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:94
|
#: participation/templates/participation/passage_detail.html:98
|
||||||
msgid "Average points for the opponent writing"
|
msgid "Average points for the opponent writing"
|
||||||
msgstr "Moyenne de l'écrit de l'équipe opposante"
|
msgstr "Moyenne de l'écrit de l'équipe opposante"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:100
|
#: participation/templates/participation/passage_detail.html:104
|
||||||
msgid "Average points for the opponent oral"
|
msgid "Average points for the opponent oral"
|
||||||
msgstr "Moyenne de l'oral de l'équipe opposante"
|
msgstr "Moyenne de l'oral de l'équipe opposante"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:106
|
#: participation/templates/participation/passage_detail.html:110
|
||||||
msgid "Average points for the reviewer writing"
|
msgid "Average points for the reviewer writing"
|
||||||
msgstr "Moyenne de l'écrit de l'équipe rapportrice"
|
msgstr "Moyenne de l'écrit de l'équipe rapportrice"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:112
|
#: participation/templates/participation/passage_detail.html:116
|
||||||
msgid "Average points for the reviewer oral"
|
msgid "Average points for the reviewer oral"
|
||||||
msgstr "Moyenne de l'oral de l'équipe rapportrice"
|
msgstr "Moyenne de l'oral de l'équipe rapportrice"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:119
|
#: participation/templates/participation/passage_detail.html:123
|
||||||
msgid "Average points for the observer writing"
|
msgid "Average points for the observer writing"
|
||||||
msgstr "Moyenne de l'écrit de l'équipe observatrice"
|
msgstr "Moyenne de l'écrit de l'équipe observatrice"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:125
|
#: participation/templates/participation/passage_detail.html:129
|
||||||
msgid "Average points for the observer oral"
|
msgid "Average points for the observer oral"
|
||||||
msgstr "Moyenne de l'oral de l'équipe observatrice"
|
msgstr "Moyenne de l'oral de l'équipe observatrice"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:136
|
#: participation/templates/participation/passage_detail.html:140
|
||||||
msgid "Defender points"
|
msgid "Defender points"
|
||||||
msgstr "Points de l'équipe défenseuse"
|
msgstr "Points de l'équipe défenseuse"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:142
|
#: participation/templates/participation/passage_detail.html:148
|
||||||
msgid "Opponent points"
|
msgid "Opponent points"
|
||||||
msgstr "Points de l'équipe opposante"
|
msgstr "Points de l'équipe opposante"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:148
|
#: participation/templates/participation/passage_detail.html:156
|
||||||
msgid "reviewer points"
|
msgid "reviewer points"
|
||||||
msgstr "Points de l'équipe rapportrice"
|
msgstr "Points de l'équipe rapportrice"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:155
|
#: participation/templates/participation/passage_detail.html:163
|
||||||
msgid "observer points"
|
msgid "observer points"
|
||||||
msgstr "Points de l'équipe observatrice"
|
msgstr "Points de l'équipe observatrice"
|
||||||
|
|
||||||
#: participation/templates/participation/passage_detail.html:167
|
#: participation/templates/participation/passage_detail.html:175
|
||||||
#: participation/templates/participation/passage_form.html:11
|
#: participation/templates/participation/passage_form.html:11
|
||||||
msgid "Update passage"
|
msgid "Update passage"
|
||||||
msgstr "Modifier le passage"
|
msgstr "Modifier le passage"
|
||||||
|
@ -2355,10 +2448,6 @@ msgstr "Dépublier les notes pour le second tour"
|
||||||
msgid "Files available for download"
|
msgid "Files available for download"
|
||||||
msgstr "Fichiers disponibles au téléchargement"
|
msgstr "Fichiers disponibles au téléchargement"
|
||||||
|
|
||||||
#: participation/templates/participation/tournament_harmonize.html:14
|
|
||||||
msgid "Rank"
|
|
||||||
msgstr "Rang"
|
|
||||||
|
|
||||||
#: participation/templates/participation/tournament_harmonize.html:16
|
#: participation/templates/participation/tournament_harmonize.html:16
|
||||||
#: registration/models.py:655
|
#: registration/models.py:655
|
||||||
msgid "Note"
|
msgid "Note"
|
||||||
|
@ -2615,17 +2704,37 @@ msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e
|
||||||
msgid "Notes were successfully uploaded."
|
msgid "Notes were successfully uploaded."
|
||||||
msgstr "Les notes ont bien été envoyées."
|
msgstr "Les notes ont bien été envoyées."
|
||||||
|
|
||||||
#: participation/views.py:1845
|
#: participation/views.py:1496
|
||||||
|
msgid "Role"
|
||||||
|
msgstr "Rôle"
|
||||||
|
|
||||||
|
#: participation/views.py:1502
|
||||||
|
msgid "Defender"
|
||||||
|
msgstr "Défenseur⋅se"
|
||||||
|
|
||||||
|
#: participation/views.py:1508
|
||||||
|
msgid "Opponent"
|
||||||
|
msgstr "Opposant⋅e"
|
||||||
|
|
||||||
|
#: participation/views.py:1515
|
||||||
|
msgid "Reviewer"
|
||||||
|
msgstr "Rapporteur⋅rice"
|
||||||
|
|
||||||
|
#: participation/views.py:1522
|
||||||
|
msgid "Observer"
|
||||||
|
msgstr "Observateur⋅rice"
|
||||||
|
|
||||||
|
#: participation/views.py:1893
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Notation sheets of pool {pool} of {tournament}.zip"
|
msgid "Notation sheets of pool {pool} of {tournament}.zip"
|
||||||
msgstr "Feuilles de notations pour la poule {pool} du tournoi {tournament}.zip"
|
msgstr "Feuilles de notations pour la poule {pool} du tournoi {tournament}.zip"
|
||||||
|
|
||||||
#: participation/views.py:1850
|
#: participation/views.py:1898
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Notation sheets of {tournament}.zip"
|
msgid "Notation sheets of {tournament}.zip"
|
||||||
msgstr "Feuilles de notation de {tournament}.zip"
|
msgstr "Feuilles de notation de {tournament}.zip"
|
||||||
|
|
||||||
#: participation/views.py:2017
|
#: participation/views.py:2065
|
||||||
msgid "You can't upload a synthesis after the deadline."
|
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."
|
msgstr "Vous ne pouvez pas envoyer de note de synthèse après la date limite."
|
||||||
|
|
||||||
|
|
|
@ -302,25 +302,26 @@ class UploadNotesForm(forms.Form):
|
||||||
line = [s for s in line if s == s]
|
line = [s for s in line if s == s]
|
||||||
# Strip cases
|
# Strip cases
|
||||||
line = [str(s).strip() for s in line if str(s)]
|
line = [str(s).strip() for s in line if str(s)]
|
||||||
if line and line[0] == 'Problème':
|
if line and line[0] in ["Problème", "Problem"]:
|
||||||
pool_size = len(line) - 1
|
pool_size = len(line) - 1
|
||||||
line_length = 2 + 6 * pool_size
|
line_length = 2 + (8 if df.iat[1, 8] == "Observer" else 6) * pool_size
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if pool_size == 0 or len(line) < line_length:
|
if pool_size == 0 or len(line) < line_length:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
name = line[0]
|
name = line[0]
|
||||||
if name.lower() in ["rôle", "juré⋅e", "juré?e", "moyenne", "coefficient", "sous-total", "équipe", "equipe"]:
|
if name.lower() in ["rôle", "juré⋅e", "juré?e", "moyenne", "coefficient", "sous-total", "équipe", "equipe",
|
||||||
|
"role", "juree", "average", "coefficient", "subtotal", "team"]:
|
||||||
continue
|
continue
|
||||||
notes = line[2:line_length]
|
notes = line[2:line_length]
|
||||||
print(name, notes)
|
|
||||||
if not all(s.isnumeric() or s[0] == '-' and s[1:].isnumeric() for s in notes):
|
if not all(s.isnumeric() or s[0] == '-' and s[1:].isnumeric() for s in notes):
|
||||||
continue
|
continue
|
||||||
notes = list(map(lambda x: int(float(x)), notes))
|
notes = list(map(lambda x: int(float(x)), notes))
|
||||||
print(notes)
|
|
||||||
|
|
||||||
max_notes = pool_size * [20, 20, 10, 10, 10, 10]
|
max_notes = pool_size * [20 if settings.TFJM_APP == "TFJM" else 10,
|
||||||
|
20 if settings.TFJM_APP == "TFJM" else 10,
|
||||||
|
10, 10, 10, 10, 10, 10]
|
||||||
for n, max_n in zip(notes, max_notes):
|
for n, max_n in zip(notes, max_notes):
|
||||||
if n > max_n:
|
if n > max_n:
|
||||||
self.add_error('file',
|
self.add_error('file',
|
||||||
|
|
|
@ -458,7 +458,7 @@ class Tournament(models.Model):
|
||||||
return self.notes_sheet_id
|
return self.notes_sheet_id
|
||||||
|
|
||||||
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
||||||
spreadsheet = gc.create(f"Feuille de notes - {self.name}", folder_id=settings.NOTES_DRIVE_FOLDER_ID)
|
spreadsheet = gc.create(f"{_('Notation sheet')} - {self.name}", folder_id=settings.NOTES_DRIVE_FOLDER_ID)
|
||||||
spreadsheet.update_locale("fr_FR")
|
spreadsheet.update_locale("fr_FR")
|
||||||
spreadsheet.share(None, "anyone", "writer", with_link=True)
|
spreadsheet.share(None, "anyone", "writer", with_link=True)
|
||||||
self.notes_sheet_id = spreadsheet.id
|
self.notes_sheet_id = spreadsheet.id
|
||||||
|
@ -470,17 +470,21 @@ class Tournament(models.Model):
|
||||||
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
||||||
spreadsheet = gc.open_by_key(self.notes_sheet_id)
|
spreadsheet = gc.open_by_key(self.notes_sheet_id)
|
||||||
worksheets = spreadsheet.worksheets()
|
worksheets = spreadsheet.worksheets()
|
||||||
if "Classement final" not in [ws.title for ws in worksheets]:
|
if _("Final ranking") not in [ws.title for ws in worksheets]:
|
||||||
worksheet = spreadsheet.add_worksheet("Classement final", 100, 26)
|
worksheet = spreadsheet.add_worksheet(_("Final ranking"), 30, 10)
|
||||||
else:
|
else:
|
||||||
worksheet = spreadsheet.worksheet("Classement final")
|
worksheet = spreadsheet.worksheet(_("Final ranking"))
|
||||||
|
|
||||||
if worksheet.index != self.pools.count():
|
if worksheet.index != self.pools.count():
|
||||||
worksheet.update_index(self.pools.count())
|
worksheet.update_index(self.pools.count())
|
||||||
|
|
||||||
header = [["Équipe", "Score jour 1", "Harmonisation 1", "Score jour 2", "Harmonisation 2", "Total", "Rang"]]
|
header = [[_("Team"), _("Scores day 1"), _("Tweaks day 1"), _("Scores day 2"), _("Tweaks day 2")]
|
||||||
|
+ ([_("Total D1 + D2"), _("Scores day 3"), _("Tweaks day 3")]
|
||||||
|
if settings.NB_ROUNDS >= 3 else [])
|
||||||
|
+ [_("Total"), _("Rank")]]
|
||||||
lines = []
|
lines = []
|
||||||
participations = self.participations.filter(pools__round=1, pools__tournament=self).distinct().all()
|
participations = self.participations.filter(pools__round=1, pools__tournament=self).distinct().all()
|
||||||
|
total_col, rank_col = ("F", "G") if settings.NB_ROUNDS == 2 else ("I", "J")
|
||||||
for i, participation in enumerate(participations):
|
for i, participation in enumerate(participations):
|
||||||
line = [f"{participation.team.name} ({participation.team.trigram})"]
|
line = [f"{participation.team.name} ({participation.team.trigram})"]
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
|
@ -494,7 +498,7 @@ class Tournament(models.Model):
|
||||||
tweak1_qs = Tweak.objects.filter(pool=pool1, participation=participation)
|
tweak1_qs = Tweak.objects.filter(pool=pool1, participation=participation)
|
||||||
tweak1 = tweak1_qs.get() if tweak1_qs.exists() else None
|
tweak1 = tweak1_qs.get() if tweak1_qs.exists() else None
|
||||||
|
|
||||||
line.append(f"=SIERREUR('Poule {pool1.short_name}'!$D{pool1.juries.count() + 10 + position1}; 0)")
|
line.append(f"=SIERREUR('{_('Pool')} {pool1.short_name}'!$D{pool1.juries.count() + 10 + position1}; 0)")
|
||||||
line.append(tweak1.diff if tweak1 else 0)
|
line.append(tweak1.diff if tweak1 else 0)
|
||||||
|
|
||||||
if Passage.objects.filter(pool__tournament=self, pool__round=2, defender=participation).exists():
|
if Passage.objects.filter(pool__tournament=self, pool__round=2, defender=participation).exists():
|
||||||
|
@ -508,23 +512,49 @@ class Tournament(models.Model):
|
||||||
tweak2 = tweak2_qs.get() if tweak2_qs.exists() else None
|
tweak2 = tweak2_qs.get() if tweak2_qs.exists() else None
|
||||||
|
|
||||||
line.append(
|
line.append(
|
||||||
f"=SIERREUR('Poule {pool2.short_name}'!$D{pool2.juries.count() + 10 + position2}; 0)")
|
f"=SIERREUR('{_('Pool')} {pool2.short_name}'!$D{pool2.juries.count() + 10 + position2}; 0)")
|
||||||
line.append(tweak2.diff if tweak2 else 0)
|
line.append(tweak2.diff if tweak2 else 0)
|
||||||
|
|
||||||
|
if settings.NB_ROUNDS >= 3:
|
||||||
|
line.append(f"=$B{i + 2} + $C{i + 2} + $D{i + 2} + E{i + 2}")
|
||||||
|
|
||||||
|
if Passage.objects.filter(pool__tournament=self, pool__round=3, defender=participation).exists():
|
||||||
|
passage3 = Passage.objects.get(pool__tournament=self, pool__round=3, defender=participation)
|
||||||
|
pool3 = passage3.pool
|
||||||
|
if pool3.participations.count() != 5:
|
||||||
|
position3 = passage3.position
|
||||||
|
else:
|
||||||
|
position3 = (passage3.position - 1) * 2 + pool3.room
|
||||||
|
tweak3_qs = Tweak.objects.filter(pool=pool3, participation=participation)
|
||||||
|
tweak3 = tweak3_qs.get() if tweak3_qs.exists() else None
|
||||||
|
|
||||||
|
line.append(
|
||||||
|
f"=SIERREUR('{_('Pool')} {pool3.short_name}'!$D{pool3.juries.count() + 10 + position3}; 0)")
|
||||||
|
line.append(tweak3.diff if tweak3 else 0)
|
||||||
|
else:
|
||||||
|
line.append(0)
|
||||||
|
line.append(0)
|
||||||
else:
|
else:
|
||||||
# User has no second pool yet
|
# There is no second pool yet
|
||||||
line.append(0)
|
line.append(0)
|
||||||
line.append(0)
|
line.append(0)
|
||||||
|
|
||||||
line.append(f"=$B{i + 2} + $C{i + 2} + $D{i + 2} + E{i + 2}")
|
if settings.NB_ROUNDS >= 3:
|
||||||
line.append(f"=RANG($F{i + 2}; $F$2:$F${participations.count() + 1})")
|
line.append(f"=$B{i + 2} + $C{i + 2} + $D{i + 2} + E{i + 2}")
|
||||||
|
line.append(0)
|
||||||
|
line.append(0)
|
||||||
|
|
||||||
final_ranking = [["", "", "", ""], ["", "", "", ""], ["Équipe", "Score", "Rang", "Mention"],
|
line.append(f"=$B{i + 2} + $C{i + 2} + $D{i + 2} + E{i + 2}"
|
||||||
|
+ (f" + (PI() - 2) * $G{i + 2} + $H{i + 2}" if settings.NB_ROUNDS >= 3 else ""))
|
||||||
|
line.append(f"=RANG(${total_col}{i + 2}; ${total_col}$2:${total_col}${participations.count() + 1})")
|
||||||
|
|
||||||
|
final_ranking = [["", "", "", ""], ["", "", "", ""], [_("Team"), _("Score"), _("Rank"), _("Mention")],
|
||||||
[f"=SORT($A$2:$A${participations.count() + 1}; "
|
[f"=SORT($A$2:$A${participations.count() + 1}; "
|
||||||
f"$F$2:$F${participations.count() + 1}; FALSE)",
|
f"${total_col}$2:${total_col}${participations.count() + 1}; FALSE)",
|
||||||
f"=SORT($F$2:$F${participations.count() + 1}; "
|
f"=SORT(${total_col}$2:${total_col}${participations.count() + 1}; "
|
||||||
f"$F$2:$F${participations.count() + 1}; FALSE)",
|
f"${total_col}$2:${total_col}${participations.count() + 1}; FALSE)",
|
||||||
f"=SORT($G$2:$G${participations.count() + 1}; "
|
f"=SORT(${rank_col}$2:${rank_col}${participations.count() + 1}; "
|
||||||
f"$F$2:$F${participations.count() + 1}; FALSE)", ]]
|
f"${total_col}$2:${total_col}${participations.count() + 1}; FALSE)", ]]
|
||||||
final_ranking += [["", "", ""] for _i in range(participations.count() - 1)]
|
final_ranking += [["", "", ""] for _i in range(participations.count() - 1)]
|
||||||
|
|
||||||
notes = dict()
|
notes = dict()
|
||||||
|
@ -538,12 +568,13 @@ class Tournament(models.Model):
|
||||||
final_ranking[i + 3].append(participation.mention if not self.final else participation.mention_final)
|
final_ranking[i + 3].append(participation.mention if not self.final else participation.mention_final)
|
||||||
|
|
||||||
data = header + lines + final_ranking
|
data = header + lines + final_ranking
|
||||||
worksheet.update(data, f"A1:G{2 * participations.count() + 4}", raw=False)
|
worksheet.update(data, f"A1:{rank_col}{2 * participations.count() + 4}", raw=False)
|
||||||
|
|
||||||
format_requests = []
|
format_requests = []
|
||||||
|
|
||||||
# Set the width of the columns
|
# Set the width of the columns
|
||||||
column_widths = [("A", 300), ("B", 150), ("C", 150), ("D", 150), ("E", 150), ("F", 150), ("G", 150)]
|
column_widths = [("A", 300), ("B", 150), ("C", 150), ("D", 150), ("E", 150), ("F", 150), ("G", 150),
|
||||||
|
("H", 150), ("I", 150), ("J", 150)]
|
||||||
for column, width in column_widths:
|
for column, width in column_widths:
|
||||||
grid_range = a1_range_to_grid_range(column, worksheet.id)
|
grid_range = a1_range_to_grid_range(column, worksheet.id)
|
||||||
format_requests.append({
|
format_requests.append({
|
||||||
|
@ -563,7 +594,7 @@ class Tournament(models.Model):
|
||||||
|
|
||||||
# Set borders
|
# Set borders
|
||||||
border_ranges = [("A1:Z", "0000"),
|
border_ranges = [("A1:Z", "0000"),
|
||||||
(f"A1:G{participations.count() + 1}", "1111"),
|
(f"A1:{rank_col}{participations.count() + 1}", "1111"),
|
||||||
(f"A{participations.count() + 4}:D{2 * participations.count() + 4}", "1111")]
|
(f"A{participations.count() + 4}:D{2 * participations.count() + 4}", "1111")]
|
||||||
sides_names = ['top', 'bottom', 'left', 'right']
|
sides_names = ['top', 'bottom', 'left', 'right']
|
||||||
styles = ["NONE", "SOLID", "SOLID_MEDIUM", "SOLID_THICK", "DOUBLE"]
|
styles = ["NONE", "SOLID", "SOLID_MEDIUM", "SOLID_THICK", "DOUBLE"]
|
||||||
|
@ -585,7 +616,7 @@ class Tournament(models.Model):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Make titles bold
|
# Make titles bold
|
||||||
bold_ranges = [("A1:Z", False), ("A1:G1", True),
|
bold_ranges = [("A1:Z", False), (f"A1:{rank_col}1", True),
|
||||||
(f"A{participations.count() + 4}:D{participations.count() + 4}", True)]
|
(f"A{participations.count() + 4}:D{participations.count() + 4}", True)]
|
||||||
for bold_range, bold in bold_ranges:
|
for bold_range, bold in bold_ranges:
|
||||||
format_requests.append({
|
format_requests.append({
|
||||||
|
@ -598,14 +629,18 @@ class Tournament(models.Model):
|
||||||
|
|
||||||
# Set background color for headers and footers
|
# Set background color for headers and footers
|
||||||
bg_colors = [("A1:Z", (1, 1, 1)),
|
bg_colors = [("A1:Z", (1, 1, 1)),
|
||||||
("A1:G1", (0.8, 0.8, 0.8)),
|
(f"A1:{rank_col}1", (0.8, 0.8, 0.8)),
|
||||||
(f"A2:B{participations.count() + 1}", (0.9, 0.9, 0.9)),
|
(f"A2:B{participations.count() + 1}", (0.9, 0.9, 0.9)),
|
||||||
(f"C2:C{participations.count() + 1}", (1, 1, 1)),
|
(f"C2:C{participations.count() + 1}", (1, 1, 1)),
|
||||||
(f"D2:D{participations.count() + 1}", (0.9, 0.9, 0.9)),
|
(f"D2:D{participations.count() + 1}", (0.9, 0.9, 0.9)),
|
||||||
(f"E2:E{participations.count() + 1}", (1, 1, 1)),
|
(f"E2:E{participations.count() + 1}", (1, 1, 1)),
|
||||||
(f"F2:G{participations.count() + 1}", (0.9, 0.9, 0.9)),
|
|
||||||
(f"A{participations.count() + 4}:D{participations.count() + 4}", (0.8, 0.8, 0.8)),
|
(f"A{participations.count() + 4}:D{participations.count() + 4}", (0.8, 0.8, 0.8)),
|
||||||
(f"A{participations.count() + 5}:C{2 * participations.count() + 4}", (0.9, 0.9, 0.9)),]
|
(f"A{participations.count() + 5}:C{2 * participations.count() + 4}", (0.9, 0.9, 0.9)),]
|
||||||
|
if settings.NB_ROUNDS >= 3:
|
||||||
|
bg_colors.append((f"F2:G{participations.count() + 1}", (0.9, 0.9, 0.9)))
|
||||||
|
bg_colors.append((f"H2:I{participations.count() + 1}", (0.9, 0.9, 0.9)))
|
||||||
|
else:
|
||||||
|
bg_colors.append((f"F2:G{participations.count() + 1}", (0.9, 0.9, 0.9)))
|
||||||
for bg_range, bg_color in bg_colors:
|
for bg_range, bg_color in bg_colors:
|
||||||
r, g, b = bg_color
|
r, g, b = bg_color
|
||||||
format_requests.append({
|
format_requests.append({
|
||||||
|
@ -622,9 +657,15 @@ class Tournament(models.Model):
|
||||||
(f"D2:D{participations.count() + 1}", "0.0"),
|
(f"D2:D{participations.count() + 1}", "0.0"),
|
||||||
(f"E2:E{participations.count() + 1}", "0"),
|
(f"E2:E{participations.count() + 1}", "0"),
|
||||||
(f"F2:F{participations.count() + 1}", "0.0"),
|
(f"F2:F{participations.count() + 1}", "0.0"),
|
||||||
(f"G2:G{participations.count() + 1}", "0"),
|
|
||||||
(f"B{participations.count() + 5}:B{2 * participations.count() + 5}", "0.0"),
|
(f"B{participations.count() + 5}:B{2 * participations.count() + 5}", "0.0"),
|
||||||
(f"C{participations.count() + 5}:C{2 * participations.count() + 5}", "0"), ]
|
(f"C{participations.count() + 5}:C{2 * participations.count() + 5}", "0"), ]
|
||||||
|
if settings.NB_ROUNDS >= 3:
|
||||||
|
number_format_ranges += [(f"G2:G{participations.count() + 1}", "0.0"),
|
||||||
|
(f"H2:H{participations.count() + 1}", "0"),
|
||||||
|
(f"I2:I{participations.count() + 1}", "0.0"),
|
||||||
|
(f"J2:J{participations.count() + 1}", "0"), ]
|
||||||
|
else:
|
||||||
|
number_format_ranges.append((f"G2:G{participations.count() + 1}", "0"))
|
||||||
for number_format_range, pattern in number_format_ranges:
|
for number_format_range, pattern in number_format_ranges:
|
||||||
format_requests.append({
|
format_requests.append({
|
||||||
"repeatCell": {
|
"repeatCell": {
|
||||||
|
@ -643,16 +684,16 @@ class Tournament(models.Model):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Protect the header, the juries list, the footer and the ranking
|
# Protect the header, the juries list, the footer and the ranking
|
||||||
protected_ranges = ["A1:G1", f"A2:B{participations.count() + 1}",
|
protected_ranges = ["A1:J1", f"A2:B{participations.count() + 1}",
|
||||||
f"D2:D{participations.count() + 1}", f"F2:G{participations.count() + 1}",
|
f"D2:D{participations.count() + 1}", f"F2:G{participations.count() + 1}",
|
||||||
|
f"I2:J{participations.count() + 1}",
|
||||||
f"A{participations.count() + 4}:C{2 * participations.count() + 4}", ]
|
f"A{participations.count() + 4}:C{2 * participations.count() + 4}", ]
|
||||||
for protected_range in protected_ranges:
|
for protected_range in protected_ranges:
|
||||||
format_requests.append({
|
format_requests.append({
|
||||||
"addProtectedRange": {
|
"addProtectedRange": {
|
||||||
"protectedRange": {
|
"protectedRange": {
|
||||||
"range": a1_range_to_grid_range(protected_range, worksheet.id),
|
"range": a1_range_to_grid_range(protected_range, worksheet.id),
|
||||||
"description": "Structure du tableur à ne pas modifier "
|
"description": _("Don't update the table structure for a better automated integration."),
|
||||||
"pour une meilleure prise en charge automatisée",
|
|
||||||
"warningOnly": True,
|
"warningOnly": True,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -666,19 +707,21 @@ class Tournament(models.Model):
|
||||||
# Draw has not been done yet
|
# Draw has not been done yet
|
||||||
return
|
return
|
||||||
|
|
||||||
|
translation.activate(settings.PREFERRED_LANGUAGE_CODE)
|
||||||
|
|
||||||
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
||||||
spreadsheet = gc.open_by_key(self.notes_sheet_id)
|
spreadsheet = gc.open_by_key(self.notes_sheet_id)
|
||||||
worksheet = spreadsheet.worksheet("Classement final")
|
worksheet = spreadsheet.worksheet(_("Final ranking"))
|
||||||
|
|
||||||
score_cell = worksheet.find("Score")
|
score_cell = worksheet.find(_("Score"))
|
||||||
max_row = score_cell.row - 3
|
max_row = score_cell.row - 3
|
||||||
if max_row == 1:
|
if max_row == 1:
|
||||||
# There is no team
|
# There is no team
|
||||||
return
|
return
|
||||||
|
|
||||||
data = worksheet.get_values(f"A2:E{max_row}")
|
data = worksheet.get_values(f"A2:H{max_row}")
|
||||||
for line in data:
|
for line in data:
|
||||||
trigram = line[0][-4:-1]
|
trigram = line[0][-settings.TEAM_CODE_LENGTH - 1:-1]
|
||||||
participation = self.participations.get(team__trigram=trigram)
|
participation = self.participations.get(team__trigram=trigram)
|
||||||
pool1 = self.pools.get(round=1, participations=participation, room=1)
|
pool1 = self.pools.get(round=1, participations=participation, room=1)
|
||||||
tweak1_qs = Tweak.objects.filter(pool=pool1, participation=participation)
|
tweak1_qs = Tweak.objects.filter(pool=pool1, participation=participation)
|
||||||
|
@ -701,6 +744,17 @@ class Tournament(models.Model):
|
||||||
create_defaults={'diff': tweak2_nb, 'pool': pool2,
|
create_defaults={'diff': tweak2_nb, 'pool': pool2,
|
||||||
'participation': participation})
|
'participation': participation})
|
||||||
|
|
||||||
|
if self.pools.filter(round=3, participations=participation).exists():
|
||||||
|
pool3 = self.pools.get(round=3, participations=participation, room=1)
|
||||||
|
tweak3_qs = Tweak.objects.filter(pool=pool3, participation=participation)
|
||||||
|
tweak3_nb = int(line[7])
|
||||||
|
if not tweak3_nb:
|
||||||
|
tweak3_qs.delete()
|
||||||
|
else:
|
||||||
|
tweak3_qs.update_or_create(defaults={'diff': tweak3_nb},
|
||||||
|
create_defaults={'diff': tweak3_nb, 'pool': pool3,
|
||||||
|
'participation': participation})
|
||||||
|
|
||||||
nb_participations = self.participations.filter(valid=True).count()
|
nb_participations = self.participations.filter(valid=True).count()
|
||||||
mentions = worksheet.get_values(f"A{score_cell.row + 1}:D{score_cell.row + nb_participations}")
|
mentions = worksheet.get_values(f"A{score_cell.row + 1}:D{score_cell.row + nb_participations}")
|
||||||
notes = dict()
|
notes = dict()
|
||||||
|
@ -1164,26 +1218,31 @@ class Pool(models.Model):
|
||||||
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
||||||
spreadsheet = gc.open_by_key(self.tournament.notes_sheet_id)
|
spreadsheet = gc.open_by_key(self.tournament.notes_sheet_id)
|
||||||
worksheets = spreadsheet.worksheets()
|
worksheets = spreadsheet.worksheets()
|
||||||
if f"Poule {self.short_name}" not in [ws.title for ws in worksheets]:
|
if f"{_('Pool')} {self.short_name}" not in [ws.title for ws in worksheets]:
|
||||||
worksheet = spreadsheet.add_worksheet(f"Poule {self.short_name}", 100, 26)
|
worksheet = spreadsheet.add_worksheet(f"{_('Pool')} {self.short_name}", 100, 34)
|
||||||
else:
|
else:
|
||||||
worksheet = spreadsheet.worksheet(f"Poule {self.short_name}")
|
worksheet = spreadsheet.worksheet(f"{_('Pool')} {self.short_name}")
|
||||||
if any(ws.title == "Sheet1" for ws in worksheets):
|
if any(ws.title == "Sheet1" for ws in worksheets):
|
||||||
spreadsheet.del_worksheet(spreadsheet.worksheet("Sheet1"))
|
spreadsheet.del_worksheet(spreadsheet.worksheet("Sheet1"))
|
||||||
|
|
||||||
pool_size = self.participations.count()
|
pool_size = self.participations.count()
|
||||||
passage_width = 6
|
has_observer = settings.TFJM_APP == "ETEAM" and pool_size >= 4
|
||||||
|
passage_width = 6 + (2 if has_observer else 0)
|
||||||
passages = self.passages.all()
|
passages = self.passages.all()
|
||||||
|
|
||||||
header = [
|
header = [
|
||||||
sum(([f"Problème {passage.solution_number}"] + (passage_width - 1) * [""]
|
sum(([_("Problem #{problem}").format(problem=passage.solution_number)] + (passage_width - 1) * [""]
|
||||||
for passage in passages), start=["Problème", ""]),
|
for passage in passages), start=[_("Problem"), ""]),
|
||||||
sum(([f"Défenseur⋅se ({passage.defender.team.trigram})", "",
|
sum(([f"{_('Defender')} ({passage.defender.team.trigram})", "",
|
||||||
f"Opposant⋅e ({passage.opponent.team.trigram})", "",
|
f"{_('Opponent')} ({passage.opponent.team.trigram})", "",
|
||||||
f"Rapporteur⋅rice ({passage.reviewer.team.trigram})", ""]
|
f"{_('Reviewer')} ({passage.reviewer.team.trigram})", ""]
|
||||||
|
+ ([f"{('Observer')} ({passage.observer.team.trigram})", ""] if has_observer else [])
|
||||||
for passage in passages), start=["Rôle", ""]),
|
for passage in passages), start=["Rôle", ""]),
|
||||||
sum((["Écrit (/20)", "Oral (/20)", "Écrit (/10)", "Oral (/10)", "Écrit (/10)", "Oral (/10)"]
|
sum(([f"{_('Writing')} (/{20 if settings.TFJM_APP == "TFJM" else 10})",
|
||||||
for _passage in passages), start=["Juré⋅e", ""]),
|
f"{_('Oral')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})"
|
||||||
|
f"{_('Writing')} (/10)", f"{_('Oral')} (/10)", f"{_('Writing')} (/10)", f"{_('Oral')} (/10)"]
|
||||||
|
+ ([f"{_('Writing')} (/10)", f"{_('Oral')} (/10)"] if has_observer else [])
|
||||||
|
for _passage in passages), start=[_("Juree"), ""]),
|
||||||
]
|
]
|
||||||
|
|
||||||
notes = [[]] # Begin with empty hidden line to ensure pretty design
|
notes = [[]] # Begin with empty hidden line to ensure pretty design
|
||||||
|
@ -1193,6 +1252,8 @@ class Pool(models.Model):
|
||||||
note = passage.notes.filter(jury=jury).first()
|
note = passage.notes.filter(jury=jury).first()
|
||||||
line.extend([note.defender_writing, note.defender_oral, note.opponent_writing, note.opponent_oral,
|
line.extend([note.defender_writing, note.defender_oral, note.opponent_writing, note.opponent_oral,
|
||||||
note.reviewer_writing, note.reviewer_oral])
|
note.reviewer_writing, note.reviewer_oral])
|
||||||
|
if has_observer:
|
||||||
|
line.extend([note.observer_writing, note.observer_oral])
|
||||||
notes.append(line)
|
notes.append(line)
|
||||||
notes.append([]) # Add empty line to ensure pretty design
|
notes.append([]) # Add empty line to ensure pretty design
|
||||||
|
|
||||||
|
@ -1204,11 +1265,15 @@ class Pool(models.Model):
|
||||||
return ''
|
return ''
|
||||||
return getcol((number - 1) // 26) + chr(65 + (number - 1) % 26)
|
return getcol((number - 1) // 26) + chr(65 + (number - 1) % 26)
|
||||||
|
|
||||||
average = ["Moyenne", ""]
|
average = [_("Average"), ""]
|
||||||
coeffs = sum(([1, 1.6 - 0.4 * passage.defender_penalties, 0.9, 2, 0.9, 1] for passage in passages),
|
coeffs = sum(([passage.coeff_defender_writing, passage.coeff_defender_oral,
|
||||||
start=["Coefficient", ""])
|
passage.coeff_opponent_writing, passage.coeff_opponent_oral,
|
||||||
subtotal = ["Sous-total", ""]
|
passage.coeff_reviewer_writing, passage.coeff_reviewer_oral]
|
||||||
footer = [average, coeffs, subtotal, 26 * [""]]
|
+ ([passage.coeff_observer_writing, passage.coeff_observer_oral] if has_observer else [])
|
||||||
|
for passage in passages),
|
||||||
|
start=[_("Coefficient"), ""])
|
||||||
|
subtotal = [_("Subtotal"), ""]
|
||||||
|
footer = [average, coeffs, subtotal, 34 * [""]]
|
||||||
|
|
||||||
min_row = 5
|
min_row = 5
|
||||||
max_row = min_row + self.juries.count()
|
max_row = min_row + self.juries.count()
|
||||||
|
@ -1234,8 +1299,14 @@ class Pool(models.Model):
|
||||||
subtotal.extend([f"={rep_w_col}{max_row + 1} * {rep_w_col}{max_row + 2}"
|
subtotal.extend([f"={rep_w_col}{max_row + 1} * {rep_w_col}{max_row + 2}"
|
||||||
f" + {rep_o_col}{max_row + 1} * {rep_o_col}{max_row + 2}", ""])
|
f" + {rep_o_col}{max_row + 1} * {rep_o_col}{max_row + 2}", ""])
|
||||||
|
|
||||||
|
if has_observer:
|
||||||
|
obs_w_col = getcol(min_column + passage_width * i + 6)
|
||||||
|
obs_o_col = getcol(min_column + passage_width * i + 7)
|
||||||
|
subtotal.extend([f"={obs_w_col}{max_row + 1} * {obs_w_col}{max_row + 2}"
|
||||||
|
f" + {obs_o_col}{max_row + 1} * {obs_o_col}{max_row + 2}", ""])
|
||||||
|
|
||||||
ranking = [
|
ranking = [
|
||||||
["Équipe", "", "Problème", "Total", "Rang"],
|
[_("Team"), "", _("Problem"), _("Total"), _("Rank")],
|
||||||
]
|
]
|
||||||
all_passages = Passage.objects.filter(pool__tournament=self.tournament,
|
all_passages = Passage.objects.filter(pool__tournament=self.tournament,
|
||||||
pool__round=self.round,
|
pool__round=self.round,
|
||||||
|
@ -1258,14 +1329,22 @@ class Pool(models.Model):
|
||||||
reviewer_col = reviewer_passage.position - 1
|
reviewer_col = reviewer_passage.position - 1
|
||||||
|
|
||||||
formula = "="
|
formula = "="
|
||||||
formula += (f"'Poule {defender_passage.pool.short_name}'"
|
formula += (f"'{_('Pool')} {defender_passage.pool.short_name}'"
|
||||||
f"!{getcol(min_column + defender_col * passage_width)}{defender_row + 3}") # Defender
|
f"!{getcol(min_column + defender_col * passage_width)}{defender_row + 3}") # Defender
|
||||||
formula += (f" + 'Poule {opponent_passage.pool.short_name}'"
|
formula += (f" + '{_('Pool')} {opponent_passage.pool.short_name}'"
|
||||||
f"!{getcol(min_column + opponent_col * passage_width + 2)}{opponent_row + 3}") # Opponent
|
f"!{getcol(min_column + opponent_col * passage_width + 2)}{opponent_row + 3}") # Opponent
|
||||||
formula += (f" + 'Poule {reviewer_passage.pool.short_name}'"
|
formula += (f" + '{_('Pool')} {reviewer_passage.pool.short_name}'"
|
||||||
f"!{getcol(min_column + reviewer_col * passage_width + 4)}{reviewer_row + 3}") # reviewer
|
f"!{getcol(min_column + reviewer_col * passage_width + 4)}{reviewer_row + 3}") # reviewer
|
||||||
|
if has_observer:
|
||||||
|
observer_passage = Passage.objects.get(observer=participation,
|
||||||
|
pool__tournament=self.tournament, pool__round=self.round)
|
||||||
|
observer_row = 5 + observer_passage.pool.juries.count()
|
||||||
|
observer_col = observer_passage.position - 1
|
||||||
|
formula += (f" + '{_('Pool')} {observer_passage.pool.short_name}'"
|
||||||
|
f"!{getcol(min_column + observer_col * passage_width + 6)}{observer_row + 3}")
|
||||||
|
|
||||||
ranking.append([f"{participation.team.name} ({participation.team.trigram})", "",
|
ranking.append([f"{participation.team.name} ({participation.team.trigram})", "",
|
||||||
f"='Poule {defender_passage.pool.short_name}'"
|
f"='{_('Pool')} {defender_passage.pool.short_name}'"
|
||||||
f"!${getcol(3 + defender_col * passage_width)}$1",
|
f"!${getcol(3 + defender_col * passage_width)}$1",
|
||||||
formula,
|
formula,
|
||||||
f"=RANG(D{max_row + 6 + i}; "
|
f"=RANG(D{max_row + 6 + i}; "
|
||||||
|
@ -1273,8 +1352,8 @@ class Pool(models.Model):
|
||||||
|
|
||||||
all_values = header + notes + footer + ranking
|
all_values = header + notes + footer + ranking
|
||||||
|
|
||||||
worksheet.batch_clear([f"A1:Z{max_row + 5 + pool_size}"])
|
worksheet.batch_clear([f"A1:AH{max_row + 5 + pool_size}"])
|
||||||
worksheet.update("A1:Z", all_values, raw=False)
|
worksheet.update("A1:AH", all_values, raw=False)
|
||||||
|
|
||||||
format_requests = []
|
format_requests = []
|
||||||
|
|
||||||
|
@ -1300,13 +1379,13 @@ class Pool(models.Model):
|
||||||
for i in range(pool_size + 1):
|
for i in range(pool_size + 1):
|
||||||
merge_cells.append(f"A{max_row + 5 + i}:B{max_row + 5 + i}")
|
merge_cells.append(f"A{max_row + 5 + i}:B{max_row + 5 + i}")
|
||||||
|
|
||||||
format_requests.append({"unmergeCells": {"range": a1_range_to_grid_range("A1:Z", worksheet.id)}})
|
format_requests.append({"unmergeCells": {"range": a1_range_to_grid_range("A1:AH", worksheet.id)}})
|
||||||
for name in merge_cells:
|
for name in merge_cells:
|
||||||
grid_range = a1_range_to_grid_range(name, worksheet.id)
|
grid_range = a1_range_to_grid_range(name, worksheet.id)
|
||||||
format_requests.append({"mergeCells": {"mergeType": MergeType.merge_all, "range": grid_range}})
|
format_requests.append({"mergeCells": {"mergeType": MergeType.merge_all, "range": grid_range}})
|
||||||
|
|
||||||
# Make titles bold
|
# Make titles bold
|
||||||
bold_ranges = [("A1:Z", False), ("A1:Z3", True),
|
bold_ranges = [("A1:AH", False), ("A1:AH3", True),
|
||||||
(f"A{max_row + 1}:B{max_row + 3}", True), (f"A{max_row + 5}:E{max_row + 5}", True)]
|
(f"A{max_row + 1}:B{max_row + 3}", True), (f"A{max_row + 5}:E{max_row + 5}", True)]
|
||||||
for bold_range, bold in bold_ranges:
|
for bold_range, bold in bold_ranges:
|
||||||
format_requests.append({
|
format_requests.append({
|
||||||
|
@ -1318,7 +1397,7 @@ class Pool(models.Model):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Set background color for headers and footers
|
# Set background color for headers and footers
|
||||||
bg_colors = [("A1:Z", (1, 1, 1)),
|
bg_colors = [("A1:AH", (1, 1, 1)),
|
||||||
(f"A1:{getcol(2 + passages.count() * passage_width)}3", (0.8, 0.8, 0.8)),
|
(f"A1:{getcol(2 + passages.count() * passage_width)}3", (0.8, 0.8, 0.8)),
|
||||||
(f"A{min_row - 1}:B{max_row}", (0.95, 0.95, 0.95)),
|
(f"A{min_row - 1}:B{max_row}", (0.95, 0.95, 0.95)),
|
||||||
(f"A{max_row + 1}:B{max_row + 3}", (0.8, 0.8, 0.8)),
|
(f"A{max_row + 1}:B{max_row + 3}", (0.8, 0.8, 0.8)),
|
||||||
|
@ -1407,7 +1486,7 @@ class Pool(models.Model):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Define borders
|
# Define borders
|
||||||
border_ranges = [("A1:Z", "0000"),
|
border_ranges = [("A1:AH", "0000"),
|
||||||
(f"A1:{getcol(2 + passages.count() * passage_width)}{max_row + 3}", "1111"),
|
(f"A1:{getcol(2 + passages.count() * passage_width)}{max_row + 3}", "1111"),
|
||||||
(f"A{max_row + 5}:E{max_row + pool_size + 5}", "1111"),
|
(f"A{max_row + 5}:E{max_row + pool_size + 5}", "1111"),
|
||||||
(f"A1:B{max_row + 3}", "1113"),
|
(f"A1:B{max_row + 3}", "1113"),
|
||||||
|
@ -1443,7 +1522,7 @@ class Pool(models.Model):
|
||||||
for j in range(passage_width):
|
for j in range(passage_width):
|
||||||
column = getcol(min_column + i * passage_width + j)
|
column = getcol(min_column + i * passage_width + j)
|
||||||
min_note = 0
|
min_note = 0
|
||||||
max_note = 20 if j < 2 else 10
|
max_note = 20 if j < 2 and settings.TFJM_APP == "TFJM" else 10
|
||||||
format_requests.append({
|
format_requests.append({
|
||||||
"setDataValidation": {
|
"setDataValidation": {
|
||||||
"range": a1_range_to_grid_range(f"{column}{min_row - 1}:{column}{max_row}", worksheet.id),
|
"range": a1_range_to_grid_range(f"{column}{min_row - 1}:{column}{max_row}", worksheet.id),
|
||||||
|
@ -1453,8 +1532,8 @@ class Pool(models.Model):
|
||||||
"values": [{"userEnteredValue": f'=ET(REGEXMATCH(TO_TEXT({column}4); "^-?[0-9]+$"); '
|
"values": [{"userEnteredValue": f'=ET(REGEXMATCH(TO_TEXT({column}4); "^-?[0-9]+$"); '
|
||||||
f'{column}4>={min_note}; {column}4<={max_note})'},],
|
f'{column}4>={min_note}; {column}4<={max_note})'},],
|
||||||
},
|
},
|
||||||
"inputMessage": f"La saisie doit être un entier valide "
|
"inputMessage": (_("Input must be a valid integer between {min_note} and {max_note}.")
|
||||||
f"compris entre {min_note} et {max_note}.",
|
.format(min_note=min_note, max_note=max_note)),
|
||||||
"strict": True,
|
"strict": True,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1482,16 +1561,15 @@ class Pool(models.Model):
|
||||||
})
|
})
|
||||||
|
|
||||||
# Protect the header, the juries list, the footer and the ranking
|
# Protect the header, the juries list, the footer and the ranking
|
||||||
protected_ranges = ["A1:Z4",
|
protected_ranges = ["A1:AH4",
|
||||||
f"A{min_row}:B{max_row}",
|
f"A{min_row}:B{max_row}",
|
||||||
f"A{max_row}:Z{max_row + 5 + pool_size}"]
|
f"A{max_row}:AH{max_row + 5 + pool_size}"]
|
||||||
for protected_range in protected_ranges:
|
for protected_range in protected_ranges:
|
||||||
format_requests.append({
|
format_requests.append({
|
||||||
"addProtectedRange": {
|
"addProtectedRange": {
|
||||||
"protectedRange": {
|
"protectedRange": {
|
||||||
"range": a1_range_to_grid_range(protected_range, worksheet.id),
|
"range": a1_range_to_grid_range(protected_range, worksheet.id),
|
||||||
"description": "Structure du tableur à ne pas modifier "
|
"description": _("Don't update the table structure for a better automated integration."),
|
||||||
"pour une meilleure prise en charge automatisée",
|
|
||||||
"warningOnly": True,
|
"warningOnly": True,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1505,9 +1583,9 @@ class Pool(models.Model):
|
||||||
|
|
||||||
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
||||||
spreadsheet = gc.open_by_key(self.tournament.notes_sheet_id)
|
spreadsheet = gc.open_by_key(self.tournament.notes_sheet_id)
|
||||||
worksheet = spreadsheet.worksheet(f"Poule {self.short_name}")
|
worksheet = spreadsheet.worksheet(f"{_('Pool')} {self.short_name}")
|
||||||
|
|
||||||
average_cell = worksheet.find("Moyenne")
|
average_cell = worksheet.find(_("Average"))
|
||||||
min_row = 5
|
min_row = 5
|
||||||
max_row = average_cell.row - 1
|
max_row = average_cell.row - 1
|
||||||
juries_visible = worksheet.get(f"A{min_row}:B{max_row}")
|
juries_visible = worksheet.get(f"A{min_row}:B{max_row}")
|
||||||
|
@ -1527,16 +1605,17 @@ class Pool(models.Model):
|
||||||
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
|
||||||
self.tournament.create_spreadsheet()
|
self.tournament.create_spreadsheet()
|
||||||
spreadsheet = gc.open_by_key(self.tournament.notes_sheet_id)
|
spreadsheet = gc.open_by_key(self.tournament.notes_sheet_id)
|
||||||
worksheet = spreadsheet.worksheet(f"Poule {self.short_name}")
|
worksheet = spreadsheet.worksheet(f"{_('Pool')} {self.short_name}")
|
||||||
|
|
||||||
average_cell = worksheet.find("Moyenne")
|
average_cell = worksheet.find(_("Average"))
|
||||||
min_row = 5
|
min_row = 5
|
||||||
max_row = average_cell.row - 2
|
max_row = average_cell.row - 2
|
||||||
data = worksheet.get_values(f"A{min_row}:Z{max_row}")
|
data = worksheet.get_values(f"A{min_row}:AH{max_row}")
|
||||||
if not data or not data[0]:
|
if not data or not data[0]:
|
||||||
return
|
return
|
||||||
|
|
||||||
passage_width = 6
|
has_observer = settings.TFJM_APP == "ETEAM" and self.participations.count() >= 4
|
||||||
|
passage_width = 6 + (2 if has_observer else 0)
|
||||||
for line in data:
|
for line in data:
|
||||||
jury_name = line[0]
|
jury_name = line[0]
|
||||||
jury_id = line[1]
|
jury_id = line[1]
|
||||||
|
@ -1640,56 +1719,87 @@ class Passage(models.Model):
|
||||||
def average_defender_writing(self) -> float:
|
def average_defender_writing(self) -> float:
|
||||||
return self.avg(note.defender_writing for note in self.notes.all())
|
return self.avg(note.defender_writing for note in self.notes.all())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coeff_defender_writing(self) -> float:
|
||||||
|
return 1 if settings.TFJM_APP == "TFJM" else 2
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_defender_oral(self) -> float:
|
def average_defender_oral(self) -> float:
|
||||||
return self.avg(note.defender_oral for note in self.notes.all())
|
return self.avg(note.defender_oral for note in self.notes.all())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coeff_defender_oral(self) -> float:
|
||||||
|
coeff = 1.6 if settings.TFJM_APP == "TFJM" else 3
|
||||||
|
coeff *= 1 - 0.25 * self.defender_penalties
|
||||||
|
return coeff
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_defender(self) -> float:
|
def average_defender(self) -> float:
|
||||||
writing_coeff = 1 if settings.TFJM_APP == "TFJM" else 2
|
return (self.coeff_defender_writing * self.average_defender_writing
|
||||||
oral_coeff = 1.6 if settings.TFJM_APP == "TFJM" else 3
|
+ self.coeff_defender_oral * self.average_defender_oral)
|
||||||
oral_coeff *= 1 - 0.25 * self.defender_penalties
|
|
||||||
return writing_coeff * self.average_defender_writing + oral_coeff * self.average_defender_oral
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_opponent_writing(self) -> float:
|
def average_opponent_writing(self) -> float:
|
||||||
return self.avg(note.opponent_writing for note in self.notes.all())
|
return self.avg(note.opponent_writing for note in self.notes.all())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coeff_opponent_writing(self) -> float:
|
||||||
|
return 0.9 if not self.observer else 0.6
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_opponent_oral(self) -> float:
|
def average_opponent_oral(self) -> float:
|
||||||
return self.avg(note.opponent_oral for note in self.notes.all())
|
return self.avg(note.opponent_oral for note in self.notes.all())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coeff_opponent_oral(self) -> float:
|
||||||
|
return 2
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_opponent(self) -> float:
|
def average_opponent(self) -> float:
|
||||||
writing_coeff = 0.9 if not self.observer else 0.6
|
return (self.coeff_opponent_writing * self.average_opponent_writing
|
||||||
oral_coeff = 2
|
+ self.coeff_opponent_oral * self.average_opponent_oral)
|
||||||
return writing_coeff * self.average_opponent_writing + oral_coeff * self.average_opponent_oral
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_reviewer_writing(self) -> float:
|
def average_reviewer_writing(self) -> float:
|
||||||
return self.avg(note.reviewer_writing for note in self.notes.all())
|
return self.avg(note.reviewer_writing for note in self.notes.all())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coeff_reviewer_writing(self):
|
||||||
|
return 0.9 if not self.observer else 0.6
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_reviewer_oral(self) -> float:
|
def average_reviewer_oral(self) -> float:
|
||||||
return self.avg(note.reviewer_oral for note in self.notes.all())
|
return self.avg(note.reviewer_oral for note in self.notes.all())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coeff_reviewer_oral(self):
|
||||||
|
return 1 if settings.TFJM_APP == "TFJM" else 1.2
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_reviewer(self) -> float:
|
def average_reviewer(self) -> float:
|
||||||
writing_coeff = 0.9 if not self.observer else 0.6
|
return (self.coeff_reviewer_writing * self.average_reviewer_writing
|
||||||
oral_coeff = 1 if settings.TFJM_APP == "TFJM" else 1.2
|
+ self.coeff_reviewer_oral * self.average_reviewer_oral)
|
||||||
return writing_coeff * self.average_reviewer_writing + oral_coeff * self.average_reviewer_oral
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_observer_writing(self) -> float:
|
def average_observer_writing(self) -> float:
|
||||||
return self.avg(note.observer_writing for note in self.notes.all())
|
return self.avg(note.observer_writing for note in self.notes.all())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coeff_observer_writing(self):
|
||||||
|
return 0.6
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_observer_oral(self) -> float:
|
def average_observer_oral(self) -> float:
|
||||||
return self.avg(note.observer_oral for note in self.notes.all())
|
return self.avg(note.observer_oral for note in self.notes.all())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coeff_observer_oral(self):
|
||||||
|
return 0.5
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average_observer(self) -> float:
|
def average_observer(self) -> float:
|
||||||
return 0.6 * self.average_observer_writing + 0.5 * self.average_observer_oral
|
return (self.coeff_observer_writing * self.average_observer_writing
|
||||||
|
+ self.coeff_observer_oral * self.average_observer_oral)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def averages(self):
|
def averages(self):
|
||||||
|
@ -1707,9 +1817,7 @@ class Passage(models.Model):
|
||||||
avg = self.average_defender if participation == self.defender else self.average_opponent \
|
avg = self.average_defender if participation == self.defender else self.average_opponent \
|
||||||
if participation == self.opponent else self.average_reviewer if participation == self.reviewer \
|
if participation == self.opponent else self.average_reviewer if participation == self.reviewer \
|
||||||
else self.average_observer if participation == self.observer else 0
|
else self.average_observer if participation == self.observer else 0
|
||||||
|
avg *= self.pool.coeff
|
||||||
if self.pool.round == 3 and settings.TFJM_APP == "ETEAM":
|
|
||||||
avg *= math.pi - 2
|
|
||||||
|
|
||||||
return avg
|
return avg
|
||||||
|
|
||||||
|
@ -1957,7 +2065,7 @@ class Note(models.Model):
|
||||||
passage = Passage.objects.prefetch_related('pool__tournament', 'pool__participations').get(pk=self.passage.pk)
|
passage = Passage.objects.prefetch_related('pool__tournament', 'pool__participations').get(pk=self.passage.pk)
|
||||||
spreadsheet_id = passage.pool.tournament.notes_sheet_id
|
spreadsheet_id = passage.pool.tournament.notes_sheet_id
|
||||||
spreadsheet = gc.open_by_key(spreadsheet_id)
|
spreadsheet = gc.open_by_key(spreadsheet_id)
|
||||||
worksheet = spreadsheet.worksheet(f"Poule {passage.pool.short_name}")
|
worksheet = spreadsheet.worksheet(f"{_('Pool')} {passage.pool.short_name}")
|
||||||
jury_id_cell = worksheet.find(str(self.jury_id), in_column=2)
|
jury_id_cell = worksheet.find(str(self.jury_id), in_column=2)
|
||||||
if not jury_id_cell:
|
if not jury_id_cell:
|
||||||
raise ValueError("The jury ID cell was not found in the spreadsheet.")
|
raise ValueError("The jury ID cell was not found in the spreadsheet.")
|
||||||
|
|
|
@ -82,13 +82,17 @@
|
||||||
{% trans "Average points for the defender writing" %}
|
{% trans "Average points for the defender writing" %}
|
||||||
({{ passage.defender.team.trigram }}) :
|
({{ passage.defender.team.trigram }}) :
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="col-sm-4">{{ passage.average_defender_writing|floatformat }}/20</dd>
|
<dd class="col-sm-4">
|
||||||
|
{{ passage.average_defender_writing|floatformat }}/{% if TFJM_APP == "TFJM" %}20{% else %}10{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
<dt class="col-sm-8">
|
<dt class="col-sm-8">
|
||||||
{% trans "Average points for the defender oral" %}
|
{% trans "Average points for the defender oral" %}
|
||||||
({{ passage.defender.team.trigram }}) :
|
({{ passage.defender.team.trigram }}) :
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="col-sm-4">{{ passage.average_defender_oral|floatformat }}/20</dd>
|
<dd class="col-sm-4">
|
||||||
|
{{ passage.average_defender_oral|floatformat }}/{% if TFJM_APP == "TFJM" %}20{% else %}10{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
<dt class="col-sm-8">
|
<dt class="col-sm-8">
|
||||||
{% trans "Average points for the opponent writing" %}
|
{% trans "Average points for the opponent writing" %}
|
||||||
|
@ -113,14 +117,14 @@
|
||||||
({{ passage.reviewer.team.trigram }}) :
|
({{ passage.reviewer.team.trigram }}) :
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="col-sm-4">{{ passage.average_reviewer_oral|floatformat }}/10</dd>
|
<dd class="col-sm-4">{{ passage.average_reviewer_oral|floatformat }}/10</dd>
|
||||||
|
|
||||||
{% if passage.observer %}
|
{% if passage.observer %}
|
||||||
<dt class="col-sm-8">
|
<dt class="col-sm-8">
|
||||||
{% trans "Average points for the observer writing" %}
|
{% trans "Average points for the observer writing" %}
|
||||||
({{ passage.observer.team.trigram }}) :
|
({{ passage.observer.team.trigram }}) :
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="col-sm-4">{{ passage.average_observer_writing|floatformat }}/10</dd>
|
<dd class="col-sm-4">{{ passage.average_observer_writing|floatformat }}/10</dd>
|
||||||
|
|
||||||
<dt class="col-sm-8">
|
<dt class="col-sm-8">
|
||||||
{% trans "Average points for the observer oral" %}
|
{% trans "Average points for the observer oral" %}
|
||||||
({{ passage.observer.team.trigram }}) :
|
({{ passage.observer.team.trigram }}) :
|
||||||
|
@ -136,27 +140,31 @@
|
||||||
{% trans "Defender points" %}
|
{% trans "Defender points" %}
|
||||||
({{ passage.defender.team.trigram }}) :
|
({{ passage.defender.team.trigram }}) :
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="col-sm-4">{{ passage.average_defender|floatformat }}/52</dd>
|
<dd class="col-sm-4">
|
||||||
|
{{ passage.average_defender|floatformat }}/{% if TFJM_APP == "TFJM" %}52{% else %}50{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
<dt class="col-sm-8">
|
<dt class="col-sm-8">
|
||||||
{% trans "Opponent points" %}
|
{% trans "Opponent points" %}
|
||||||
({{ passage.opponent.team.trigram }}) :
|
({{ passage.opponent.team.trigram }}) :
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="col-sm-4">{{ passage.average_opponent|floatformat }}/29</dd>
|
<dd class="col-sm-4">
|
||||||
|
{{ passage.average_opponent|floatformat }}/{% if TFJM_APP == "TFJM" %}29{% else %}{% if passage.observer %}26{% else %}29{% endif %}{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
<dt class="col-sm-8">
|
<dt class="col-sm-8">
|
||||||
{% trans "reviewer points" %}
|
{% trans "reviewer points" %}
|
||||||
({{ passage.reviewer.team.trigram }}) :
|
({{ passage.reviewer.team.trigram }}) :
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="col-sm-4">{{ passage.average_reviewer|floatformat }}/19</dd>
|
<dd class="col-sm-4">{{ passage.average_reviewer|floatformat }}/{% if TFJM_APP == "TFJM" %}19{% else %}{% if passage.observer %}18{% else %}21{% endif %}{% endif %}</dd>
|
||||||
|
|
||||||
{% if passage.observer %}
|
{% if passage.observer %}
|
||||||
<dt class="col-sm-8">
|
<dt class="col-sm-8">
|
||||||
{% trans "observer points" %}
|
{% trans "observer points" %}
|
||||||
({{ passage.observer.team.trigram }}) :
|
({{ passage.observer.team.trigram }}) :
|
||||||
</dt>
|
</dt>
|
||||||
|
|
||||||
<dd class="col-sm-4">{{ passage.average_observer|floatformat }}/10</dd>
|
<dd class="col-sm-4">{{ passage.average_observer|floatformat }}/6</dd>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,7 +24,7 @@ from django.http import FileResponse, Http404, HttpResponse
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils import timezone
|
from django.utils import timezone, translation
|
||||||
from django.utils.crypto import get_random_string
|
from django.utils.crypto import get_random_string
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.utils.timezone import localtime
|
from django.utils.timezone import localtime
|
||||||
|
@ -1254,7 +1254,7 @@ class PoolUploadNotesView(VolunteerMixin, FormView, DetailView):
|
||||||
return self.form_invalid(form)
|
return self.form_invalid(form)
|
||||||
|
|
||||||
for vr, notes in parsed_notes.items():
|
for vr, notes in parsed_notes.items():
|
||||||
notes_count = 6
|
notes_count = 6 + (2 if pool.participations.count() >= 4 and settings.TFJM_APP == "ETEAM" else 0)
|
||||||
for i, passage in enumerate(pool.passages.all()):
|
for i, passage in enumerate(pool.passages.all()):
|
||||||
note = Note.objects.get_or_create(jury=vr, passage=passage)[0]
|
note = Note.objects.get_or_create(jury=vr, passage=passage)[0]
|
||||||
passage_notes = notes[notes_count * i:notes_count * (i + 1)]
|
passage_notes = notes[notes_count * i:notes_count * (i + 1)]
|
||||||
|
@ -1289,8 +1289,11 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
return self.handle_no_permission()
|
return self.handle_no_permission()
|
||||||
|
|
||||||
def render_to_response(self, context, **response_kwargs): # noqa: C901
|
def render_to_response(self, context, **response_kwargs): # noqa: C901
|
||||||
|
translation.activate(settings.PREFERRED_LANGUAGE_CODE)
|
||||||
|
|
||||||
pool_size = self.object.passages.count()
|
pool_size = self.object.passages.count()
|
||||||
passage_width = 6
|
has_observer = self.object.participations.count() >= 4 and settings.TFJM_APP == "ETEAM"
|
||||||
|
passage_width = 6 + (2 if has_observer else 0)
|
||||||
line_length = pool_size * passage_width
|
line_length = pool_size * passage_width
|
||||||
|
|
||||||
def getcol(number: int) -> str:
|
def getcol(number: int) -> str:
|
||||||
|
@ -1475,79 +1478,96 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
header_pb = TableRow()
|
header_pb = TableRow()
|
||||||
table.addElement(header_pb)
|
table.addElement(header_pb)
|
||||||
problems_tc = TableCell(valuetype="string", stylename=title_style_topleft)
|
problems_tc = TableCell(valuetype="string", stylename=title_style_topleft)
|
||||||
problems_tc.addElement(P(text="Problème"))
|
problems_tc.addElement(P(text=_("Problem")))
|
||||||
problems_tc.setAttribute('numbercolumnsspanned', "2")
|
problems_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
header_pb.addElement(problems_tc)
|
header_pb.addElement(problems_tc)
|
||||||
header_pb.addElement(CoveredTableCell())
|
header_pb.addElement(CoveredTableCell())
|
||||||
for passage in self.object.passages.all():
|
for passage in self.object.passages.all():
|
||||||
tc = TableCell(valuetype="string", stylename=title_style_topleftright)
|
tc = TableCell(valuetype="string", stylename=title_style_topleftright)
|
||||||
tc.addElement(P(text=f"Problème {passage.solution_number}"))
|
tc.addElement(P(text=_("Problem #{problem}").format(problem=passage.solution_number)))
|
||||||
tc.setAttribute('numbercolumnsspanned', "6")
|
tc.setAttribute('numbercolumnsspanned', str(passage_width))
|
||||||
header_pb.addElement(tc)
|
header_pb.addElement(tc)
|
||||||
header_pb.addElement(CoveredTableCell(numbercolumnsrepeated=5))
|
header_pb.addElement(CoveredTableCell(numbercolumnsrepeated=passage_width - 1))
|
||||||
|
|
||||||
# Add roles on the second line of the table
|
# Add roles on the second line of the table
|
||||||
header_role = TableRow()
|
header_role = TableRow()
|
||||||
table.addElement(header_role)
|
table.addElement(header_role)
|
||||||
role_tc = TableCell(valuetype="string", stylename=title_style_left)
|
role_tc = TableCell(valuetype="string", stylename=title_style_left)
|
||||||
role_tc.addElement(P(text="Rôle"))
|
role_tc.addElement(P(text=_("Role")))
|
||||||
role_tc.setAttribute('numbercolumnsspanned', "2")
|
role_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
header_role.addElement(role_tc)
|
header_role.addElement(role_tc)
|
||||||
header_role.addElement(CoveredTableCell())
|
header_role.addElement(CoveredTableCell())
|
||||||
for i in range(pool_size):
|
for i in range(pool_size):
|
||||||
defender_tc = TableCell(valuetype="string", stylename=title_style_left)
|
defender_tc = TableCell(valuetype="string", stylename=title_style_left)
|
||||||
defender_tc.addElement(P(text="Défenseur⋅se"))
|
defender_tc.addElement(P(text=_("Defender")))
|
||||||
defender_tc.setAttribute('numbercolumnsspanned', "2")
|
defender_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
header_role.addElement(defender_tc)
|
header_role.addElement(defender_tc)
|
||||||
header_role.addElement(CoveredTableCell())
|
header_role.addElement(CoveredTableCell())
|
||||||
|
|
||||||
opponent_tc = TableCell(valuetype="string", stylename=title_style)
|
opponent_tc = TableCell(valuetype="string", stylename=title_style)
|
||||||
opponent_tc.addElement(P(text="Opposant⋅e"))
|
opponent_tc.addElement(P(text=_("Opponent")))
|
||||||
opponent_tc.setAttribute('numbercolumnsspanned', "2")
|
opponent_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
header_role.addElement(opponent_tc)
|
header_role.addElement(opponent_tc)
|
||||||
header_role.addElement(CoveredTableCell())
|
header_role.addElement(CoveredTableCell())
|
||||||
|
|
||||||
reviewer_tc = TableCell(valuetype="string",
|
reviewer_tc = TableCell(valuetype="string",
|
||||||
stylename=title_style_right)
|
stylename=title_style if has_observer else title_style_right)
|
||||||
reviewer_tc.addElement(P(text="Rapporteur⋅rice"))
|
reviewer_tc.addElement(P(text=_("Reviewer")))
|
||||||
reviewer_tc.setAttribute('numbercolumnsspanned', "2")
|
reviewer_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
header_role.addElement(reviewer_tc)
|
header_role.addElement(reviewer_tc)
|
||||||
header_role.addElement(CoveredTableCell())
|
header_role.addElement(CoveredTableCell())
|
||||||
|
|
||||||
|
if has_observer:
|
||||||
|
observer_tc = TableCell(valuetype="string", stylename=title_style_right)
|
||||||
|
observer_tc.addElement(P(text=_("Observer")))
|
||||||
|
observer_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
|
header_role.addElement(observer_tc)
|
||||||
|
header_role.addElement(CoveredTableCell())
|
||||||
|
|
||||||
# Add maximum notes on the third line
|
# Add maximum notes on the third line
|
||||||
header_notes = TableRow()
|
header_notes = TableRow()
|
||||||
table.addElement(header_notes)
|
table.addElement(header_notes)
|
||||||
jury_tc = TableCell(valuetype="string", value="Juré⋅e", stylename=title_style_botleft)
|
jury_tc = TableCell(valuetype="string", value=_("Juree"), stylename=title_style_botleft)
|
||||||
jury_tc.addElement(P(text="Juré⋅e"))
|
jury_tc.addElement(P(text=_("Juree")))
|
||||||
jury_tc.setAttribute('numbercolumnsspanned', "2")
|
jury_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
header_notes.addElement(jury_tc)
|
header_notes.addElement(jury_tc)
|
||||||
header_notes.addElement(CoveredTableCell())
|
header_notes.addElement(CoveredTableCell())
|
||||||
|
|
||||||
for i in range(pool_size):
|
for i in range(pool_size):
|
||||||
defender_w_tc = TableCell(valuetype="string", stylename=title_style_botleft)
|
defender_w_tc = TableCell(valuetype="string", stylename=title_style_botleft)
|
||||||
defender_w_tc.addElement(P(text="Écrit (/20)"))
|
defender_w_tc.addElement(P(text=f"{_('Writing')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})"))
|
||||||
header_notes.addElement(defender_w_tc)
|
header_notes.addElement(defender_w_tc)
|
||||||
|
|
||||||
defender_o_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
defender_o_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
||||||
defender_o_tc.addElement(P(text="Oral (/20)"))
|
defender_o_tc.addElement(P(text=f"{_('Oral')} (/{20 if settings.TFJM_APP == 'TFJM' else 10})"))
|
||||||
header_notes.addElement(defender_o_tc)
|
header_notes.addElement(defender_o_tc)
|
||||||
|
|
||||||
opponent_w_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
opponent_w_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
||||||
opponent_w_tc.addElement(P(text="Écrit (/10)"))
|
opponent_w_tc.addElement(P(text=f"{_('Writing')} (/10)"))
|
||||||
header_notes.addElement(opponent_w_tc)
|
header_notes.addElement(opponent_w_tc)
|
||||||
|
|
||||||
opponent_o_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
opponent_o_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
||||||
opponent_o_tc.addElement(P(text="Oral (/10)"))
|
opponent_o_tc.addElement(P(text=f"{_('Oral')} (/10)"))
|
||||||
header_notes.addElement(opponent_o_tc)
|
header_notes.addElement(opponent_o_tc)
|
||||||
|
|
||||||
reviewer_w_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
reviewer_w_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
||||||
reviewer_w_tc.addElement(P(text="Écrit (/10)"))
|
reviewer_w_tc.addElement(P(text=f"{_('Writing')} (/10)"))
|
||||||
header_notes.addElement(reviewer_w_tc)
|
header_notes.addElement(reviewer_w_tc)
|
||||||
|
|
||||||
reviewer_o_tc = TableCell(valuetype="string", stylename=title_style_botright)
|
reviewer_o_tc = TableCell(valuetype="string",
|
||||||
reviewer_o_tc.addElement(P(text="Oral (/10)"))
|
stylename=title_style_bot if has_observer else title_style_botright)
|
||||||
|
reviewer_o_tc.addElement(P(text=f"{_('Oral')} (/10)"))
|
||||||
header_notes.addElement(reviewer_o_tc)
|
header_notes.addElement(reviewer_o_tc)
|
||||||
|
|
||||||
|
if has_observer:
|
||||||
|
observer_w_tc = TableCell(valuetype="string", stylename=title_style_bot)
|
||||||
|
observer_w_tc.addElement(P(text=f"{_('Writing')} (/10)"))
|
||||||
|
header_notes.addElement(observer_w_tc)
|
||||||
|
|
||||||
|
observer_o_tc = TableCell(valuetype="string", stylename=title_style_botright)
|
||||||
|
observer_o_tc.addElement(P(text=f"{_('Oral')} (/10)"))
|
||||||
|
header_notes.addElement(observer_o_tc)
|
||||||
|
|
||||||
# Add a notation line for each jury
|
# Add a notation line for each jury
|
||||||
for jury in self.object.juries.all():
|
for jury in self.object.juries.all():
|
||||||
jury_row = TableRow()
|
jury_row = TableRow()
|
||||||
|
@ -1577,7 +1597,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
average_row = TableRow()
|
average_row = TableRow()
|
||||||
table.addElement(average_row)
|
table.addElement(average_row)
|
||||||
average_tc = TableCell(valuetype="string", stylename=title_style_topleftright)
|
average_tc = TableCell(valuetype="string", stylename=title_style_topleftright)
|
||||||
average_tc.addElement(P(text="Moyenne"))
|
average_tc.addElement(P(text=_("Average")))
|
||||||
average_tc.setAttribute('numbercolumnsspanned', "2")
|
average_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
average_row.addElement(average_tc)
|
average_row.addElement(average_tc)
|
||||||
average_row.addElement(CoveredTableCell())
|
average_row.addElement(CoveredTableCell())
|
||||||
|
@ -1596,40 +1616,50 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
coeff_row = TableRow()
|
coeff_row = TableRow()
|
||||||
table.addElement(coeff_row)
|
table.addElement(coeff_row)
|
||||||
coeff_tc = TableCell(valuetype="string", stylename=title_style_leftright)
|
coeff_tc = TableCell(valuetype="string", stylename=title_style_leftright)
|
||||||
coeff_tc.addElement(P(text="Coefficient"))
|
coeff_tc.addElement(P(text=_("Coefficient")))
|
||||||
coeff_tc.setAttribute('numbercolumnsspanned', "2")
|
coeff_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
coeff_row.addElement(coeff_tc)
|
coeff_row.addElement(coeff_tc)
|
||||||
coeff_row.addElement(CoveredTableCell())
|
coeff_row.addElement(CoveredTableCell())
|
||||||
for passage in self.object.passages.all():
|
for passage in self.object.passages.all():
|
||||||
defender_w_tc = TableCell(valuetype="float", value=1, stylename=style_left)
|
defender_w_tc = TableCell(valuetype="float", value=passage.coeff_defender_writing, stylename=style_left)
|
||||||
defender_w_tc.addElement(P(text="1"))
|
defender_w_tc.addElement(P(text=str(passage.coeff_defender_writing)))
|
||||||
coeff_row.addElement(defender_w_tc)
|
coeff_row.addElement(defender_w_tc)
|
||||||
|
|
||||||
defender_o_tc = TableCell(valuetype="float", value=1.6 - 0.4 * passage.defender_penalties, stylename=style)
|
defender_o_tc = TableCell(valuetype="float", value=passage.coeff_defender_oral, stylename=style)
|
||||||
defender_o_tc.addElement(P(text=str(2 - 0.4 * passage.defender_penalties)))
|
defender_o_tc.addElement(P(text=str(passage.coeff_defender_oral)))
|
||||||
coeff_row.addElement(defender_o_tc)
|
coeff_row.addElement(defender_o_tc)
|
||||||
|
|
||||||
opponent_w_tc = TableCell(valuetype="float", value=0.9, stylename=style)
|
opponent_w_tc = TableCell(valuetype="float", value=passage.coeff_opponent_writing, stylename=style)
|
||||||
opponent_w_tc.addElement(P(text="1"))
|
opponent_w_tc.addElement(P(text=str(passage.coeff_opponent_writing)))
|
||||||
coeff_row.addElement(opponent_w_tc)
|
coeff_row.addElement(opponent_w_tc)
|
||||||
|
|
||||||
opponent_o_tc = TableCell(valuetype="float", value=2, stylename=style)
|
opponent_o_tc = TableCell(valuetype="float", value=passage.coeff_opponent_oral, stylename=style)
|
||||||
opponent_o_tc.addElement(P(text="2"))
|
opponent_o_tc.addElement(P(text=str(passage.coeff_opponent_oral)))
|
||||||
coeff_row.addElement(opponent_o_tc)
|
coeff_row.addElement(opponent_o_tc)
|
||||||
|
|
||||||
reviewer_w_tc = TableCell(valuetype="float", value=0.9, stylename=style)
|
reviewer_w_tc = TableCell(valuetype="float", value=passage.coeff_reviewer_writing, stylename=style)
|
||||||
reviewer_w_tc.addElement(P(text="1"))
|
reviewer_w_tc.addElement(P(text=str(passage.coeff_reviewer_writing)))
|
||||||
coeff_row.addElement(reviewer_w_tc)
|
coeff_row.addElement(reviewer_w_tc)
|
||||||
|
|
||||||
reviewer_o_tc = TableCell(valuetype="float", value=1, stylename=style_right)
|
reviewer_o_tc = TableCell(valuetype="float", value=passage.coeff_reviewer_oral,
|
||||||
reviewer_o_tc.addElement(P(text="1"))
|
stylename=style if has_observer else style_right)
|
||||||
|
reviewer_o_tc.addElement(P(text=str(passage.coeff_reviewer_oral)))
|
||||||
coeff_row.addElement(reviewer_o_tc)
|
coeff_row.addElement(reviewer_o_tc)
|
||||||
|
|
||||||
|
if has_observer:
|
||||||
|
observer_w_tc = TableCell(valuetype="float", value=passage.coeff_observer_writing, stylename=style)
|
||||||
|
observer_w_tc.addElement(P(text=str(passage.coeff_observer_writing)))
|
||||||
|
coeff_row.addElement(observer_w_tc)
|
||||||
|
|
||||||
|
observer_o_tc = TableCell(valuetype="float", value=passage.coeff_observer_oral, stylename=style_right)
|
||||||
|
observer_o_tc.addElement(P(text=str(passage.coeff_observer_oral)))
|
||||||
|
coeff_row.addElement(observer_o_tc)
|
||||||
|
|
||||||
# Add the subtotal on the next line
|
# Add the subtotal on the next line
|
||||||
subtotal_row = TableRow()
|
subtotal_row = TableRow()
|
||||||
table.addElement(subtotal_row)
|
table.addElement(subtotal_row)
|
||||||
subtotal_tc = TableCell(valuetype="string", stylename=title_style_botleft)
|
subtotal_tc = TableCell(valuetype="string", stylename=title_style_botleft)
|
||||||
subtotal_tc.addElement(P(text="Sous-total"))
|
subtotal_tc.addElement(P(text=_("Subtotal")))
|
||||||
subtotal_tc.setAttribute('numbercolumnsspanned', "2")
|
subtotal_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
subtotal_row.addElement(subtotal_tc)
|
subtotal_row.addElement(subtotal_tc)
|
||||||
subtotal_row.addElement(CoveredTableCell())
|
subtotal_row.addElement(CoveredTableCell())
|
||||||
|
@ -1656,7 +1686,8 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
|
|
||||||
rep_w_col = getcol(min_column + passage_width * i + 4)
|
rep_w_col = getcol(min_column + passage_width * i + 4)
|
||||||
rep_o_col = getcol(min_column + passage_width * i + 5)
|
rep_o_col = getcol(min_column + passage_width * i + 5)
|
||||||
reviewer_tc = TableCell(valuetype="float", value=passage.average_reviewer, stylename=style_botright)
|
reviewer_tc = TableCell(valuetype="float", value=passage.average_reviewer,
|
||||||
|
stylename=style_bot if has_observer else style_botright)
|
||||||
reviewer_tc.addElement(P(text=str(passage.average_reviewer)))
|
reviewer_tc.addElement(P(text=str(passage.average_reviewer)))
|
||||||
reviewer_tc.setAttribute('numbercolumnsspanned', "2")
|
reviewer_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
reviewer_tc.setAttribute("formula", f"of:=[.{rep_w_col}{max_row + 1}] * [.{rep_w_col}{max_row + 2}]"
|
reviewer_tc.setAttribute("formula", f"of:=[.{rep_w_col}{max_row + 1}] * [.{rep_w_col}{max_row + 2}]"
|
||||||
|
@ -1664,6 +1695,17 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
subtotal_row.addElement(reviewer_tc)
|
subtotal_row.addElement(reviewer_tc)
|
||||||
subtotal_row.addElement(CoveredTableCell())
|
subtotal_row.addElement(CoveredTableCell())
|
||||||
|
|
||||||
|
if has_observer:
|
||||||
|
obs_w_col = getcol(min_column + passage_width * i + 6)
|
||||||
|
obs_o_col = getcol(min_column + passage_width * i + 7)
|
||||||
|
observer_tc = TableCell(valuetype="float", value=passage.average_observer, stylename=style_botright)
|
||||||
|
observer_tc.addElement(P(text=str(passage.average_observer)))
|
||||||
|
observer_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
|
observer_tc.setAttribute("formula", f"of:=[.{obs_w_col}{max_row + 1}] * [.{obs_w_col}{max_row + 2}]"
|
||||||
|
f" + [.{obs_o_col}{max_row + 1}] * [.{obs_o_col}{max_row + 2}]")
|
||||||
|
subtotal_row.addElement(observer_tc)
|
||||||
|
subtotal_row.addElement(CoveredTableCell())
|
||||||
|
|
||||||
table.addElement(TableRow())
|
table.addElement(TableRow())
|
||||||
|
|
||||||
if self.object.participations.count() == 5:
|
if self.object.participations.count() == 5:
|
||||||
|
@ -1681,17 +1723,17 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
scores_header = TableRow()
|
scores_header = TableRow()
|
||||||
table.addElement(scores_header)
|
table.addElement(scores_header)
|
||||||
team_tc = TableCell(valuetype="string", stylename=title_style_topbotleft)
|
team_tc = TableCell(valuetype="string", stylename=title_style_topbotleft)
|
||||||
team_tc.addElement(P(text="Équipe"))
|
team_tc.addElement(P(text=_("Team")))
|
||||||
team_tc.setAttribute('numbercolumnsspanned', "2")
|
team_tc.setAttribute('numbercolumnsspanned', "2")
|
||||||
scores_header.addElement(team_tc)
|
scores_header.addElement(team_tc)
|
||||||
problem_tc = TableCell(valuetype="string", stylename=title_style_topbot)
|
problem_tc = TableCell(valuetype="string", stylename=title_style_topbot)
|
||||||
problem_tc.addElement(P(text="Problème"))
|
problem_tc.addElement(P(text=_("Problem")))
|
||||||
scores_header.addElement(problem_tc)
|
scores_header.addElement(problem_tc)
|
||||||
total_tc = TableCell(valuetype="string", stylename=title_style_topbot)
|
total_tc = TableCell(valuetype="string", stylename=title_style_topbot)
|
||||||
total_tc.addElement(P(text="Total"))
|
total_tc.addElement(P(text=_("Total")))
|
||||||
scores_header.addElement(total_tc)
|
scores_header.addElement(total_tc)
|
||||||
rank_tc = TableCell(valuetype="string", stylename=title_style_topbotright)
|
rank_tc = TableCell(valuetype="string", stylename=title_style_topbotright)
|
||||||
rank_tc.addElement(P(text="Rang"))
|
rank_tc.addElement(P(text=_("Rank")))
|
||||||
scores_header.addElement(rank_tc)
|
scores_header.addElement(rank_tc)
|
||||||
|
|
||||||
sorted_participations = sorted(self.object.participations.all(), key=lambda p: -self.object.average(p))
|
sorted_participations = sorted(self.object.participations.all(), key=lambda p: -self.object.average(p))
|
||||||
|
@ -1707,13 +1749,15 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
|
|
||||||
problem_tc = TableCell(valuetype="string",
|
problem_tc = TableCell(valuetype="string",
|
||||||
stylename=style_bot if passage.position == pool_size else style)
|
stylename=style_bot if passage.position == pool_size else style)
|
||||||
problem_tc.addElement(P(text=f"Problème {passage.solution_number}"))
|
problem_tc.addElement(P(text=_("Problem #{problem}").format(problem=passage.solution_number)))
|
||||||
problem_tc.setAttribute("formula", f"of:=[.B{3 + passage_width * (passage.position - 1)}]")
|
problem_tc.setAttribute("formula", f"of:=[.B{3 + passage_width * (passage.position - 1)}]")
|
||||||
team_row.addElement(problem_tc)
|
team_row.addElement(problem_tc)
|
||||||
|
|
||||||
defender_pos = passage.position - 1
|
defender_pos = passage.position - 1
|
||||||
opponent_pos = self.object.passages.get(opponent=passage.defender).position - 1
|
opponent_pos = self.object.passages.get(opponent=passage.defender).position - 1
|
||||||
reviewer_pos = self.object.passages.get(reviewer=passage.defender).position - 1
|
reviewer_pos = self.object.passages.get(reviewer=passage.defender).position - 1
|
||||||
|
observer_pos = self.object.passages.get(observer=passage.defender).position - 1 \
|
||||||
|
if has_observer else None
|
||||||
|
|
||||||
score_tc = TableCell(valuetype="float", value=self.object.average(passage.defender),
|
score_tc = TableCell(valuetype="float", value=self.object.average(passage.defender),
|
||||||
stylename=style_bot if passage.position == pool_size else style)
|
stylename=style_bot if passage.position == pool_size else style)
|
||||||
|
@ -1721,7 +1765,10 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
formula = "of:="
|
formula = "of:="
|
||||||
formula += getcol(min_column + defender_pos * passage_width) + str(max_row + 3) # Defender
|
formula += getcol(min_column + defender_pos * passage_width) + str(max_row + 3) # Defender
|
||||||
formula += " + " + getcol(min_column + opponent_pos * passage_width + 2) + str(max_row + 3) # Opponent
|
formula += " + " + getcol(min_column + opponent_pos * passage_width + 2) + str(max_row + 3) # Opponent
|
||||||
formula += " + " + getcol(min_column + reviewer_pos * passage_width + 4) + str(max_row + 3) # reviewer
|
formula += " + " + getcol(min_column + reviewer_pos * passage_width + 4) + str(max_row + 3) # Reviewer
|
||||||
|
if has_observer:
|
||||||
|
# Observer
|
||||||
|
formula += " + " + getcol(min_column + observer_pos * passage_width + 6) + str(max_row + 3)
|
||||||
score_tc.setAttribute("formula", formula)
|
score_tc.setAttribute("formula", formula)
|
||||||
team_row.addElement(score_tc)
|
team_row.addElement(score_tc)
|
||||||
|
|
||||||
|
@ -1730,7 +1777,8 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
stylename=style_botright if passage.position == pool_size else style_right)
|
stylename=style_botright if passage.position == pool_size else style_right)
|
||||||
rank_tc.addElement(P(text=str(sorted_participations.index(passage.defender) + 1)))
|
rank_tc.addElement(P(text=str(sorted_participations.index(passage.defender) + 1)))
|
||||||
rank_tc.setAttribute("formula", f"of:=RANK([.{score_col}{max_row + 5 + passage.position}]; "
|
rank_tc.setAttribute("formula", f"of:=RANK([.{score_col}{max_row + 5 + passage.position}]; "
|
||||||
f"[.{score_col}${max_row + 6}]:[.{score_col}${max_row + 5 + pool_size}])")
|
f"[.{score_col}${max_row + 6}]:"
|
||||||
|
f"[.{score_col}${max_row + 5 + pool_size}])")
|
||||||
team_row.addElement(rank_tc)
|
team_row.addElement(rank_tc)
|
||||||
|
|
||||||
table.addElement(TableRow())
|
table.addElement(TableRow())
|
||||||
|
@ -1755,8 +1803,8 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
|
||||||
|
|
||||||
return FileResponse(streaming_content=open("/tmp/notes.ods", "rb"),
|
return FileResponse(streaming_content=open("/tmp/notes.ods", "rb"),
|
||||||
content_type="application/vnd.oasis.opendocument.spreadsheet",
|
content_type="application/vnd.oasis.opendocument.spreadsheet",
|
||||||
filename=f"Feuille de notes - {self.object.tournament.name} "
|
filename=f"{_('Notation sheet')} - {self.object.tournament.name} "
|
||||||
f"- Poule {self.object.short_name}.ods")
|
f"- {_('Pool')} {self.object.short_name}.ods")
|
||||||
|
|
||||||
|
|
||||||
class NotationSheetTemplateView(VolunteerMixin, DetailView):
|
class NotationSheetTemplateView(VolunteerMixin, DetailView):
|
||||||
|
|
Loading…
Reference in New Issue