diff --git a/participation/forms.py b/participation/forms.py index 7c6d4c9..4dc32ae 100644 --- a/participation/forms.py +++ b/participation/forms.py @@ -276,7 +276,6 @@ class UploadNotesForm(forms.Form): def process(self, df: pandas.DataFrame, cleaned_data: dict): parsed_notes = {} - valid_lengths = [2 + 6 * 3, 2 + 7 * 4, 2 + 6 * 5] # Per pool sizes pool_size = 0 line_length = 0 for line in df.values.tolist(): @@ -286,10 +285,7 @@ class UploadNotesForm(forms.Form): line = [str(s).strip() for s in line if str(s)] if line and line[0] == 'Problème': pool_size = len(line) - 1 - if pool_size < 3 or pool_size > 5: - self.add_error('file', _("Can't determine the pool size. Are you sure your file is correct?")) - return - line_length = valid_lengths[pool_size - 3] + line_length = 2 + 6 * pool_size continue if pool_size == 0 or len(line) < line_length: @@ -299,11 +295,13 @@ class UploadNotesForm(forms.Form): if name.lower() in ["rôle", "juré⋅e", "juré?e", "moyenne", "coefficient", "sous-total", "équipe", "equipe"]: continue notes = line[2:line_length] + print(name, notes) if not all(s.isnumeric() or s[0] == '-' and s[1:].isnumeric() for s in notes): continue notes = list(map(lambda x: int(float(x)), notes)) + print(notes) - max_notes = pool_size * ([20, 20, 10, 10, 10, 10] + ([4] if pool_size == 4 else [])) + max_notes = pool_size * [20, 20, 10, 10, 10, 10] for n, max_n in zip(notes, max_notes): if n > max_n: self.add_error('file', @@ -317,6 +315,8 @@ class UploadNotesForm(forms.Form): jury = jury.get() parsed_notes[jury] = notes + print(parsed_notes) + cleaned_data['parsed_notes'] = parsed_notes return cleaned_data diff --git a/participation/models.py b/participation/models.py index 6b0cc7c..2f2d201 100644 --- a/participation/models.py +++ b/participation/models.py @@ -1080,7 +1080,7 @@ class Pool(models.Model): coeffs = sum(([1, 1.6 - 0.4 * passage.defender_penalties, 0.9, 2, 0.9, 1] for passage in passages), start=["Coefficient", ""]) subtotal = ["Sous-total", ""] - footer = [average, coeffs, subtotal, 32 * [""]] + footer = [average, coeffs, subtotal, 26 * [""]] min_row = 5 max_row = min_row + self.juries.count() diff --git a/participation/views.py b/participation/views.py index 615d5e1..9b70a7c 100644 --- a/participation/views.py +++ b/participation/views.py @@ -1477,7 +1477,6 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView): tc = TableCell(valuetype="string", stylename=title_style_topleftright) tc.addElement(P(text=f"Problème {passage.solution_number}")) tc.setAttribute('numbercolumnsspanned', "6") - tc.setAttribute("formula", f"of:=[.B{8 + self.object.juries.count() + passage.position}]") header_pb.addElement(tc) header_pb.addElement(CoveredTableCell(numbercolumnsrepeated=5)) @@ -1661,60 +1660,73 @@ class PoolNotesTemplateView(VolunteerMixin, DetailView): table.addElement(TableRow()) - # Compute the total scores in a new table - scores_header = TableRow() - table.addElement(scores_header) - team_tc = TableCell(valuetype="string", stylename=title_style_topbotleft) - team_tc.addElement(P(text="Équipe")) - team_tc.setAttribute('numbercolumnsspanned', "2") - scores_header.addElement(team_tc) - problem_tc = TableCell(valuetype="string", stylename=title_style_topbot) - problem_tc.addElement(P(text="Problème")) - scores_header.addElement(problem_tc) - total_tc = TableCell(valuetype="string", stylename=title_style_topbot) - total_tc.addElement(P(text="Total")) - scores_header.addElement(total_tc) - rank_tc = TableCell(valuetype="string", stylename=title_style_topbotright) - rank_tc.addElement(P(text="Rang")) - scores_header.addElement(rank_tc) - sorted_participations = sorted(self.object.participations.all(), key=lambda p: -self.object.average(p)) - for passage in self.object.passages.all(): - team_row = TableRow() - table.addElement(team_row) - - team_tc = TableCell(valuetype="string", - 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})")) + if self.object.participations.count() == 5: + # 5-teams pools are separated in two different objects. + # So, displaying the ranking may don't make any sens. We don't display it for this reason. + scores_row = TableRow() + table.addElement(scores_row) + score_tc = TableCell(valuetype="string") + score_tc.addElement(P(text="Le classement d'une poule à 5 n'est pas disponible sur le tableur, " + "puisque les notes de l'autre salle sont manquantes.\n" + "Merci de vous fier au site, ou bien au Google Sheets.")) + scores_row.addElement(score_tc) + else: + # Compute the total scores in a new table + scores_header = TableRow() + table.addElement(scores_header) + team_tc = TableCell(valuetype="string", stylename=title_style_topbotleft) + team_tc.addElement(P(text="Équipe")) team_tc.setAttribute('numbercolumnsspanned', "2") - team_row.addElement(team_tc) + scores_header.addElement(team_tc) + problem_tc = TableCell(valuetype="string", stylename=title_style_topbot) + problem_tc.addElement(P(text="Problème")) + scores_header.addElement(problem_tc) + total_tc = TableCell(valuetype="string", stylename=title_style_topbot) + total_tc.addElement(P(text="Total")) + scores_header.addElement(total_tc) + rank_tc = TableCell(valuetype="string", stylename=title_style_topbotright) + rank_tc.addElement(P(text="Rang")) + scores_header.addElement(rank_tc) - problem_tc = TableCell(valuetype="string", - stylename=style_bot if passage.position == pool_size else style) - problem_tc.addElement(P(text=f"Problème {passage.solution_number}")) - team_row.addElement(problem_tc) + sorted_participations = sorted(self.object.participations.all(), key=lambda p: -self.object.average(p)) + for passage in self.object.passages.all(): + team_row = TableRow() + table.addElement(team_row) - defender_pos = passage.position - 1 - opponent_pos = self.object.passages.get(opponent=passage.defender).position - 1 - reporter_pos = self.object.passages.get(reporter=passage.defender).position - 1 + team_tc = TableCell(valuetype="string", + 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.setAttribute('numbercolumnsspanned', "2") + team_row.addElement(team_tc) - score_tc = TableCell(valuetype="float", value=self.object.average(passage.defender), - stylename=style_bot if passage.position == pool_size else style) - score_tc.addElement(P(text=self.object.average(passage.defender))) - formula = "of:=" - 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 - score_tc.setAttribute("formula", formula) - team_row.addElement(score_tc) + problem_tc = TableCell(valuetype="string", + stylename=style_bot if passage.position == pool_size else style) + problem_tc.addElement(P(text=f"Problème {passage.solution_number}")) + problem_tc.setAttribute("formula", f"of:=[.B{3 + passage_width * (passage.position - 1)}]") + team_row.addElement(problem_tc) - score_col = 'C' - rank_tc = TableCell(valuetype="float", value=sorted_participations.index(passage.defender) + 1, - 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.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}])") - team_row.addElement(rank_tc) + defender_pos = passage.position - 1 + opponent_pos = self.object.passages.get(opponent=passage.defender).position - 1 + reporter_pos = self.object.passages.get(reporter=passage.defender).position - 1 + + score_tc = TableCell(valuetype="float", value=self.object.average(passage.defender), + stylename=style_bot if passage.position == pool_size else style) + score_tc.addElement(P(text=self.object.average(passage.defender))) + formula = "of:=" + 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 + score_tc.setAttribute("formula", formula) + team_row.addElement(score_tc) + + score_col = 'C' + rank_tc = TableCell(valuetype="float", value=sorted_participations.index(passage.defender) + 1, + 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.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}])") + team_row.addElement(rank_tc) table.addElement(TableRow())