diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py index dcbcd417..37902137 100644 --- a/app/but/bulletin_but.py +++ b/app/but/bulletin_but.py @@ -321,8 +321,8 @@ class BulletinBUT: } decisions_ues = self.res.get_etud_decision_ues(etud.id) or {} if self.prefs["bul_show_ects"]: - ects_tot = sum([ue.ects or 0 for ue in res.ues]) if res.ues else 0.0 - ects_acquis = sum([d.get("ects", 0) for d in decisions_ues.values()]) + ects_tot = res.etud_ects_tot_sem(etud.id) + ects_acquis = res.get_etud_ects_valides(etud.id, decisions_ues) semestre_infos["ECTS"] = {"acquis": ects_acquis, "total": ects_tot} if sco_preferences.get_preference("bul_show_decision", formsemestre.id): semestre_infos.update( diff --git a/app/but/jury_but_recap.py b/app/but/jury_but_recap.py index 427c2d0f..ada5280b 100644 --- a/app/but/jury_but_recap.py +++ b/app/but/jury_but_recap.py @@ -395,6 +395,18 @@ def get_table_jury_but( 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) + # --- Les ECTS validés + ects_valides = 0.0 + if deca.res_impair: + ects_valides += deca.res_impair.get_etud_ects_valides(etudid) + if deca.res_pair: + ects_valides += deca.res_pair.get_etud_ects_valides(etudid) + row.add_cell( + "ects_annee", + "ECTS", + f"""{int(ects_valides)}""", + "col_code_annee", + ) # --- Le code annuel existant row.add_cell( "code_annee", diff --git a/app/comp/jury.py b/app/comp/jury.py index d9be05b6..ef6bda11 100644 --- a/app/comp/jury.py +++ b/app/comp/jury.py @@ -55,7 +55,9 @@ class ValidationsSemestre(ResultatsCache): """Cherche les decisions du jury pour le semestre (pas les UE). Calcule les attributs: decisions_jury = { etudid : { 'code' : None|ATT|..., 'assidu' : 0|1 }} - decision_jury_ues={ etudid : { ue_id : { 'code' : Note|ADM|CMP, 'event_date' }}} + decision_jury_ues={ etudid : + { ue_id : { 'code' : Note|ADM|CMP, 'event_date' : "d/m/y", 'ects' : x }} + } Si la décision n'a pas été prise, la clé etudid n'est pas présente. Si l'étudiant est défaillant, pas de décisions d'UE. """ diff --git a/app/comp/res_but.py b/app/comp/res_but.py index 0b58521a..f1292df5 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -6,7 +6,6 @@ """Résultats semestres BUT """ -from collections.abc import Generator from re import U import time import numpy as np @@ -235,7 +234,3 @@ class ResultatsSemestreBUT(NotesTableCompat): """ s = self.ues_inscr_parcours_df.loc[etudid] return s.index[s.notna()] - - def etud_ues(self, etudid: int) -> Generator[UniteEns]: - """Liste des UE auxquelles l'étudiant est inscrit.""" - return (UniteEns.query.get(ue_id) for ue_id in self.etud_ues_ids(etudid)) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 15c1d7cd..f548be66 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -8,6 +8,7 @@ """ from collections import Counter +from collections.abc import Generator from functools import cached_property import numpy as np import pandas as pd @@ -120,6 +121,15 @@ class ResultatsSemestre(ResultatsCache): # car tous les étudiants sont inscrits à toutes les UE return [ue.id for ue in self.ues if ue.type != UE_SPORT] + def etud_ues(self, etudid: int) -> Generator[UniteEns]: + """Liste des UE auxquelles l'étudiant est inscrit.""" + return (UniteEns.query.get(ue_id) for ue_id in self.etud_ues_ids(etudid)) + + def etud_ects_tot_sem(self, etudid: int) -> float: + """Le total des ECTS associées à ce semestre (que l'étudiant peut ou non valider)""" + etud_ues = self.etud_ues(etudid) + return sum([ue.ects or 0 for ue in etud_ues]) if etud_ues else 0.0 + def modimpl_notes(self, modimpl_id: int, ue_id: int) -> np.ndarray: """Les notes moyennes des étudiants du sem. à ce modimpl dans cette ue. Utile pour stats bottom tableau recap. diff --git a/app/comp/res_compat.py b/app/comp/res_compat.py index d48c727d..94493928 100644 --- a/app/comp/res_compat.py +++ b/app/comp/res_compat.py @@ -278,7 +278,7 @@ class NotesTableCompat(ResultatsSemestre): def get_etud_decision_ues(self, etudid: int) -> dict: """Decisions du jury pour les UE de cet etudiant, ou None s'il n'y en pas eu. Ne tient pas compte des UE capitalisées. - { ue_id : { 'code' : ADM|CMP|AJ, 'event_date' : } + { ue_id : { 'code' : ADM|CMP|AJ, 'event_date' : "d/m/y", 'ects' : x } Ne renvoie aucune decision d'UE pour les défaillants """ if self.get_etud_etat(etudid) == DEF: @@ -290,6 +290,17 @@ class NotesTableCompat(ResultatsSemestre): ) return self.validations.decisions_jury_ues.get(etudid, None) + def get_etud_ects_valides(self, etudid: int, decisions_ues: dict = False) -> 0: + """Le total des ECTS validés (et enregistrés) par l'étudiant dans ce semestre. + NB: avant jury, rien d'enregistré, donc zéro ECTS. + Optimisation: si decisions_ues est passé, l'utilise, sinon appelle get_etud_decision_ues() + """ + if decisions_ues is False: + decisions_ues = self.get_etud_decision_ues(etudid) + if not decisions_ues: + return 0.0 + return sum([d.get("ects", 0.0) for d in decisions_ues.values()]) + def get_etud_decision_sem(self, etudid: int) -> dict: """Decision du jury prise pour cet etudiant, ou None s'il n'y en pas eu. { 'code' : None|ATT|..., 'assidu' : 0|1, 'event_date' : , compense_formsemestre_id } diff --git a/sco_version.py b/sco_version.py index 3b33418f..ac839f92 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.3.21" +SCOVERSION = "9.3.22" SCONAME = "ScoDoc"