diff --git a/app/comp/res_common.py b/app/comp/res_common.py index f1020b48..fbeba8be 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -426,47 +426,53 @@ class ResultatsSemestre(ResultatsCache): NO_NOTE = "-" # contenu des cellules sans notes rows = [] # column_id : title - titles = { - "rang": "Rg", - # ordre des colonnes de gauche à droite: - "_civilite_str_col_order": 2, - "_nom_disp_col_order": 3, - "_prenom_col_order": 4, - "_nom_short_col_order": 5, - "_rang_col_order": 6, - # les colonnes des groupes sont à la position 10 - "_ues_validables_col_order": 20, - } + titles = {} # les titres en footer: les mêmes, mais avec des bulles et liens: titles_bot = {} def add_cell( - row: dict, col_id: str, title: str, content: str, classes: str = "" + row: dict, + col_id: str, + title: str, + content: str, + classes: str = "", + idx: int = 100, ): "Add a row to our table. classes is a list of css class names" row[col_id] = content if classes: - row[f"_{col_id}_class"] = classes + row[f"_{col_id}_class"] = classes + f" c{idx}" if not col_id in titles: titles[col_id] = title + titles[f"_{col_id}_col_order"] = idx if classes: titles[f"_{col_id}_class"] = classes + return idx + 1 etuds_inscriptions = self.formsemestre.etuds_inscriptions ues = self.formsemestre.query_ues(with_sport=True) # avec bonus ues_sans_bonus = [ue for ue in ues if ue.type != UE_SPORT] modimpl_ids = set() # modimpl effectivement présents dans la table for etudid in etuds_inscriptions: + idx = 0 # index de la colonne etud = Identite.query.get(etudid) row = {"etudid": etudid} # --- Rang - add_cell(row, "rang", "Rg", self.etud_moy_gen_ranks[etudid], "rang") + idx = add_cell( + row, "rang", "Rg", self.etud_moy_gen_ranks[etudid], "rang", idx + ) row["_rang_order"] = f"{self.etud_moy_gen_ranks_int[etudid]:05d}" # --- Identité étudiant - add_cell(row, "civilite_str", "Civ.", etud.civilite_str, "identite_detail") - add_cell(row, "nom_disp", "Nom", etud.nom_disp(), "identite_detail") - add_cell(row, "prenom", "Prénom", etud.prenom, "identite_detail") - add_cell(row, "nom_short", "Nom", etud.nom_short, "identite_court") + idx = add_cell( + row, "civilite_str", "Civ.", etud.civilite_str, "identite_detail", idx + ) + idx = add_cell( + row, "nom_disp", "Nom", etud.nom_disp(), "identite_detail", idx + ) + idx = add_cell(row, "prenom", "Prénom", etud.prenom, "identite_detail", idx) + idx = add_cell( + row, "nom_short", "Nom", etud.nom_short, "identite_court", idx + ) row["_nom_short_target"] = url_for( "notes.formsemestre_bulletinetud", scodoc_dept=g.scodoc_dept, @@ -476,6 +482,8 @@ class ResultatsSemestre(ResultatsCache): row["_nom_short_target_attrs"] = f'class="etudinfo" id="{etudid}"' row["_nom_disp_target"] = row["_nom_short_target"] row["_nom_disp_target_attrs"] = row["_nom_short_target_attrs"] + + idx = 30 # début des colonnes de notes # --- Moyenne générale moy_gen = self.etud_moy_gen.get(etudid, False) note_class = "" @@ -483,12 +491,13 @@ class ResultatsSemestre(ResultatsCache): moy_gen = NO_NOTE elif isinstance(moy_gen, float) and moy_gen < barre_moy: note_class = " moy_ue_warning" # en rouge - add_cell( + idx = add_cell( row, "moy_gen", "Moy", fmt_note(moy_gen), "col_moy_gen" + note_class, + idx, ) titles_bot["_moy_gen_target_attrs"] = ( 'title="moyenne indicative"' if self.is_apc else "" @@ -510,16 +519,32 @@ class ResultatsSemestre(ResultatsCache): if val < barre_warning_ue: note_class = " moy_ue_warning" # notes très basses nb_ues_warning += 1 - add_cell( + idx = add_cell( row, col_id, ue.acronyme, fmt_note(val), "col_ue" + note_class, + idx, ) titles_bot[ f"_{col_id}_target_attrs" ] = f"""title="{ue.titre} S{ue.semestre_idx or '?'}" """ + # Bonus (sport) dans cette UE ? + # Le bonus sport appliqué sur cette UE + if (self.bonus_ues is not None) and (ue.id in self.bonus_ues): + val = self.bonus_ues[ue.id][etud.id] or "" + val_fmt = fmt_note(val) + if val: + val_fmt = f'{val_fmt}' + idx = add_cell( + row, + f"bonus_ue_{ue.id}", + f"Bonus {ue.acronyme}", + val_fmt, + "col_ue_bonus", + idx, + ) # Les moyennes des modules (ou ressources et SAÉs) dans cette UE for modimpl in self.modimpls_in_ue(ue.id, etudid, with_bonus=False): if ue_status["is_capitalized"]: @@ -546,13 +571,19 @@ class ResultatsSemestre(ResultatsCache): col_id = ( f"moy_{modimpl.module.type_abbrv()}_{modimpl.id}_{ue.id}" ) - add_cell( + val_fmt = fmt_note(val) + if modimpl.module.module_type == scu.ModuleType.MALUS: + val_fmt = ( + (scu.EMO_RED_TRIANGLE_DOWN + val_fmt) if val else "" + ) + idx = add_cell( row, col_id, modimpl.module.code, - fmt_note(val), + val_fmt, # class col_res mod_ue_123 f"col_{modimpl.module.type_abbrv()} mod_ue_{ue.id}", + idx, ) titles_bot[f"_{col_id}_target"] = url_for( "notes.moduleimpl_status", @@ -571,9 +602,10 @@ class ResultatsSemestre(ResultatsCache): add_cell( row, "ues_validables", - "Nb UE", + "UEs", ue_valid_txt, "col_ue col_ues_validables", + 29, # juste avant moy. gen. ) if nb_ues_warning: row["_ues_validables_class"] += " moy_ue_warning" @@ -581,6 +613,7 @@ class ResultatsSemestre(ResultatsCache): row["_ues_validables_class"] += " moy_inf" row["_ues_validables_order"] = nb_ues_validables # pour tri rows.append(row) + self._recap_add_partitions(rows, titles) self._recap_add_admissions(rows, titles) # tri par rang croissant @@ -589,6 +622,16 @@ class ResultatsSemestre(ResultatsCache): # INFOS POUR FOOTER bottom_infos = self._recap_bottom_infos(ues_sans_bonus, modimpl_ids, fmt_note) + # Ajoute style "col_empty" aux colonnes de modules vides + for col_id in titles: + c_class = f"_{col_id}_class" + if "col_empty" in bottom_infos["moy"].get(c_class, ""): + for row in rows: + row[c_class] += " col_empty" + titles[c_class] += " col_empty" + for row in bottom_infos.values(): + row[c_class] = row.get(c_class, "") + " col_empty" + # --- TABLE FOOTER: ECTS, moyennes, min, max... footer_rows = [] for (bottom_line, row) in bottom_infos.items(): @@ -604,7 +647,9 @@ class ResultatsSemestre(ResultatsCache): titles_bot.update(titles) footer_rows.append(titles_bot) column_ids = [title for title in titles if not title.startswith("_")] - column_ids.sort(key=lambda col_id: titles.get("_" + col_id + "_col_order", 100)) + column_ids.sort( + key=lambda col_id: titles.get("_" + col_id + "_col_order", 1000) + ) return (rows, footer_rows, titles, column_ids) def _recap_bottom_infos(self, ues, modimpl_ids: set, fmt_note) -> dict: @@ -651,7 +696,11 @@ class ResultatsSemestre(ResultatsCache): notes = self.modimpl_notes(modimpl.id, ue.id) row_min[col_id] = fmt_note(np.nanmin(notes)) row_max[col_id] = fmt_note(np.nanmax(notes)) - row_moy[col_id] = fmt_note(np.nanmean(notes)) + moy = np.nanmean(notes) + row_moy[col_id] = fmt_note(moy) + if np.isnan(moy): + # aucune note dans ce module + row_moy[f"_{col_id}_class"] = "col_empty" return { # { key : row } avec key = min, max, moy, coef "min": row_min, @@ -696,6 +745,14 @@ class ResultatsSemestre(ResultatsCache): "type_admission": "Type Adm.", "classement": "Rg. Adm.", } + first = True + for i, cid in enumerate(fields): + titles[f"_{cid}_col_order"] = 10000 + i # tout à droite + if first: + titles[f"_{cid}_class"] = "admission admission_first" + first = False + else: + titles[f"_{cid}_class"] = "admission" titles.update(fields) for row in rows: etud = Identite.query.get(row["etudid"]) @@ -708,8 +765,6 @@ class ResultatsSemestre(ResultatsCache): first = False else: row[f"_{cid}_class"] = "admission" - titles[f"_{cid}_class"] = row[f"_{cid}_class"] - titles[f"_{cid}_col_order"] = 1000 # à la fin def _recap_add_partitions(self, rows: list[dict], titles: dict): """Ajoute les colonnes indiquant les groupes diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index 117ce567..a00e7df3 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -643,7 +643,7 @@ def make_formsemestre_recapcomplet( "recap_row_nbeval", "recap_row_ects", )[ir - nblines + 6] - cells = '