Update ODS note sheets

Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
Emmy D'Anello 2024-03-24 20:05:07 +01:00
parent 3465da4c36
commit b6d54d27cd
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
3 changed files with 41 additions and 23 deletions

View File

@ -17,6 +17,7 @@ from django.db.models.functions import Concat
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from pypdf import PdfReader from pypdf import PdfReader
from registration.models import VolunteerRegistration
from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament from .models import Note, Participation, Passage, Pool, Solution, Synthesis, Team, Tournament
@ -291,7 +292,7 @@ class UploadNotesForm(forms.Form):
def process(self, csvfile: Iterable[str], cleaned_data: dict): def process(self, csvfile: Iterable[str], cleaned_data: dict):
parsed_notes = {} parsed_notes = {}
valid_lengths = [1 + 6 * 3, 1 + 7 * 4, 1 + 6 * 5] # Per pool sizes valid_lengths = [2 + 6 * 3, 2 + 7 * 4, 2 + 6 * 5] # Per pool sizes
pool_size = 0 pool_size = 0
line_length = 0 line_length = 0
for line in csvfile: for line in csvfile:
@ -310,29 +311,24 @@ class UploadNotesForm(forms.Form):
name = line[0] name = line[0]
if name.lower() in ["rôle", "juré", "moyenne", "coefficient", "sous-total", "équipe", "equipe"]: if name.lower() in ["rôle", "juré", "moyenne", "coefficient", "sous-total", "équipe", "equipe"]:
continue continue
notes = line[1:line_length] notes = line[2:line_length]
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(int, notes)) notes = list(map(int, notes))
max_notes = pool_size * ([20, 16, 9, 10, 9, 10] + ([4] if pool_size == 4 else [])) max_notes = pool_size * ([20, 20, 10, 10, 10, 10] + ([4] if pool_size == 4 else []))
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',
_("The following note is higher of the maximum expected value:") _("The following note is higher of the maximum expected value:")
+ str(n) + " > " + str(max_n)) + str(n) + " > " + str(max_n))
# Search by "{first_name} {last_name}" # Search by volunteer id
jury = User.objects.annotate(full_name=Concat('first_name', Value(' '), 'last_name', jury = VolunteerRegistration.objects.filter(pk=line[1])
output_field=CharField())) \
.filter(full_name=name.replace('', '\''), registration__volunteerregistration__isnull=False)
if jury.count() != 1: if jury.count() != 1:
self.add_error('file', _("The following user was not found:") + " " + name) raise ValidationError({'file': _("The following user was not found:") + " " + name})
continue
jury = jury.get() jury = jury.get()
parsed_notes[jury] = notes
vr = jury.registration
parsed_notes[vr] = notes
cleaned_data['parsed_notes'] = parsed_notes cleaned_data['parsed_notes'] = parsed_notes

View File

@ -680,7 +680,7 @@ class Passage(models.Model):
@property @property
def average_defender(self) -> float: def average_defender(self) -> float:
return self.average_defender_writing + (2 - 0.5 * self.defender_penalties) * self.average_defender_oral return self.average_defender_writing + (1.6 - 0.4 * self.defender_penalties) * self.average_defender_oral
@property @property
def average_opponent_writing(self) -> float: def average_opponent_writing(self) -> float:
@ -692,7 +692,7 @@ class Passage(models.Model):
@property @property
def average_opponent(self) -> float: def average_opponent(self) -> float:
return self.average_opponent_writing + 2 * self.average_opponent_oral return 0.9 * self.average_opponent_writing + 2 * self.average_opponent_oral
@property @property
def average_reporter_writing(self) -> float: def average_reporter_writing(self) -> float:
@ -704,7 +704,7 @@ class Passage(models.Model):
@property @property
def average_reporter(self) -> float: def average_reporter(self) -> float:
return self.average_reporter_writing + self.average_reporter_oral return 0.9 * self.average_reporter_writing + self.average_reporter_oral
@property @property
def average_observer(self) -> float: def average_observer(self) -> float:

View File

@ -1176,6 +1176,10 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
first_col_style.addElement(TableColumnProperties(columnwidth="9cm", breakbefore="auto")) first_col_style.addElement(TableColumnProperties(columnwidth="9cm", breakbefore="auto"))
doc.automaticstyles.addElement(first_col_style) doc.automaticstyles.addElement(first_col_style)
jury_id_style = Style(name="co_jury_id", family="table-column")
jury_id_style.addElement(TableColumnProperties(columnwidth="1cm", breakbefore="auto"))
doc.automaticstyles.addElement(jury_id_style)
col_style = Style(name="co2", family="table-column") col_style = Style(name="co2", family="table-column")
col_style.addElement(TableColumnProperties(columnwidth="2.6cm", breakbefore="auto")) col_style.addElement(TableColumnProperties(columnwidth="2.6cm", breakbefore="auto"))
doc.automaticstyles.addElement(col_style) doc.automaticstyles.addElement(col_style)
@ -1188,6 +1192,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
doc.spreadsheet.addElement(table) doc.spreadsheet.addElement(table)
table.addElement(TableColumn(stylename=first_col_style)) table.addElement(TableColumn(stylename=first_col_style))
table.addElement(TableColumn(stylename=jury_id_style))
for i in range(line_length): for i in range(line_length):
table.addElement(TableColumn(stylename=obs_col_style if pool_size == 4 table.addElement(TableColumn(stylename=obs_col_style if pool_size == 4
@ -1198,7 +1203,9 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
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="Problème"))
problems_tc.setAttribute('numbercolumnsspanned', "2")
header_pb.addElement(problems_tc) header_pb.addElement(problems_tc)
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=f"Problème {passage.solution_number}"))
@ -1212,7 +1219,9 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
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="Rôle"))
role_tc.setAttribute('numbercolumnsspanned', "2")
header_role.addElement(role_tc) header_role.addElement(role_tc)
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="Défenseur⋅se"))
@ -1243,7 +1252,9 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
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="Juré⋅e", stylename=title_style_botleft)
jury_tc.addElement(P(text="Juré⋅e")) jury_tc.addElement(P(text="Juré⋅e"))
jury_tc.setAttribute('numbercolumnsspanned', "2")
header_notes.addElement(jury_tc) header_notes.addElement(jury_tc)
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)
@ -1251,11 +1262,11 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
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 (/16)")) defender_o_tc.addElement(P(text="Oral (/20)"))
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 (/9)")) opponent_w_tc.addElement(P(text="Écrit (/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)
@ -1263,7 +1274,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
header_notes.addElement(opponent_o_tc) header_notes.addElement(opponent_o_tc)
reporter_w_tc = TableCell(valuetype="string", stylename=title_style_bot) reporter_w_tc = TableCell(valuetype="string", stylename=title_style_bot)
reporter_w_tc.addElement(P(text="Écrit (/9)")) reporter_w_tc.addElement(P(text="Écrit (/10)"))
header_notes.addElement(reporter_w_tc) header_notes.addElement(reporter_w_tc)
reporter_o_tc = TableCell(valuetype="string", reporter_o_tc = TableCell(valuetype="string",
@ -1285,6 +1296,9 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
name_tc = TableCell(valuetype="string", stylename=style_leftright) name_tc = TableCell(valuetype="string", stylename=style_leftright)
name_tc.addElement(P(text=f"{jury.user.first_name} {jury.user.last_name}")) name_tc.addElement(P(text=f"{jury.user.first_name} {jury.user.last_name}"))
jury_row.addElement(name_tc) jury_row.addElement(name_tc)
jury_id_tc = TableCell(valuetype="float", value=jury.pk, stylename=style_leftright)
jury_id_tc.addElement(P(text=str(jury.pk)))
jury_row.addElement(jury_id_tc)
for passage in self.object.passages.all(): for passage in self.object.passages.all():
notes = Note.objects.get(jury=jury, passage=passage) notes = Note.objects.get(jury=jury, passage=passage)
@ -1297,14 +1311,16 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
jury_size = self.object.juries.count() jury_size = self.object.juries.count()
min_row = 4 min_row = 4
max_row = 4 + jury_size - 1 max_row = 4 + jury_size - 1
min_column = 2 min_column = 3
# Add line for averages # Add line for averages
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="Moyenne"))
average_tc.setAttribute('numbercolumnsspanned', "2")
average_row.addElement(average_tc) average_row.addElement(average_tc)
average_row.addElement(CoveredTableCell())
for i, passage in enumerate(self.object.passages.all()): for i, passage in enumerate(self.object.passages.all()):
for j, note in enumerate(passage.averages): for j, note in enumerate(passage.averages):
tc = TableCell(valuetype="float", value=note, tc = TableCell(valuetype="float", value=note,
@ -1321,17 +1337,19 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
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_row.addElement(coeff_tc) coeff_row.addElement(coeff_tc)
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=1, stylename=style_left)
defender_w_tc.addElement(P(text="1")) defender_w_tc.addElement(P(text="1"))
coeff_row.addElement(defender_w_tc) coeff_row.addElement(defender_w_tc)
defender_o_tc = TableCell(valuetype="float", value=2 - 0.5 * passage.defender_penalties, stylename=style) defender_o_tc = TableCell(valuetype="float", value=1.6 - 0.4 * passage.defender_penalties, stylename=style)
defender_o_tc.addElement(P(text=str(2 - 0.5 * passage.defender_penalties))) defender_o_tc.addElement(P(text=str(2 - 0.4 * passage.defender_penalties)))
coeff_row.addElement(defender_o_tc) coeff_row.addElement(defender_o_tc)
opponent_w_tc = TableCell(valuetype="float", value=1, stylename=style) opponent_w_tc = TableCell(valuetype="float", value=0.9, stylename=style)
opponent_w_tc.addElement(P(text="1")) opponent_w_tc.addElement(P(text="1"))
coeff_row.addElement(opponent_w_tc) coeff_row.addElement(opponent_w_tc)
@ -1339,7 +1357,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
opponent_o_tc.addElement(P(text="2")) opponent_o_tc.addElement(P(text="2"))
coeff_row.addElement(opponent_o_tc) coeff_row.addElement(opponent_o_tc)
reporter_w_tc = TableCell(valuetype="float", value=1, stylename=style) reporter_w_tc = TableCell(valuetype="float", value=0.9, stylename=style)
reporter_w_tc.addElement(P(text="1")) reporter_w_tc.addElement(P(text="1"))
coeff_row.addElement(reporter_w_tc) coeff_row.addElement(reporter_w_tc)
@ -1358,7 +1376,9 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
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="Sous-total"))
subtotal_tc.setAttribute('numbercolumnsspanned', "2")
subtotal_row.addElement(subtotal_tc) subtotal_row.addElement(subtotal_tc)
subtotal_row.addElement(CoveredTableCell())
for i, passage in enumerate(self.object.passages.all()): for i, passage in enumerate(self.object.passages.all()):
def_w_col = getcol(min_column + passage_width * i) def_w_col = getcol(min_column + passage_width * i)
def_o_col = getcol(min_column + passage_width * i + 1) def_o_col = getcol(min_column + passage_width * i + 1)
@ -1406,6 +1426,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
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="Équipe"))
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="Problème"))
@ -1452,6 +1473,7 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView):
team_tc = TableCell(valuetype="string", team_tc = TableCell(valuetype="string",
stylename=style_botleft if passage.position == pool_size else style_left) stylename=style_botleft if passage.position == pool_size else style_left)
team_tc.addElement(P(text=f"{passage.defender.team.name} ({passage.defender.team.trigram})")) team_tc.addElement(P(text=f"{passage.defender.team.name} ({passage.defender.team.trigram})"))
team_tc.setAttribute('numbercolumnsspanned', "2")
team_row.addElement(team_tc) team_row.addElement(team_tc)
problem_tc = TableCell(valuetype="string", problem_tc = TableCell(valuetype="string",