diff --git a/app/but/jury_but.py b/app/but/jury_but.py index 8db372b1..391f77ed 100644 --- a/app/but/jury_but.py +++ b/app/but/jury_but.py @@ -246,6 +246,8 @@ class DecisionsProposeesAnnee(DecisionsProposees): "liste des niveaux de compétences associés à cette année" self.decisions_rcue_by_niveau = self.compute_decisions_niveaux() "les décisions rcue associées aux niveau_id" + self.dec_rcue_by_ue = self._dec_rcue_by_ue() + "{ ue_id : DecisionsProposeesRCUE }" self.nb_competences = len(self.niveaux_competences) "le nombre de niveaux de compétences à valider cette année" self.nb_validables = len( @@ -357,6 +359,7 @@ class DecisionsProposeesAnnee(DecisionsProposees): if res.etuds_parcour_id[etudid] is None: # pas de parcour: prend toutes les UEs (non bonus) ues = [ue for ue in res.etud_ues(etudid) if ue.type == UE_STANDARD] + ues.sort(key=lambda u: u.numero) else: parcour = ApcParcours.query.get(res.etuds_parcour_id[etudid]) if parcour is not None: @@ -364,6 +367,7 @@ class DecisionsProposeesAnnee(DecisionsProposees): ues = ( formation.query_ues_parcour(parcour) .filter_by(semestre_idx=formsemestre.semestre_id) + .order_by(UniteEns.numero) .all() ) ues_sems.append(ues) @@ -418,9 +422,10 @@ class DecisionsProposeesAnnee(DecisionsProposees): return rcues_annee def compute_decisions_niveaux(self) -> dict[int, "DecisionsProposeesRCUE"]: - """Pour chaque niveau de compétence de cette année, donne le DecisionsProposeesRCUE - ou None s'il n'y en a pas (ne devrait pas arriver car - compute_rcues_annee vérifie déjà cela). + """Pour chaque niveau de compétence de cette année, construit + le DecisionsProposeesRCUE, + ou None s'il n'y en a pas + (ne devrait pas arriver car compute_rcues_annee vérifie déjà cela). Return: { niveau_id : DecisionsProposeesRCUE } """ # Retrouve le RCUE associé à chaque niveau @@ -442,6 +447,15 @@ class DecisionsProposeesAnnee(DecisionsProposees): decisions_rcue_by_niveau = {x[1]: x[0] for x in rc_niveaux} return decisions_rcue_by_niveau + def _dec_rcue_by_ue(self) -> dict[int, "DecisionsProposeesRCUE"]: + """construit dict { ue_id : DecisionsProposeesRCUE } + à partir de self.decisions_rcue_by_niveau""" + d = {} + for dec_rcue in self.decisions_rcue_by_niveau.values(): + d[dec_rcue.rcue.ue_1.id] = dec_rcue + d[dec_rcue.rcue.ue_2.id] = dec_rcue + return d + # def lookup_ue(self, ue_id: int) -> UniteEns: # "check that ue_id belongs to our UE, if not returns None" # ues = [ue for ue in self.ues_impair + self.ues_pair if ue.id == ue_id] diff --git a/app/but/jury_but_recap.py b/app/but/jury_but_recap.py index 47f82608..b9ed57a3 100644 --- a/app/but/jury_but_recap.py +++ b/app/but/jury_but_recap.py @@ -11,7 +11,11 @@ import time from flask import g, url_for from app.but import jury_but -from app.but.jury_but import DecisionsProposeesAnnee +from app.but.jury_but import ( + DecisionsProposeesAnnee, + DecisionsProposeesRCUE, + DecisionsProposeesUE, +) from app.comp.res_but import ResultatsSemestreBUT from app.comp import res_sem from app.models.but_validations import RegroupementCoherentUE @@ -179,10 +183,11 @@ class RowCollector: self["_nom_disp_target_attrs"] = self["_nom_short_target_attrs"] self.last_etud_cell_idx = self.idx - def add_ue_cell(self, ue: UniteEns, val): + def add_ue_cells(self, dec_ue: DecisionsProposeesUE): "cell de moyenne d'UE" - col_id = f"moy_ue_{ue.id}" + col_id = f"moy_ue_{dec_ue.ue.id}" note_class = "" + val = dec_ue.moy_ue if isinstance(val, float): if val < BUT_BARRE_UE: note_class = " moy_inf" @@ -190,10 +195,19 @@ class RowCollector: note_class = " moy_ue_valid" if val < BUT_BARRE_UE8: note_class = " moy_ue_warning" # notes très basses - self.add_cell(col_id, ue.acronyme, self.fmt_note(val), "col_ue" + note_class) + self.add_cell( + col_id, dec_ue.ue.acronyme, self.fmt_note(val), "col_ue" + note_class + ) + self.add_cell( + col_id + "_code", + dec_ue.ue.acronyme, + dec_ue.code_valide or "", + "col_ue_code recorded_code", + ) - def add_rcue_cell(self, rcue: RegroupementCoherentUE): - "cell de moyenne d'UE" + def add_rcue_cells(self, dec_rcue: DecisionsProposeesRCUE): + "2 cells: moyenne du RCUE, code enregistré" + rcue = dec_rcue.rcue col_id = f"moy_rcue_{rcue.ue_1.niveau_competence_id}" # le niveau_id note_class = "" val = rcue.moy_rcue @@ -210,6 +224,12 @@ class RowCollector: self.fmt_note(val), "col_rcue" + note_class, ) + self.add_cell( + col_id + "_code", + f"
{rcue.ue_1.acronyme}
{rcue.ue_2.acronyme}
", + dec_rcue.code_valide or "", + "col_rcue_code recorded_code", + ) def add_nb_rcues_cell(self, deca: DecisionsProposeesAnnee): "cell avec nb niveaux validables / total" @@ -259,9 +279,10 @@ def get_table_jury_but( row.add_nb_rcues_cell(deca) # --- Les RCUEs for rcue in deca.rcues_annee: - row.add_ue_cell(rcue.ue_1, rcue.moy_ue_1) - row.add_ue_cell(rcue.ue_2, rcue.moy_ue_2) - row.add_rcue_cell(rcue) + dec_rcue = deca.dec_rcue_by_ue[rcue.ue_1.id] + row.add_ue_cells(deca.decisions_ues[rcue.ue_1.id]) + row.add_ue_cells(deca.decisions_ues[rcue.ue_2.id]) + row.add_rcue_cells(dec_rcue) # --- Le code annuel existant row.add_cell( "code_annee", diff --git a/app/scodoc/sco_codes_parcours.py b/app/scodoc/sco_codes_parcours.py index cfc44015..d4479939 100644 --- a/app/scodoc/sco_codes_parcours.py +++ b/app/scodoc/sco_codes_parcours.py @@ -188,7 +188,7 @@ CODES_SEM_ATTENTES = {ATT: True, ATB: True, ATJ: True} # semestre en attente CODES_SEM_REO = {NAR: 1} # reorientation -CODES_UE_VALIDES = {ADM: True, CMP: True} # UE validée +CODES_UE_VALIDES = {ADM: True, CMP: True, ADJ: True} # UE validée # Pour le BUT: CODES_ANNEE_ARRET = {DEF, DEM, ABAN, ABL} diff --git a/app/static/js/table_recap.js b/app/static/js/table_recap.js index 0c87ecda..18829d8e 100644 --- a/app/static/js/table_recap.js +++ b/app/static/js/table_recap.js @@ -35,6 +35,18 @@ $(function () { dt.buttons('toggle_partitions_rangs:name').text(rangs_visible ? "Rangs groupes" : "Cacher rangs groupes"); } }); + } else { + // table jury BUT: avec ou sans codes enregistrés + buttons.push( + { + name: "toggle_recorded_code", + text: "Code jury enregistrés", + action: function (e, dt, node, config) { + let visible = dt.columns(".recorded_code").visible()[0]; + dt.columns(".recorded_code").visible(!visible); + dt.buttons('toggle_recorded_code:name').text(visible ? "Code jury enregistrés" : "Cacher codes jury"); + } + }); } if (!$('table.table_recap').hasClass("jury")) { @@ -113,7 +125,7 @@ $(function () { "columnDefs": [ { // cache les codes, le détail de l'identité, les groupes, les colonnes admission et les vides - targets: ["codes", "identite_detail", "partition_aux", "partition_rangs", "admission", "col_empty"], + targets: ["codes", "identite_detail", "partition_aux", "partition_rangs", "admission", "col_empty", "recorded_code"], visible: false, }, {