Split 5-teams pols in two pools for each room

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello 2024-04-18 14:53:58 +02:00
parent 059cae75c5
commit 266afaf5c9
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
9 changed files with 337 additions and 238 deletions

View File

@ -361,6 +361,17 @@ class Pool(models.Model):
.prefetch_related('participation')])
await self.asave()
pool2 = None
if self.size == 5:
pool2, _created = await PPool.objects.aget_or_create(
tournament=self.round.draw.tournament,
round=self.round.number,
letter=self.letter,
room=2,
)
await pool2.participations.aset([td.participation async for td in self.team_draws
.prefetch_related('participation')])
# Define the passage matrix according to the number of teams
table = []
if self.size == 3:
@ -380,16 +391,24 @@ class Pool(models.Model):
table = [
[0, 2, 3],
[1, 3, 4],
[4, 0, 2],
[2, 4, 0],
[3, 0, 1],
[4, 1, 2],
]
for i, line in enumerate(table):
passage_pool = self.associated_pool
passage_position = i + 1
if self.size == 5:
# In 5-teams pools, we may create some passages in the second room
if i % 2 == 1:
passage_pool = pool2
passage_position = 1 + i // 2
# Create the passage
await Passage.objects.acreate(
pool=self.associated_pool,
position=i + 1,
pool=passage_pool,
position=passage_position,
solution_number=tds[line[0]].accepted,
defender=tds[line[0]].participation,
opponent=tds[line[1]].participation,

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: TFJM\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-16 23:57+0200\n"
"POT-Creation-Date: 2024-04-17 22:47+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -29,15 +29,15 @@ msgstr "équipes"
#: draw/admin.py:53 draw/admin.py:71 draw/admin.py:88 draw/models.py:26
#: participation/admin.py:79 participation/admin.py:140
#: participation/admin.py:171 participation/models.py:656
#: participation/models.py:680 participation/models.py:886
#: participation/admin.py:171 participation/models.py:683
#: participation/models.py:707 participation/models.py:927
#: registration/models.py:756
#: registration/templates/registration/payment_form.html:53
msgid "tournament"
msgstr "tournoi"
#: draw/admin.py:92 draw/models.py:234 draw/models.py:429
#: participation/models.py:890
#: draw/admin.py:92 draw/models.py:234 draw/models.py:448
#: participation/models.py:931
msgid "round"
msgstr "tour"
@ -175,7 +175,7 @@ msgstr "La poule en cours, où les équipes choisissent leurs problèmes"
msgid "rounds"
msgstr "tours"
#: draw/models.py:257 participation/models.py:904
#: draw/models.py:257 participation/models.py:939
msgid "letter"
msgstr "lettre"
@ -208,82 +208,82 @@ msgstr "poule associée"
msgid "The full pool instance."
msgstr "L'instance complète de la poule."
#: draw/models.py:407
#: draw/models.py:426
#, python-brace-format
msgid "Pool {letter}{number}"
msgstr "Poule {letter}{number}"
#: draw/models.py:410 draw/models.py:437 participation/admin.py:136
#: participation/admin.py:155 participation/models.py:1364
#: participation/models.py:1373 participation/tables.py:84
#: draw/models.py:429 draw/models.py:456 participation/admin.py:136
#: participation/admin.py:155 participation/models.py:1397
#: participation/models.py:1406 participation/tables.py:84
msgid "pool"
msgstr "poule"
#: draw/models.py:411 participation/models.py:1365
#: draw/models.py:430 participation/models.py:1398
msgid "pools"
msgstr "poules"
#: draw/models.py:423 participation/models.py:876 participation/models.py:1514
#: participation/models.py:1544 participation/models.py:1586
#: draw/models.py:442 participation/models.py:917 participation/models.py:1547
#: participation/models.py:1577 participation/models.py:1619
msgid "participation"
msgstr "participation"
#: draw/models.py:444
#: draw/models.py:463
msgid "passage index"
msgstr "numéro de passage"
#: draw/models.py:445
#: draw/models.py:464
msgid ""
"The passage order in the pool, between 0 and the size of the pool minus 1."
msgstr ""
"L'ordre de passage dans la poule, de 0 à la taille de la poule moins 1."
#: draw/models.py:453
#: draw/models.py:472
msgid "choose index"
msgstr "numéro de choix"
#: draw/models.py:454
#: draw/models.py:473
msgid ""
"The choice order in the pool, between 0 and the size of the pool minus 1."
msgstr ""
"L'ordre de choix dans la poule, entre 0 et la taille de la poule moins 1."
#: draw/models.py:460 draw/models.py:483 participation/models.py:1387
#: participation/models.py:1551
#: draw/models.py:479 draw/models.py:502 participation/models.py:1420
#: participation/models.py:1584
#, python-brace-format
msgid "Problem #{problem}"
msgstr "Problème n°{problem}"
#: draw/models.py:464
#: draw/models.py:483
msgid "accepted problem"
msgstr "problème accepté"
#: draw/models.py:471
#: draw/models.py:490
msgid "passage dice"
msgstr "dé d'ordre de passage"
#: draw/models.py:478
#: draw/models.py:497
msgid "choice dice"
msgstr "dé d'ordre de choix"
#: draw/models.py:487
#: draw/models.py:506
msgid "purposed problem"
msgstr "problème proposé"
#: draw/models.py:492
#: draw/models.py:511
msgid "rejected problems"
msgstr "problèmes rejetés"
#: draw/models.py:521
#: draw/models.py:540
#, python-brace-format
msgid "Draw of the team {trigram} for the pool {letter}{number}"
msgstr "Tirage de l'équipe {trigram} pour la poule {letter}{number}"
#: draw/models.py:527
#: draw/models.py:546
msgid "team draw"
msgstr "tirage d'équipe"
#: draw/models.py:528
#: draw/models.py:547
msgid "team draws"
msgstr "tirages d'équipe"
@ -332,7 +332,7 @@ msgid "Continue draw"
msgstr "Continuer le tirage"
#: draw/templates/draw/tournament_content.html:216 participation/admin.py:167
#: participation/models.py:252 participation/models.py:671
#: participation/models.py:252 participation/models.py:698
#: participation/templates/participation/tournament_harmonize.html:15
#: registration/models.py:157 registration/models.py:747
#: registration/tables.py:39
@ -345,35 +345,31 @@ msgstr "équipe"
#: draw/templates/draw/tournament_content.html:228
#: draw/templates/draw/tournament_content.html:229
#: draw/templates/draw/tournament_content.html:230
#: participation/templates/participation/pool_detail.html:85
#: participation/templates/participation/pool_detail.html:89
#: participation/templates/participation/pool_detail.html:94
#: participation/templates/participation/pool_detail.html:98
msgid "Room"
msgstr "Salle"
#: draw/templates/draw/tournament_content.html:335
#: draw/templates/draw/tournament_content.html:354
#: draw/templates/draw/tournament_content.html:334
#: draw/templates/draw/tournament_content.html:353
msgid "Abort"
msgstr "Annuler"
#: draw/templates/draw/tournament_content.html:345
#: draw/templates/draw/tournament_content.html:344
msgid "Are you sure?"
msgstr "Êtes-vous sûr⋅e ?"
#: draw/templates/draw/tournament_content.html:349
#: draw/templates/draw/tournament_content.html:348
msgid "This will reset the draw from the beginning."
msgstr "Cela va réinitialiser le tirage au sort depuis le début."
#: draw/templates/draw/tournament_content.html:350
#: draw/templates/draw/tournament_content.html:349
msgid "This operation is irreversible."
msgstr "Cette opération est irréversible."
#: draw/templates/draw/tournament_content.html:351
#: draw/templates/draw/tournament_content.html:350
msgid "Are you sure you want to abort this draw?"
msgstr "Êtes-vous sûr·e de vouloir annuler le tirage au sort ?"
#: draw/templates/draw/tournament_content.html:355
#: draw/templates/draw/tournament_content.html:354
#: tfjm/templates/base_modal.html:17
msgid "Close"
msgstr "Fermer"
@ -452,26 +448,26 @@ msgstr "Changelog de type \"{action}\" pour le modèle {model} le {timestamp}"
msgid "valid"
msgstr "valide"
#: participation/admin.py:87 participation/models.py:692
#: participation/admin.py:87 participation/models.py:719
msgid "selected for final"
msgstr "sélectionnée pour la finale"
#: participation/admin.py:124 participation/admin.py:183
#: participation/models.py:1394 participation/tables.py:112
#: participation/models.py:1427 participation/tables.py:112
msgid "defender"
msgstr "défenseur⋅se"
#: participation/admin.py:128 participation/models.py:1401
#: participation/models.py:1598
#: participation/admin.py:128 participation/models.py:1434
#: participation/models.py:1631
msgid "opponent"
msgstr "opposant⋅e"
#: participation/admin.py:132 participation/models.py:1408
#: participation/models.py:1599
#: participation/admin.py:132 participation/models.py:1441
#: participation/models.py:1632
msgid "reporter"
msgstr "rapporteur⋅rice"
#: participation/admin.py:187 participation/models.py:1549
#: participation/admin.py:187 participation/models.py:1582
msgid "problem"
msgstr "numéro de problème"
@ -799,28 +795,36 @@ msgstr "finale"
msgid "Google Sheet ID"
msgstr "ID de la feuille Google Sheets"
#: participation/models.py:657 registration/admin.py:125
#: participation/models.py:684 registration/admin.py:125
msgid "tournaments"
msgstr "tournois"
#: participation/models.py:686
#: participation/models.py:713
msgid "valid team"
msgstr "équipe valide"
#: participation/models.py:687
#: participation/models.py:714
msgid "The participation got the validation of the organizers."
msgstr "La participation a été validée par les organisateur⋅rices."
#: participation/models.py:693
#: participation/models.py:720
msgid "The team is selected for the final tournament."
msgstr "L'équipe est sélectionnée pour la finale."
#: participation/models.py:700
#: participation/models.py:724
msgid "mention"
msgstr "mention"
#: participation/models.py:731
msgid "mention (final)"
msgstr "Mention (pour la finale) :"
#: participation/models.py:741
#, python-brace-format
msgid "Participation of the team {name} ({trigram})"
msgstr "Participation de l'équipe {name} ({trigram})"
#: participation/models.py:707
#: participation/models.py:748
#, python-brace-format
msgid ""
"<p>The team {trigram} has {nb_missing_payments} missing payments. Each "
@ -833,11 +837,11 @@ msgstr ""
"notification de bourse) pour participer au tournoi.</p><p>Les participant⋅es "
"qui n'ont pas encore payé sont : {participants}.</p>"
#: participation/models.py:715
#: participation/models.py:756
msgid "Missing payments"
msgstr "Paiements manquants"
#: participation/models.py:732
#: participation/models.py:773
msgid ""
"<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> "
@ -852,11 +856,11 @@ msgstr ""
"pouvez envoyer vos solutions sur <a href='{url}'>votre page de "
"participation</a>.</p>"
#: participation/models.py:742 participation/models.py:756
#: participation/models.py:783 participation/models.py:797
msgid "Solutions due"
msgstr "Rendu des solutions"
#: participation/models.py:748
#: participation/models.py:789
msgid ""
"<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 "
@ -869,7 +873,7 @@ msgstr ""
"parties.</p><p>Vous pouvez envoyer vos solutions sur <a href='{url}'>votre "
"page de participation</a>.</p>"
#: participation/models.py:762 registration/models.py:600
#: participation/models.py:803 registration/models.py:600
msgid ""
"<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>."
@ -879,11 +883,11 @@ msgstr ""
"{date:%d/%m/%Y %H:%M}. Vous pouvez y participer sur <a href='{url}'>ce lien</"
"a>.</p>"
#: participation/models.py:768 registration/models.py:607
#: participation/models.py:809 registration/models.py:607
msgid "Draw of solutions"
msgstr "Tirage au sort des solutions"
#: participation/models.py:779
#: participation/models.py:820
#, python-brace-format
msgid ""
"<p>The solutions draw is ended. You can check the result on <a "
@ -895,7 +899,7 @@ msgstr ""
"tour, vous défendrez <a href='{solution_url}'>votre solution du problème "
"{problem}</a>.</p>"
#: participation/models.py:788 participation/models.py:831
#: participation/models.py:829 participation/models.py:872
#, python-brace-format
msgid ""
"<p>You will oppose the solution of the team {opponent} on the <a "
@ -906,7 +910,7 @@ msgstr ""
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
#: participation/models.py:797 participation/models.py:840
#: participation/models.py:838 participation/models.py:881
#, python-brace-format
msgid ""
"<p>You will report the solution of the team {reporter} on the <a "
@ -917,11 +921,11 @@ msgstr ""
"href='{solution_url}'>problème {problem}</a>. Vous pouvez envoyer votre note "
"de synthèse sur <a href='{passage_url}'>cette page</a>.</p>"
#: participation/models.py:813 registration/models.py:622
#: participation/models.py:854 registration/models.py:622
msgid "First round"
msgstr "Premier tour"
#: participation/models.py:824
#: participation/models.py:865
#, python-brace-format
msgid ""
"<p>For the second round, you will defend <a href='{solution_url}'>your "
@ -930,11 +934,11 @@ msgstr ""
"<p>Pour le second tour, vous défendrez <a href='{solution_url}'>votre "
"solution du problème {problem}</a>.</p>"
#: participation/models.py:856 registration/models.py:633
#: participation/models.py:897 registration/models.py:633
msgid "Second round"
msgstr "Second tour"
#: participation/models.py:862
#: participation/models.py:903
#, python-brace-format
msgid ""
"<p>The tournament {tournament} is ended. You can check the results on the <a "
@ -943,40 +947,56 @@ msgstr ""
"<p>Le tournoi {tournament} est terminé. Vous pouvez consulter les résultats "
"sur la <a href='{url}'>page du tournoi</a>.</p>"
#: participation/models.py:867
#: participation/models.py:908
msgid "Tournament ended"
msgstr "Tournoi terminé"
#: participation/models.py:877 participation/models.py:910
#: participation/models.py:918 participation/models.py:961
msgid "participations"
msgstr "participations"
#: participation/models.py:892 participation/models.py:893
#: participation/models.py:933 participation/models.py:934
#, python-brace-format
msgid "Round {round}"
msgstr "Tour {round}"
#: participation/models.py:916
#: participation/models.py:949
msgid "room"
msgstr "salle"
#: participation/models.py:951
msgid "Room 1"
msgstr "Salle 1"
#: participation/models.py:952
msgid "Room 2"
msgstr "Salle 2"
#: participation/models.py:955
msgid "For 5-teams pools only"
msgstr "Pour les poules de 5 équipe uniquement"
#: participation/models.py:967
msgid "juries"
msgstr "jurys"
#: participation/models.py:925
#: participation/models.py:976
msgid "president of the jury"
msgstr "président⋅e du jury"
#: participation/models.py:932
#: participation/models.py:983
msgid "BigBlueButton URL"
msgstr "Lien BigBlueButton"
#: participation/models.py:933
#: participation/models.py:984
msgid "The link of the BBB visio for this pool."
msgstr "Le lien du salon BBB pour cette poule."
#: participation/models.py:938
#: participation/models.py:989
msgid "results available"
msgstr "résultats disponibles"
#: participation/models.py:939
#: participation/models.py:990
msgid ""
"Check this case when results become accessible to teams. They stay "
"accessible to you. Only averages are given."
@ -985,33 +1005,33 @@ msgstr ""
"Ils restent toujours accessibles pour vous. Seules les moyennes sont "
"communiquées."
#: participation/models.py:964
#: participation/models.py:1018
msgid "The president of the jury must be part of the jury."
msgstr "Læ président⋅e du jury doit faire partie du jury."
#: participation/models.py:1345
#: participation/models.py:1378
#, python-brace-format
msgid "The jury {jury} is not part of the jury for this pool."
msgstr "{jury} ne fait pas partie du jury pour cette poule."
#: participation/models.py:1358
#: participation/models.py:1391
#, python-brace-format
msgid "Pool of day {round} for tournament {tournament} with teams {teams}"
msgstr "Poule du jour {round} du tournoi {tournament} avec les équipes {teams}"
#: participation/models.py:1378
#: participation/models.py:1411
msgid "position"
msgstr "position"
#: participation/models.py:1385
#: participation/models.py:1418
msgid "defended solution"
msgstr "solution défendue"
#: participation/models.py:1413
#: participation/models.py:1446
msgid "penalties"
msgstr "pénalités"
#: participation/models.py:1415
#: participation/models.py:1448
msgid ""
"Number of penalties for the defender. The defender will loose a 0.5 "
"coefficient per penalty."
@ -1019,120 +1039,120 @@ msgstr ""
"Nombre de pénalités pour l'équipe défenseuse. Elle perd un coefficient 0.5 "
"sur sa présentation orale par pénalité."
#: participation/models.py:1484 participation/models.py:1487
#: participation/models.py:1490
#: participation/models.py:1517 participation/models.py:1520
#: participation/models.py:1523
#, python-brace-format
msgid "Team {trigram} is not registered in the pool."
msgstr "L'équipe {trigram} n'est pas inscrite dans la poule."
#: participation/models.py:1495
#: participation/models.py:1528
#, python-brace-format
msgid "Passage of {defender} for problem {problem}"
msgstr "Passage de {defender} pour le problème {problem}"
#: participation/models.py:1499 participation/models.py:1508
#: participation/models.py:1593 participation/models.py:1635
#: participation/models.py:1532 participation/models.py:1541
#: participation/models.py:1626 participation/models.py:1668
msgid "passage"
msgstr "passage"
#: participation/models.py:1500
#: participation/models.py:1533
msgid "passages"
msgstr "passages"
#: participation/models.py:1519
#: participation/models.py:1552
msgid "difference"
msgstr "différence"
#: participation/models.py:1520
#: participation/models.py:1553
msgid "Score to add/remove on the final score"
msgstr "Score à ajouter/retrancher au score final"
#: participation/models.py:1527
#: participation/models.py:1560
msgid "tweak"
msgstr "harmonisation"
#: participation/models.py:1528
#: participation/models.py:1561
msgid "tweaks"
msgstr "harmonisations"
#: participation/models.py:1556
#: participation/models.py:1589
msgid "solution for the final tournament"
msgstr "solution pour la finale"
#: participation/models.py:1561 participation/models.py:1604
#: participation/models.py:1594 participation/models.py:1637
msgid "file"
msgstr "fichier"
#: participation/models.py:1571
#: participation/models.py:1604
#, python-brace-format
msgid "Solution of team {team} for problem {problem}"
msgstr "Solution de l'équipe {team} pour le problème {problem}"
#: participation/models.py:1573
#: participation/models.py:1606
msgid "for final"
msgstr "pour la finale"
#: participation/models.py:1576
#: participation/models.py:1609
msgid "solution"
msgstr "solution"
#: participation/models.py:1577
#: participation/models.py:1610
msgid "solutions"
msgstr "solutions"
#: participation/models.py:1610
#: participation/models.py:1643
#, python-brace-format
msgid "Synthesis of {team} as {type} for problem {problem} of {defender}"
msgstr ""
"Note de synthèse de l'équipe {team} en tant que {type} pour le problème "
"{problem} de {defender}"
#: participation/models.py:1618
#: participation/models.py:1651
msgid "synthesis"
msgstr "note de synthèse"
#: participation/models.py:1619
#: participation/models.py:1652
msgid "syntheses"
msgstr "notes de synthèse"
#: participation/models.py:1628
#: participation/models.py:1661
msgid "jury"
msgstr "jury"
#: participation/models.py:1640
#: participation/models.py:1673
msgid "defender writing note"
msgstr "note d'écrit défenseur⋅se"
#: participation/models.py:1646
#: participation/models.py:1679
msgid "defender oral note"
msgstr "note d'oral défenseur⋅se"
#: participation/models.py:1652
#: participation/models.py:1685
msgid "opponent writing note"
msgstr "note d'écrit opposant⋅e"
#: participation/models.py:1658
#: participation/models.py:1691
msgid "opponent oral note"
msgstr "note d'oral opposant⋅e"
#: participation/models.py:1664
#: participation/models.py:1697
msgid "reporter writing note"
msgstr "note d'écrit rapporteur⋅rice"
#: participation/models.py:1670
#: participation/models.py:1703
msgid "reporter oral note"
msgstr "note d'oral du rapporteur⋅rice"
#: participation/models.py:1728
#: participation/models.py:1761
#, python-brace-format
msgid "Notes of {jury} for {passage}"
msgstr "Notes de {jury} pour le {passage}"
#: participation/models.py:1731
#: participation/models.py:1764
msgid "note"
msgstr "note"
#: participation/models.py:1732
#: participation/models.py:1765
msgid "notes"
msgstr "notes"
@ -1159,8 +1179,8 @@ msgstr "Du {start} au {end}"
#: participation/tables.py:94
#, python-brace-format
msgid "Pool {letter}{round}"
msgstr "Poule {letter}{round}"
msgid "Pool {code}"
msgstr "Poule {code}"
#: participation/tables.py:98
msgid "No defined team"
@ -1172,7 +1192,7 @@ msgstr "Pas d'équipe définie"
#: participation/templates/participation/passage_detail.html:140
#: participation/templates/participation/passage_detail.html:146
#: participation/templates/participation/pool_detail.html:13
#: participation/templates/participation/pool_detail.html:157
#: participation/templates/participation/pool_detail.html:152
#: participation/templates/participation/team_detail.html:179
#: participation/templates/participation/team_detail.html:243
#: participation/templates/participation/tournament_form.html:12
@ -1273,7 +1293,7 @@ msgstr "Envoyer une solution"
#: participation/templates/participation/participation_detail.html:65
#: participation/templates/participation/passage_detail.html:152
#: participation/templates/participation/pool_detail.html:162
#: participation/templates/participation/pool_detail.html:157
#: participation/templates/participation/team_detail.html:238
#: participation/templates/participation/upload_motivation_letter.html:13
#: participation/templates/participation/upload_notes.html:24
@ -1321,12 +1341,12 @@ msgid "Defender penalties count:"
msgstr "Nombre de pénalités :"
#: participation/templates/participation/passage_detail.html:43
#: participation/templates/participation/pool_detail.html:54
#: participation/templates/participation/pool_detail.html:59
msgid "Syntheses:"
msgstr "Notes de synthèse :"
#: participation/templates/participation/passage_detail.html:48
#: participation/templates/participation/pool_detail.html:63
#: participation/templates/participation/pool_detail.html:68
msgid "No synthesis was uploaded yet."
msgstr "Aucune note de synthèse n'a encore été envoyée."
@ -1393,36 +1413,40 @@ msgstr "Tour :"
msgid "Letter:"
msgstr "Lettre :"
#: participation/templates/participation/pool_detail.html:29
#: participation/templates/participation/pool_detail.html:30
msgid "Room:"
msgstr "Salle :"
#: participation/templates/participation/pool_detail.html:34
msgid "Teams:"
msgstr "Équipes :"
#: participation/templates/participation/pool_detail.html:36
#: participation/templates/participation/pool_detail.html:41
msgid "Juries:"
msgstr "Juré⋅es :"
#: participation/templates/participation/pool_detail.html:40
#: participation/templates/participation/pool_detail.html:45
msgid "Edit jury"
msgstr "Modifier le jury"
#: participation/templates/participation/pool_detail.html:44
#: participation/templates/participation/pool_detail.html:49
msgid "Defended solutions:"
msgstr "Solutions défendues :"
#: participation/templates/participation/pool_detail.html:50
#: participation/templates/participation/pool_detail.html:69
#: participation/templates/participation/pool_detail.html:55
#: participation/templates/participation/pool_detail.html:74
msgid "Download all"
msgstr "Tout télécharger"
#: participation/templates/participation/pool_detail.html:74
#: participation/templates/participation/pool_detail.html:79
msgid "BigBlueButton link:"
msgstr "Lien BigBlueButton :"
#: participation/templates/participation/pool_detail.html:80
#: participation/templates/participation/pool_detail.html:85
msgid "Notation sheets:"
msgstr "Feuilles de notations :"
#: participation/templates/participation/pool_detail.html:85
#: participation/templates/participation/pool_detail.html:90
msgid "Download the scale sheet"
msgstr "Télécharger la feuille de barème"
@ -1430,42 +1454,42 @@ msgstr "Télécharger la feuille de barème"
msgid "Download the final notation sheet"
msgstr "Télécharger la fiche de notation finale"
#: participation/templates/participation/pool_detail.html:103
#: participation/templates/participation/pool_detail.html:98
msgid "Download all notation sheets"
msgstr "Télécharger toutes les fiches de notation"
#: participation/templates/participation/pool_detail.html:108
#: participation/templates/participation/pool_detail.html:103
msgid "Google Sheets Spreadsheet:"
msgstr "Tableur Google Sheets :"
#: participation/templates/participation/pool_detail.html:112
#: participation/templates/participation/pool_detail.html:107
msgid "Go to the Google Sheets page of the pool"
msgstr "Aller à la page Google Sheets de la poule"
#: participation/templates/participation/pool_detail.html:121
#: participation/templates/participation/pool_detail.html:116
#: participation/templates/participation/tournament_detail.html:101
#: participation/templates/participation/tournament_harmonize.html:8
msgid "Ranking"
msgstr "Classement"
#: participation/templates/participation/pool_detail.html:136
#: participation/templates/participation/pool_detail.html:131
msgid "Upload notes from a spreadsheet file"
msgstr "Soumettre les notes à partir d'un tableur"
#: participation/templates/participation/pool_detail.html:140
#: participation/templates/participation/pool_detail.html:135
msgid "Download notation spreadsheet"
msgstr "Télécharger le tableur de notes"
#: participation/templates/participation/pool_detail.html:152
#: participation/templates/participation/pool_detail.html:147
msgid "Passages"
msgstr "Passages"
#: participation/templates/participation/pool_detail.html:156
#: participation/templates/participation/pool_detail.html:151
#: participation/templates/participation/pool_form.html:11
msgid "Update pool"
msgstr "Modifier la poule"
#: participation/templates/participation/pool_detail.html:161
#: participation/templates/participation/pool_detail.html:156
msgid "Upload notes"
msgstr "Envoyer les notes"
@ -1763,41 +1787,41 @@ msgstr "Accéder à la liste des paiements"
msgid "Pools"
msgstr "Poules"
#: participation/templates/participation/tournament_detail.html:111
#: participation/templates/participation/tournament_detail.html:119
msgid "Selected for final tournament"
msgstr "Sélectionnée pour la finale"
#: participation/templates/participation/tournament_detail.html:119
#: participation/templates/participation/tournament_detail.html:127
msgid "Select for final tournament"
msgstr "Sélectionner pour la finale"
#: participation/templates/participation/tournament_detail.html:132
#: participation/templates/participation/tournament_detail.html:136
#: participation/templates/participation/tournament_detail.html:140
#: participation/templates/participation/tournament_detail.html:144
msgid "Harmonize"
msgstr "Harmoniser"
#: participation/templates/participation/tournament_detail.html:132
#: participation/templates/participation/tournament_detail.html:136
#: participation/templates/participation/tournament_detail.html:140
#: participation/templates/participation/tournament_detail.html:144
msgid "Day"
msgstr "Jour"
#: participation/templates/participation/tournament_detail.html:145
#: participation/templates/participation/tournament_detail.html:153
msgid "Publish notes for first round"
msgstr "Publier les notes pour le premier tour"
#: participation/templates/participation/tournament_detail.html:150
#: participation/templates/participation/tournament_detail.html:158
msgid "Unpublish notes for first round"
msgstr "Dépublier les notes pour le premier tour"
#: participation/templates/participation/tournament_detail.html:156
#: participation/templates/participation/tournament_detail.html:164
msgid "Publish notes for second round"
msgstr "Publier les notes pour le second tour"
#: participation/templates/participation/tournament_detail.html:161
#: participation/templates/participation/tournament_detail.html:169
msgid "Unpublish notes for second round"
msgstr "Dépublier les notes pour le second tour"
#: participation/templates/participation/tournament_detail.html:173
#: participation/templates/participation/tournament_detail.html:181
msgid "Files available for download"
msgstr "Fichiers disponibles au téléchargement"
@ -2061,17 +2085,17 @@ msgstr "L'utilisateur⋅rice suivant n'est pas inscrit⋅e en tant que juré⋅e
msgid "Notes were successfully uploaded."
msgstr "Les notes ont bien été envoyées."
#: participation/views.py:1855
#: participation/views.py:1825
#, python-brace-format
msgid "Notation sheets of pool {pool} of {tournament}.zip"
msgstr "Feuilles de notations pour la poule {pool} du tournoi {tournament}.zip"
#: participation/views.py:1860
#: participation/views.py:1830
#, python-brace-format
msgid "Notation sheets of {tournament}.zip"
msgstr "Feuilles de notation de {tournament}.zip"
#: participation/views.py:2033
#: participation/views.py:1995
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."

View File

@ -100,8 +100,8 @@ class ParticipationAdmin(admin.ModelAdmin):
@admin.register(Pool)
class PoolAdmin(admin.ModelAdmin):
list_display = ('__str__', 'tournament', 'round', 'letter', 'teams', 'jury_president',)
list_filter = ('tournament', 'round', 'letter',)
list_display = ('__str__', 'tournament', 'round', 'letter', 'room', 'teams', 'jury_president',)
list_filter = ('tournament', 'round', 'letter', 'room',)
search_fields = ('participations__team__name', 'participations__team__trigram',)
autocomplete_fields = ('tournament', 'participations', 'jury_president', 'juries',)
inlines = (PassageInline, TweakInline,)

View File

@ -0,0 +1,31 @@
# Generated by Django 5.0.3 on 2024-04-17 20:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("participation", "0012_participation_mention_participation_mention_final"),
]
operations = [
migrations.AlterModelOptions(
name="pool",
options={
"ordering": ("round", "letter", "room"),
"verbose_name": "pool",
"verbose_name_plural": "pools",
},
),
migrations.AddField(
model_name="pool",
name="room",
field=models.PositiveSmallIntegerField(
choices=[(1, "Room 1"), (2, "Room 2")],
default=1,
help_text="For 5-teams pools only",
verbose_name="room",
),
),
]

View File

@ -10,7 +10,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator, RegexVa
from django.db import models
from django.db.models import Index
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.text import format_lazy
from django.utils.timezone import localtime
@ -430,7 +430,9 @@ class Tournament(models.Model):
self.notes_sheet_id = spreadsheet.id
self.save()
def update_ranking_spreadsheet(self):
def update_ranking_spreadsheet(self): # noqa: C901
translation.activate('fr')
gc = gspread.service_account_from_dict(settings.GOOGLE_SERVICE_CLIENT)
spreadsheet = gc.open_by_key(self.notes_sheet_id)
worksheets = spreadsheet.worksheets()
@ -444,27 +446,35 @@ class Tournament(models.Model):
header = [["Équipe", "Score jour 1", "Harmonisation 1", "Score jour 2", "Harmonisation 2", "Total", "Rang"]]
lines = []
participations = self.participations.filter(pools__round=1, pools__tournament=self).all()
participations = self.participations.filter(pools__round=1, pools__tournament=self).distinct().all()
for i, participation in enumerate(participations):
line = [f"{participation.team.name} ({participation.team.trigram})"]
lines.append(line)
pool1 = self.pools.get(round=1, participations=participation)
passage1 = pool1.passages.get(defender=participation)
passage1 = Passage.objects.get(pool__tournament=self, pool__round=1, defender=participation)
pool1 = passage1.pool
if pool1.participations.count() != 5:
position1 = passage1.position
else:
position1 = (passage1.position - 1) * 2 + pool1.room
tweak1_qs = Tweak.objects.filter(pool=pool1, participation=participation)
tweak1 = tweak1_qs.get() if tweak1_qs.exists() else None
line.append(f"=SIERREUR('Poule {pool1.short_name}'!$D{pool1.juries.count() + 10 + passage1.position}; 0)")
line.append(f"=SIERREUR('Poule {pool1.short_name}'!$D{pool1.juries.count() + 10 + position1}; 0)")
line.append(tweak1.diff if tweak1 else 0)
if self.pools.filter(round=2, participations=participation).exists():
pool2 = self.pools.get(round=2, participations=participation)
passage2 = pool2.passages.get(defender=participation)
if Passage.objects.filter(pool__tournament=self, pool__round=2, defender=participation).exists():
passage2 = Passage.objects.get(pool__tournament=self, pool__round=2, defender=participation)
pool2 = passage2.pool
if pool2.participations.count() != 5:
position2 = passage2.position
else:
position2 = (passage2.position - 1) * 2 + pool2.room
tweak2_qs = Tweak.objects.filter(pool=pool2, participation=participation)
tweak2 = tweak2_qs.get() if tweak2_qs.exists() else None
line.append(
f"=SIERREUR('Poule {pool2.short_name}'!$D{pool2.juries.count() + 10 + passage2.position}; 0)")
f"=SIERREUR('Poule {pool2.short_name}'!$D{pool2.juries.count() + 10 + position2}; 0)")
line.append(tweak2.diff if tweak2 else 0)
else:
# User has no second pool yet
@ -936,13 +946,23 @@ class Pool(models.Model):
)
letter = models.PositiveSmallIntegerField(
verbose_name=_('letter'),
choices=[
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D'),
],
verbose_name=_('letter'),
)
room = models.PositiveSmallIntegerField(
verbose_name=_("room"),
choices=[
(1, _("Room 1")),
(2, _("Room 2")),
],
default=1,
help_text=_("For 5-teams pools only"),
)
participations = models.ManyToManyField(
@ -983,7 +1003,10 @@ class Pool(models.Model):
@property
def short_name(self):
return f"{self.get_letter_display()}{self.round}"
short_name = f"{self.get_letter_display()}{self.round}"
if self.participations.count() == 5:
short_name += f"{self.get_room_display()}"
return short_name
@property
def solutions(self):
@ -1006,6 +1029,8 @@ class Pool(models.Model):
return super().validate_constraints()
def update_spreadsheet(self): # noqa: C901
translation.activate('fr')
# Create tournament sheet if it does not exist
self.tournament.create_spreadsheet()
@ -1085,18 +1110,38 @@ class Pool(models.Model):
ranking = [
["Équipe", "", "Problème", "Total", "Rang"],
]
for passage in passages:
all_passages = Passage.objects.filter(pool__tournament=self.tournament,
pool__round=self.round,
pool__letter=self.letter).order_by('position', 'pool__room')
for i, passage in enumerate(all_passages):
participation = passage.defender
defender_pos = passage.position - 1
opponent_pos = passages.get(opponent=passage.defender).position - 1
reporter_pos = passages.get(reporter=passage.defender).position - 1
defender_passage = Passage.objects.get(defender=participation,
pool__tournament=self.tournament, pool__round=self.round)
defender_row = 5 + defender_passage.pool.juries.count()
defender_col = defender_passage.position - 1
opponent_passage = Passage.objects.get(opponent=participation,
pool__tournament=self.tournament, pool__round=self.round)
opponent_row = 5 + opponent_passage.pool.juries.count()
opponent_col = opponent_passage.position - 1
reporter_passage = Passage.objects.get(reporter=participation,
pool__tournament=self.tournament, pool__round=self.round)
reporter_row = 5 + reporter_passage.pool.juries.count()
reporter_col = reporter_passage.position - 1
formula = "="
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 + reporter_pos * passage_width + 4) + str(max_row + 3) # Reporter
formula += (f"'Poule {defender_passage.pool.short_name}'"
f"!{getcol(min_column + defender_col * passage_width)}{defender_row + 3}") # Defender
formula += (f" + 'Poule {opponent_passage.pool.short_name}'"
f"!{getcol(min_column + opponent_col * passage_width + 2)}{opponent_row + 3}") # Opponent
formula += (f" + 'Poule {reporter_passage.pool.short_name}'"
f"!{getcol(min_column + reporter_col * passage_width + 4)}{reporter_row + 3}") # Reporter
ranking.append([f"{participation.team.name} ({participation.team.trigram})", "",
f"=${getcol(3 + (passage.position - 1) * passage_width)}$1", formula,
f"=RANG(D{max_row + 5 + passage.position}; "
f"='Poule {defender_passage.pool.short_name}'"
f"!${getcol(3 + defender_col * passage_width)}$1",
formula,
f"=RANG(D{max_row + 6 + i}; "
f"D${max_row + 6}:D${max_row + 5 + pool_size})"])
all_values = header + notes + footer + ranking
@ -1147,10 +1192,10 @@ class Pool(models.Model):
# Set background color for headers and footers
bg_colors = [("A1:AF", (1, 1, 1)),
(f"A1:{getcol(2 + pool_size * 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{max_row + 1}:B{max_row + 3}", (0.8, 0.8, 0.8)),
(f"C{max_row + 1}:{getcol(2 + pool_size * passage_width)}{max_row + 3}", (0.9, 0.9, 0.9)),
(f"C{max_row + 1}:{getcol(2 + passages.count() * passage_width)}{max_row + 3}", (0.9, 0.9, 0.9)),
(f"A{max_row + 5}:E{max_row + 5}", (0.8, 0.8, 0.8)),
(f"A{max_row + 6}:E{max_row + 5 + pool_size}", (0.9, 0.9, 0.9)),]
for bg_range, bg_color in bg_colors:
@ -1233,11 +1278,11 @@ class Pool(models.Model):
# Define borders
border_ranges = [("A1:AF", "0000"),
(f"A1:{getcol(2 + pool_size * 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"A1:B{max_row + 3}", "1113"),
(f"C1:{getcol(2 + (pool_size - 1) * passage_width)}1", "1113")]
for i in range(pool_size - 1):
(f"C1:{getcol(2 + (passages.count() - 1) * passage_width)}1", "1113")]
for i in range(passages.count() - 1):
border_ranges.append((f"{getcol(1 + (i + 1) * passage_width)}2"
f":{getcol(2 + (i + 1) * passage_width)}2", "1113"))
border_ranges.append((f"{getcol(2 + (i + 1) * passage_width)}3"
@ -1264,7 +1309,7 @@ class Pool(models.Model):
})
# Add range conditions
for i in range(pool_size):
for i in range(passages.count()):
for j in range(passage_width):
column = getcol(min_column + i * passage_width + j)
min_note = 0
@ -1286,9 +1331,9 @@ class Pool(models.Model):
})
# Set number format, display only one decimal
number_format_ranges = [f"C{max_row + 1}:{getcol(2 + passage_width * pool_size)}{max_row + 1}",
f"C{max_row + 3}:{getcol(2 + passage_width * pool_size)}{max_row + 3}",
f"D{max_row + 6}:D{max_row + 5 + pool_size}",]
number_format_ranges = [f"C{max_row + 1}:{getcol(2 + passage_width * passages.count())}{max_row + 1}",
f"C{max_row + 3}:{getcol(2 + passage_width * passages.count())}{max_row + 3}",
f"D{max_row + 6}:D{max_row + 5 + passages.count()}",]
for number_format_range in number_format_ranges:
format_requests.append({
"repeatCell": {
@ -1383,7 +1428,7 @@ class Pool(models.Model):
class Meta:
verbose_name = _("pool")
verbose_name_plural = _("pools")
ordering = ('round', 'letter',)
ordering = ('round', 'letter', 'room',)
class Passage(models.Model):

View File

@ -91,7 +91,7 @@ class PoolTable(tables.Table):
)
def render_letter(self, record):
return format_lazy(_("Pool {letter}{round}"), letter=record.get_letter_display(), round=record.round)
return format_lazy(_("Pool {code}"), code=record.short_name)
def render_teams(self, record):
return ", ".join(participation.team.trigram for participation in record.participations.all()) \

View File

@ -25,6 +25,11 @@
<dt class="col-sm-3">{% trans "Letter:" %}</dt>
<dd class="col-sm-9">{{ pool.get_letter_display }}</dd>
{% if pool.participations.count == 5 %}
<dt class="col-sm-3">{% trans "Room:" %}</dt>
<dd class="col-sm-9">{{ pool.get_room_display }}</dd>
{% endif %}
<dt class="col-sm-3">{% trans "Teams:" %}</dt>
<dd class="col-sm-9">
@ -82,22 +87,12 @@
<div class="btn-group">
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_scale_note_sheet' pk=pool.pk %}">
<i class="fas fa-download"></i>
{% trans "Download the scale sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %}
{% trans "Download the scale sheet" %}
</a>
{% if pool.passages.count == 5 %}
<a class="btn btn-info" href="{% url 'participation:pool_scale_note_sheet' pk=pool.pk %}?page=2">
{% trans "Room" %} 2
</a>
{% endif %}
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}">
<i class="fas fa-download"></i>
{% trans "Download the final notation sheet" %}{% if pool.passages.count == 5 %} — {% trans "Room" %} 1{% endif %}
{% trans "Download the final notation sheet" %}
</a>
{% if pool.passages.count == 5 %}
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_final_note_sheet' pk=pool.pk %}?page=2">
{% trans "Room" %} 2
</a>
{% endif %}
<a class="btn btn-sm btn-info" href="{% url 'participation:pool_notation_sheets' pool_id=pool.id %}">
<i class="fas fa-archive"></i>
{% trans "Download all notation sheets" %}

View File

@ -37,14 +37,14 @@
\Large {\bf \tfjmedition$^{e}$ Tournoi Fran\c cais des Jeunes Math\'ematiciennes et Math\'ematiciens \tfjm}\\
\vspace{3mm}
Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{{ page }} \;-- {% if pool.round == 1 %}{{ pool.tournament.date_start }}{% else %}{{ pool.tournament.date_end }}{% endif %}
Tour {{ pool.round }} \;-- Poule {{ pool.get_letter_display }}{% if pool.participations.count == 5 %} \;-- {{ pool.get_room_display }}{% endif %} \;-- {% if pool.round == 1 %}{{ pool.tournament.date_start }}{% else %}{{ pool.tournament.date_end }}{% endif %}
\vspace{15mm}
\begin{tabular}{|p{35mm}{% for passage in passages.all %}{% if passages.count == 3 %}|p{3cm}|p{3cm}{% else %}|p{2.5cm}|p{2.5cm}{% endif %}{% endfor %}|}\hline
\multirow{2}{35mm}{\LARGE R\^ole} {% for passage in passages.all %}& \multicolumn{2}{c|}{ \Large Probl\`eme {{ passage.solution_number }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
\begin{tabular}{|p{40mm}{% for passage in passages.all %}{% if passages.count == 3 %}|p{3cm}|p{3cm}{% else %}|p{2.5cm}|p{2.5cm}{% endif %}{% endfor %}|}\hline
\multirow{2}{40mm}{\LARGE R\^ole} {% for passage in passages.all %}& \multicolumn{2}{c|}{ \Large Probl\`eme {{ passage.solution_number }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
{% for passage in passages.all %}& \hspace{4mm} {\Large \'ECRIT} & \hspace{4mm} {\Large ORAL}{% endfor %} \\ \hline
\multirow{2}{35mm}{\LARGE D\'efenseur\textperiodcentered{}se} {% for passage in passages.all %}& \multicolumn{2}{c|}{\Large {{ passage.defender.team.trigram }}}{% endfor %} \\ \cline{2-{{ passages.count|add:passages.count|add:1 }}}
{% for passage in passages.all %}

View File

@ -1760,13 +1760,6 @@ class NotationSheetTemplateView(VolunteerMixin, DetailView):
context = super().get_context_data(**kwargs)
passages = self.object.passages.all()
if passages.count() == 5:
page = self.request.GET.get('page', '1')
if not page.isnumeric() or page not in ['1', '2']:
page = '1'
passages = passages.filter(id__in=([passages[0].id, passages[2].id, passages[4].id]
if page == '1' else [passages[1].id, passages[3].id]))
context['page'] = page
context['passages'] = passages
context['esp'] = passages.count() * '&'
@ -1841,44 +1834,36 @@ class NotationSheetsArchiveView(VolunteerMixin, DetailView):
for pool in pools:
prefix = f"{pool.short_name}/" if len(pools) > 1 else ""
for template_name in ['bareme', 'finale']:
pages = [1] if pool.participations.count() < 5 else [1, 2]
for page in pages:
juries = list(pool.juries.all()) + [None]
juries = list(pool.juries.all()) + [None]
for jury in juries:
if jury is not None and template_name == "bareme":
continue
for jury in juries:
if jury is not None and template_name == "bareme":
continue
context = {'jury': jury, 'page': page, 'pool': pool,
'tfjm_number': timezone.now().year - 2010}
context = {'jury': jury, 'pool': pool,
'tfjm_number': timezone.now().year - 2010}
passages = pool.passages.all()
if passages.count() == 5:
passages = passages.filter(
id__in=([passages[0].id, passages[2].id, passages[4].id]
if page == '1' else [passages[1].id, passages[3].id]))
passages = pool.passages.all()
context['passages'] = passages
context['esp'] = passages.count() * '&'
context['passages'] = passages
context['esp'] = passages.count() * '&'
tex = render_to_string(f"participation/tex/{template_name}.tex",
context=context, request=self.request)
temp_dir = mkdtemp()
with open(os.path.join(temp_dir, "texput.tex"), "w") as f:
f.write(tex)
tex = render_to_string(f"participation/tex/{template_name}.tex",
context=context, request=self.request)
temp_dir = mkdtemp()
with open(os.path.join(temp_dir, "texput.tex"), "w") as f:
f.write(tex)
process = subprocess.Popen(
["pdflatex", "-interaction=nonstopmode", f"-output-directory={temp_dir}",
os.path.join(temp_dir, "texput.tex"), ])
process.wait()
process = subprocess.Popen(
["pdflatex", "-interaction=nonstopmode", f"-output-directory={temp_dir}",
os.path.join(temp_dir, "texput.tex"), ])
process.wait()
sheet_name = f"Barème pour la poule {pool.short_name}" if template_name == "bareme" \
else (f"Feuille de notation pour la poule {pool.short_name}"
f" - {str(jury) if jury else 'Vierge'}")
sheet_name = f"Barème pour la poule {pool.short_name}" if template_name == "bareme" \
else (f"Feuille de notation pour la poule {pool.short_name}"
f" - {str(jury) if jury else 'Vierge'}")
sheet_name += " - page 2" if page == 2 else ""
zf.write(os.path.join(temp_dir, "texput.pdf"),
f"{prefix}{sheet_name}.pdf")
zf.write(os.path.join(temp_dir, "texput.pdf"),
f"{prefix}{sheet_name}.pdf")
response = HttpResponse(content_type="application/zip")
response["Content-Disposition"] = f"attachment; filename=\"{filename}\""