From 02989e6c88158b10ac699c17460065d418ae08c6 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sun, 16 Jan 2022 23:47:52 +0100 Subject: [PATCH] WIP: reorganisation des calculs --- app/but/bulletin_but.py | 5 ++- app/but/bulletin_but_xml_compat.py | 7 ++-- app/comp/inscr_mod.py | 4 +- app/comp/moy_mod.py | 16 ++++---- app/comp/moy_sem.py | 15 +++++--- app/comp/moy_ue.py | 37 ++++++++++++------ app/comp/res_but.py | 5 +++ app/comp/res_classic.py | 7 +++- app/comp/res_common.py | 60 +++++++++++++++++++++--------- app/models/formsemestre.py | 24 ++++++++---- app/scodoc/bonus_sport.py | 2 +- app/scodoc/notes_table.py | 3 +- app/scodoc/sco_bulletins.py | 33 +++++++++++++--- app/scodoc/sco_groups.py | 9 +++-- app/scodoc/sco_liste_notes.py | 2 +- app/scodoc/sco_placement.py | 2 +- app/scodoc/sco_recapcomplet.py | 17 ++++----- app/scodoc/sco_saisie_notes.py | 8 ++-- 18 files changed, 169 insertions(+), 87 deletions(-) diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py index 3cba7fc5..2c6288bb 100644 --- a/app/but/bulletin_but.py +++ b/app/but/bulletin_but.py @@ -147,6 +147,7 @@ class BulletinBUT(ResultatsSemestreBUT): def bulletin_etud(self, etud, formsemestre) -> dict: """Le bulletin de l'étudiant dans ce semestre""" etat_inscription = etud.etat_inscription(formsemestre.id) + nb_inscrits = self.get_inscriptions_counts()[scu.INSCRIT] d = { "version": "0", "type": "BUT", @@ -189,7 +190,7 @@ class BulletinBUT(ResultatsSemestreBUT): }, "rang": { # classement wrt moyenne général, indicatif "value": self.etud_moy_gen_ranks[etud.id], - "total": len(self.etuds), + "total": nb_inscrits, }, }, ) @@ -212,7 +213,7 @@ class BulletinBUT(ResultatsSemestreBUT): "moy": "", "max": "", }, - "rang": {"value": "DEM", "total": len(self.etuds)}, + "rang": {"value": "DEM", "total": nb_inscrits}, } ) d.update( diff --git a/app/but/bulletin_but_xml_compat.py b/app/but/bulletin_but_xml_compat.py index b3398ef9..f318f236 100644 --- a/app/but/bulletin_but_xml_compat.py +++ b/app/but/bulletin_but_xml_compat.py @@ -69,10 +69,11 @@ def bulletin_but_xml_compat( % (formsemestre_id, etudid) ) formsemestre = FormSemestre.query.get_or_404(formsemestre_id) - etud = Identite.query.get_or_404(etudid) + etud: Identite = Identite.query.get_or_404(etudid) results = bulletin_but.ResultatsSemestreBUT(formsemestre) - nb_inscrits = len(results.etuds) - etat_inscription = etud.etat_inscription(formsemestre.id) + nb_inscrits = results.get_inscriptions_counts()[scu.INSCRIT] + # etat_inscription = etud.etat_inscription(formsemestre.id) + etat_inscription = results.formsemestre.etuds_inscriptions[etudid].etat if (not formsemestre.bul_hide_xml) or force_publishing: published = 1 else: diff --git a/app/comp/inscr_mod.py b/app/comp/inscr_mod.py index c34547e6..8a5f4bc8 100644 --- a/app/comp/inscr_mod.py +++ b/app/comp/inscr_mod.py @@ -16,13 +16,13 @@ from app import models # def df_load_modimpl_inscr(formsemestre) -> pd.DataFrame: """Charge la matrice des inscriptions aux modules du semestre - rows: etudid + rows: etudid (inscrits au semestre, avec DEM et DEF) columns: moduleimpl_id (en chaîne) value: bool (0/1 inscrit ou pas) """ # méthode la moins lente: une requete par module, merge les dataframes moduleimpl_ids = [m.id for m in formsemestre.modimpls] - etudids = [i.etudid for i in formsemestre.get_inscrits(include_dem=False)] + etudids = [inscr.etudid for inscr in formsemestre.inscriptions] df = pd.DataFrame(index=etudids, dtype=int) for moduleimpl_id in moduleimpl_ids: ins_df = pd.read_sql_query( diff --git a/app/comp/moy_mod.py b/app/comp/moy_mod.py index 95524597..2fee521d 100644 --- a/app/comp/moy_mod.py +++ b/app/comp/moy_mod.py @@ -75,7 +75,7 @@ class ModuleImplResults: "{ evaluation_id: EvaluationEtat }" # self.evals_notes = None - """DataFrame, colonnes: EVALS, Lignes: etudid + """DataFrame, colonnes: EVALS, Lignes: etudid (inscrits au SEMESTRE) valeur: notes brutes, float ou NOTES_ATTENTE, NOTES_NEUTRALISE, NOTES_ABSENCE. Les NaN désignent les notes manquantes (non saisies). @@ -105,7 +105,7 @@ class ModuleImplResults: Évaluation "complete" (prise en compte dans les calculs) si: - soit tous les étudiants inscrits au module ont des notes - - soit elle a été déclarée "à prise ne compte immédiate" (publish_incomplete) + - soit elle a été déclarée "à prise en compte immédiate" (publish_incomplete) Évaluation "attente" (prise en compte dans les calculs, mais il y manque des notes) ssi il y a des étudiants inscrits au semestre et au module @@ -178,14 +178,12 @@ class ModuleImplResults: return eval_df def _etudids(self): - """L'index du dataframe est la liste des étudiants inscrits au semestre, - sans les démissionnaires. - """ + """L'index du dataframe est la liste de tous les étudiants inscrits au semestre""" return [ - e.etudid - for e in ModuleImpl.query.get(self.moduleimpl_id).formsemestre.get_inscrits( - include_dem=False - ) + inscr.etudid + for inscr in ModuleImpl.query.get( + self.moduleimpl_id + ).formsemestre.inscriptions ] def get_evaluations_coefs(self, moduleimpl: ModuleImpl) -> np.array: diff --git a/app/comp/moy_sem.py b/app/comp/moy_sem.py index 8797b856..3c658988 100644 --- a/app/comp/moy_sem.py +++ b/app/comp/moy_sem.py @@ -31,8 +31,10 @@ import numpy as np import pandas as pd -def compute_sem_moys_apc(etud_moy_ue_df, modimpl_coefs_df): - """Calcule la moyenne générale indicative +def compute_sem_moys_apc( + etud_moy_ue_df: pd.DataFrame, modimpl_coefs_df: pd.DataFrame +) -> pd.Series: + """Calcule les moyennes générales indicatives de tous les étudiants = moyenne des moyennes d'UE, pondérée par la somme de leurs coefs etud_moy_ue_df: DataFrame, colonnes ue_id, lignes etudid @@ -46,10 +48,11 @@ def compute_sem_moys_apc(etud_moy_ue_df, modimpl_coefs_df): return moy_gen -def comp_ranks_series(notes: pd.Series): - """Calcul rangs à partir d'une séries ("vecteur") de notes (index etudid, valeur numérique) - en tenant compte des ex-aequos - Le resultat est: { etudid : rang } où rang est une chaine decrivant le rang +def comp_ranks_series(notes: pd.Series) -> dict[int, str]: + """Calcul rangs à partir d'une séries ("vecteur") de notes (index etudid, valeur + numérique) en tenant compte des ex-aequos. + + Result: { etudid : rang:str } où rang est une chaine decrivant le rang. """ notes = notes.sort_values(ascending=False) # Serie, tri par ordre décroissant rangs = pd.Series(index=notes.index, dtype=str) # le rang est une chaîne diff --git a/app/comp/moy_ue.py b/app/comp/moy_ue.py index e3c9620a..228c2c74 100644 --- a/app/comp/moy_ue.py +++ b/app/comp/moy_ue.py @@ -140,9 +140,14 @@ def notes_sem_assemble_cube(modimpls_notes: list[pd.DataFrame]) -> np.ndarray: def notes_sem_load_cube(formsemestre: FormSemestre) -> tuple: - """Calcule le cube des notes du semestre - (charge toutes les notes, calcule les moyenne des modules - et assemble le cube) + """Construit le "cube" (tenseur) des notes du semestre. + Charge toutes les notes (sql), calcule les moyennes des modules + et assemble le cube. + + etuds: tous les inscrits au semestre (avec dem. et def.) + modimpls: _tous_ les modimpls de ce semestre + UEs: X?X voir quelles sont les UE considérées ici + Resultat: sem_cube : ndarray (etuds x modimpls x UEs) modimpls_evals_poids dict { modimpl.id : evals_poids } @@ -174,14 +179,14 @@ def compute_ue_moys_apc( ) -> pd.DataFrame: """Calcul de la moyenne d'UE en mode APC (BUT). La moyenne d'UE est un nombre (note/20), ou NI ou NA ou ERR - NI non inscrit à (au moins un) module de cette UE - NA pas de notes disponibles - ERR erreur dans une formule utilisateur. [XXX pas encore gérées ici] + NI non inscrit à (au moins un) module de cette UE + NA pas de notes disponibles + ERR erreur dans une formule utilisateur. [XXX pas encore gérées ici] sem_cube: notes moyennes aux modules ndarray (etuds x modimpls x UEs) (floats avec des NaN) - etuds : listes des étudiants (dim. 0 du cube) + etuds : liste des étudiants (dim. 0 du cube) modimpls : liste des modules à considérer (dim. 1 du cube) ues : liste des UE (dim. 2 du cube) modimpl_inscr_df: matrice d'inscription du semestre (etud x modimpl) @@ -235,12 +240,12 @@ def compute_ue_moys_classic( ues: list, modimpl_inscr_df: pd.DataFrame, modimpl_coefs: np.array, -) -> tuple: +) -> tuple[pd.Series, pd.DataFrame, pd.DataFrame]: """Calcul de la moyenne d'UE en mode classique. La moyenne d'UE est un nombre (note/20), ou NI ou NA ou ERR - NI non inscrit à (au moins un) module de cette UE - NA pas de notes disponibles - ERR erreur dans une formule utilisateur. [XXX pas encore gérées ici] + NI non inscrit à (au moins un) module de cette UE + NA pas de notes disponibles + ERR erreur dans une formule utilisateur. [XXX pas encore gérées ici] sem_matrix: notes moyennes aux modules ndarray (etuds x modimpls) @@ -253,6 +258,9 @@ def compute_ue_moys_classic( Résultat: - moyennes générales: pd.Series, index etudid - moyennes d'UE: DataFrame columns UE, rows etudid + - coefficients d'UE: DataFrame, columns UE, rows etudid + les coefficients effectifs de chaque UE pour chaque étudiant + (sommes de coefs de modules pris en compte) """ nb_etuds, nb_modules = sem_matrix.shape assert len(modimpl_coefs) == nb_modules @@ -293,4 +301,9 @@ def compute_ue_moys_classic( etud_moy_ue_df = pd.DataFrame( etud_moy_ue, index=modimpl_inscr_df.index, columns=[ue.id for ue in ues] ) - return etud_moy_gen_s, etud_moy_ue_df + etud_coef_ue_df = pd.DataFrame( + coefs.sum(axis=2).T, + index=modimpl_inscr_df.index, # etudids + columns=[ue.id for ue in ues], + ) + return etud_moy_gen_s, etud_moy_ue_df, etud_coef_ue_df diff --git a/app/comp/res_but.py b/app/comp/res_but.py index aa9f3fe0..669380a3 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -6,6 +6,7 @@ """Résultats semestres BUT """ +import pandas as pd from app.comp import moy_ue, moy_sem, inscr_mod from app.comp.res_common import NotesTableCompat @@ -49,6 +50,10 @@ class ResultatsSemestreBUT(NotesTableCompat): self.modimpl_inscr_df, self.modimpl_coefs_df, ) + # Les coefficients d'UE ne sont pas utilisés en APC + self.etud_coef_ue_df = pd.DataFrame( + 1.0, index=self.etud_moy_ue.index, columns=self.etud_moy_ue.columns + ) self.etud_moy_gen = moy_sem.compute_sem_moys_apc( self.etud_moy_ue, self.modimpl_coefs_df ) diff --git a/app/comp/res_classic.py b/app/comp/res_classic.py index 93e3a9fb..68972ced 100644 --- a/app/comp/res_classic.py +++ b/app/comp/res_classic.py @@ -8,6 +8,7 @@ """ import numpy as np import pandas as pd + from app.comp import moy_mod, moy_ue, moy_sem, inscr_mod from app.comp.res_common import NotesTableCompat from app.models.formsemestre import FormSemestre @@ -45,7 +46,11 @@ class ResultatsSemestreClassic(NotesTableCompat): self.modimpl_idx = {m.id: i for i, m in enumerate(self.formsemestre.modimpls)} "l'idx de la colonne du mod modimpl.id est modimpl_idx[modimpl.id]" - self.etud_moy_gen, self.etud_moy_ue = moy_ue.compute_ue_moys_classic( + ( + self.etud_moy_gen, + self.etud_moy_ue, + self.etud_coef_ue_df, + ) = moy_ue.compute_ue_moys_classic( self.formsemestre, self.sem_matrix, self.ues, diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 7a922cf6..1ff65468 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -4,13 +4,13 @@ # See LICENSE ############################################################################## -from collections import defaultdict +from collections import defaultdict, Counter from functools import cached_property import numpy as np import pandas as pd from app.comp.aux import StatsMoyenne from app.comp.moy_mod import ModuleImplResults -from app.models import FormSemestre, ModuleImpl +from app.models import FormSemestre, Identite, ModuleImpl from app.models.ues import UniteEns from app.scodoc import sco_utils as scu from app.scodoc.sco_cache import ResultatsSemestreCache @@ -32,6 +32,7 @@ class ResultatsSemestre: "etud_moy_ue", "modimpl_inscr_df", "modimpls_results", + "etud_coef_ue_df", ) def __init__(self, formsemestre: FormSemestre): @@ -45,7 +46,10 @@ class ResultatsSemestre: self.etud_moy_gen = {} self.etud_moy_gen_ranks = {} self.modimpls_results: ModuleImplResults = None - # TODO + self.etud_coef_ue_df = None + """coefs d'UE effectifs pour chaque etudiant (pour form. classiques)""" + + # TODO ? def load_cached(self) -> bool: "Load cached dataframes, returns False si pas en cache" @@ -68,24 +72,34 @@ class ResultatsSemestre: # voir ce qui est chargé / calculé ici et dans les sous-classes raise NotImplementedError() - @cached_property - def etuds(self): - "Liste des inscrits au semestre, sans les démissionnaires" - # nb: si la liste des inscrits change, ResultatsSemestre devient invalide - return self.formsemestre.get_inscrits(include_dem=False) + def get_inscriptions_counts(self) -> Counter: + """Nombre d'inscrits, défaillants, démissionnaires. + + Exemple: res.get_inscriptions_counts()[scu.INSCRIT] + + Result: a collections.Counter instance + """ + return Counter(ins.etat for ins in self.formsemestre.inscriptions) @cached_property - def etud_index(self): + def etuds(self) -> list[Identite]: + "Liste des inscrits au semestre, avec les démissionnaires et les défaillants" + # nb: si la liste des inscrits change, ResultatsSemestre devient invalide + return self.formsemestre.get_inscrits(include_demdef=True) + + @cached_property + def etud_index(self) -> dict[int, int]: "dict { etudid : indice dans les inscrits }" return {e.id: idx for idx, e in enumerate(self.etuds)} @cached_property - def etuds_dict(self): - "dict { etudid : Identite } inscrits au semestre, sans les démissionnaires" + def etuds_dict(self) -> dict[int, Identite]: + """dict { etudid : Identite } inscrits au semestre, + avec les démissionnaires et defs.""" return {etud.id: etud for etud in self.etuds} @cached_property - def ues(self) -> list: + def ues(self) -> list[UniteEns]: """Liste des UEs du semestre (indices des DataFrames) """ @@ -153,6 +167,7 @@ class NotesTableCompat(ResultatsSemestre): def __init__(self, formsemestre: FormSemestre): super().__init__(formsemestre) + nb_etuds = len(self.etuds) self.bonus = defaultdict(lambda: 0.0) # XXX TODO self.ue_rangs = {u.id: (defaultdict(lambda: 0.0), nb_etuds) for u in self.ues} @@ -178,12 +193,18 @@ class NotesTableCompat(ResultatsSemestre): return [x["etudid"] for x in self.inscrlist] + @cached_property + def sem(self) -> dict: + """le formsemestre, comme un dict (nt.sem)""" + return self.formsemestre.to_dict() + @cached_property def inscrlist(self) -> list[dict]: # utilisé par PE seulement - """Liste de dict etud, avec démissionnaires + """Liste des inscrits au semestre (avec DEM et DEF), + sous forme de dict etud, classée dans l'ordre alphabétique de noms. """ - etuds = self.formsemestre.get_inscrits(include_dem=True) + etuds = self.formsemestre.get_inscrits(include_demdef=True) etuds.sort(key=lambda e: e.sort_key) return [e.to_dict_scodoc7() for e in etuds] @@ -256,9 +277,12 @@ class NotesTableCompat(ResultatsSemestre): raise NotImplementedError() # virtual method def get_etud_ue_status(self, etudid: int, ue_id: int): + coef_ue = self.etud_coef_ue_df[ue_id][etudid] return { "cur_moy_ue": self.etud_moy_ue[ue_id][etudid], + "moy": self.etud_moy_ue[ue_id][etudid], "is_capitalized": False, # XXX TODO + "coef_ue": coef_ue, # XXX TODO } def get_etud_rang(self, etudid: int): @@ -277,18 +301,20 @@ class NotesTableCompat(ResultatsSemestre): for e in modimpl.evaluations: if self.modimpls_results[moduleimpl_id].evaluations_completes_dict[e.id]: d = e.to_dict() + moduleimpl_results = self.modimpls_results[e.moduleimpl_id] d["heure_debut"] = e.heure_debut # datetime.time d["heure_fin"] = e.heure_fin d["jour"] = e.jour # datetime d["notes"] = { etud.id: { "etudid": etud.id, - "value": self.modimpls_evals_notes[e.moduleimpl_id][e.id][ - etud.id - ], + "value": moduleimpl_results.evals_notes[e.id][etud.id], } for etud in self.etuds } + d["etat"] = { + "evalattente": moduleimpl_results.evaluations_etat[e.id].nb_attente, + } evals_results.append(d) return evals_results diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index a55188b6..a74f1671 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -117,11 +117,18 @@ class FormSemestre(db.Model): d.pop("_sa_instance_state", None) # ScoDoc7 output_formators: (backward compat) d["formsemestre_id"] = self.id - d["date_debut"] = ( - self.date_debut.strftime("%d/%m/%Y") if self.date_debut else "" - ) - d["date_fin"] = self.date_fin.strftime("%d/%m/%Y") if self.date_fin else "" + if self.date_debut: + d["date_debut"] = self.date_debut.strftime("%d/%m/%Y") + d["date_debut_iso"] = self.date_debut.isoformat() + else: + d["date_debut"] = d["date_debut_iso"] = "" + if self.date_fin: + d["date_fin"] = self.date_fin.strftime("%d/%m/%Y") + d["date_fin_iso"] = self.date_fin.isoformat() + else: + d["date_fin"] = d["date_fin_iso"] = "" d["responsables"] = [u.id for u in self.responsables] + return d def query_ues(self, with_sport=False) -> flask_sqlalchemy.BaseQuery: @@ -271,18 +278,19 @@ class FormSemestre(db.Model): etudid, self.date_debut.isoformat(), self.date_fin.isoformat() ) - def get_inscrits(self, include_dem=False) -> list[Identite]: + def get_inscrits(self, include_demdef=False) -> list[Identite]: """Liste des étudiants inscrits à ce semestre - Si all, tous les étudiants, avec les démissionnaires. + Si include_demdef, tous les étudiants, avec les démissionnaires + et défaillants. """ - if include_dem: + if include_demdef: return [ins.etud for ins in self.inscriptions] else: return [ins.etud for ins in self.inscriptions if ins.etat == scu.INSCRIT] @cached_property def etuds_inscriptions(self) -> dict: - """Map { etudid : inscription }""" + """Map { etudid : inscription } (incluant DEM et DEF)""" return {ins.etud.id: ins for ins in self.inscriptions} diff --git a/app/scodoc/bonus_sport.py b/app/scodoc/bonus_sport.py index 651c6081..75b08b50 100644 --- a/app/scodoc/bonus_sport.py +++ b/app/scodoc/bonus_sport.py @@ -62,7 +62,7 @@ Pour modifier les moyennes d'UE: La valeur retournée est: - formations classiques: ajoutée à la moyenne générale - - BUT: ajoutée à chaque UE si le coef XXX + - BUT: valeur multipliée par la somme des coefs modules sport ajoutée à chaque UE. """ diff --git a/app/scodoc/notes_table.py b/app/scodoc/notes_table.py index 828ea228..eec178f1 100644 --- a/app/scodoc/notes_table.py +++ b/app/scodoc/notes_table.py @@ -171,6 +171,7 @@ class NotesTable: def __init__(self, formsemestre_id): log(f"NotesTable( formsemestre_id={formsemestre_id} )") + # raise NotImplementedError() # XXX if not formsemestre_id: raise ValueError("invalid formsemestre_id (%s)" % formsemestre_id) self.formsemestre_id = formsemestre_id @@ -409,7 +410,7 @@ class NotesTable: return "" def get_etud_etat_html(self, etudid): - etat = self.inscrdict[etudid]["etat"] + if etat == "I": return "" elif etat == "D": diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index ae7e14a9..1941d051 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -48,6 +48,9 @@ import app.scodoc.sco_utils as scu from app.scodoc.sco_utils import ModuleType import app.scodoc.notesdb as ndb from app import log +from app.comp import res_sem +from app.comp.res_common import NotesTableCompat +from app.models import FormSemestre from app.scodoc.sco_permissions import Permission from app.scodoc.sco_exceptions import AccessDenied, ScoValueError from app.scodoc import html_sco_header @@ -136,7 +139,9 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): raise ValueError("invalid version code !") prefs = sco_preferences.SemPreferences(formsemestre_id) - nt = sco_cache.NotesTableCache.get(formsemestre_id) # > toutes notes + # nt = sco_cache.NotesTableCache.get(formsemestre_id) # > toutes notes + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + nt: NotesTableCompat = res_sem.load_formsemestre_result(formsemestre) if not nt.get_etud_etat(etudid): raise ScoValueError("Etudiant non inscrit à ce semestre") I = scu.DictDefault(defaultvalue="") @@ -191,7 +196,9 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): I["decision_sem"] = "" I.update(infos) - I["etud_etat_html"] = nt.get_etud_etat_html(etudid) + I["etud_etat_html"] = _get_etud_etat_html( + formsemestre.etuds_inscriptions[etudid].etat + ) I["etud_etat"] = nt.get_etud_etat(etudid) I["filigranne"] = "" I["demission"] = "" @@ -261,17 +268,18 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): # notes en attente dans ce semestre rang = scu.RANG_ATTENTE_STR rang_gr = scu.DictDefault(defaultvalue=scu.RANG_ATTENTE_STR) + inscriptions_counts = nt.get_inscriptions_counts() I["rang"] = rang I["rang_gr"] = rang_gr I["gr_name"] = gr_name I["ninscrits_gr"] = ninscrits_gr I["nbetuds"] = len(nt.etud_moy_gen_ranks) - I["nb_demissions"] = nt.nb_demissions - I["nb_defaillants"] = nt.nb_defaillants + I["nb_demissions"] = inscriptions_counts[scu.DEMISSION] + I["nb_defaillants"] = inscriptions_counts[scu.DEF] if prefs["bul_show_rangs"]: I["rang_nt"] = "%s / %d" % ( rang, - I["nbetuds"] - nt.nb_demissions - nt.nb_defaillants, + inscriptions_counts[scu.INSCRIT], ) I["rang_txt"] = "Rang " + I["rang_nt"] else: @@ -379,7 +387,8 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): I["ues"].append(u) # ne montre pas les UE si non inscrit # Accès par matieres - I["matieres_modules"].update(_sort_mod_by_matiere(modules, nt, etudid)) + # voir si on supporte encore cela en #sco92 XXX + # I["matieres_modules"].update(_sort_mod_by_matiere(modules, nt, etudid)) # C = make_context_dict(I["sem"], I["etud"]) @@ -389,6 +398,18 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): return C +def _get_etud_etat_html(etat: str) -> str: + """chaine html représentant l'état (backward compat sco7)""" + if etat == scu.INSCRIT: # "I" + return "" + elif etat == scu.DEMISSION: # "D" + return ' (DEMISSIONNAIRE) ' + elif etat == scu.DEF: # "DEF" + return ' (DEFAILLANT) ' + else: + return ' (%s) ' % etat + + def _sort_mod_by_matiere(modlist, nt, etudid): matmod = {} # { matiere_id : [] } for mod in modlist: diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py index 8248491a..2036a64d 100644 --- a/app/scodoc/sco_groups.py +++ b/app/scodoc/sco_groups.py @@ -1433,18 +1433,19 @@ def create_etapes_partition(formsemestre_id, partition_name="apo_etapes"): def do_evaluation_listeetuds_groups( - evaluation_id, groups=None, getallstudents=False, include_dems=False + evaluation_id, groups=None, getallstudents=False, include_demdef=False ): """Donne la liste des etudids inscrits a cette evaluation dans les groupes indiqués. Si getallstudents==True, donne tous les etudiants inscrits a cette evaluation. - Si include_dems, compte aussi les etudiants démissionnaires + Si include_demdef, compte aussi les etudiants démissionnaires et défaillants (sinon, par défaut, seulement les 'I') Résultat: [ (etudid, etat) ], où etat='I', 'D', 'DEF' """ - # nb: pour notes_table / do_evaluation_etat, getallstudents est vrai et include_dems faux + # nb: pour notes_table / do_evaluation_etat, getallstudents est vrai et + # include_demdef faux fromtables = [ "notes_moduleimpl_inscription Im", "notes_formsemestre_inscription Isem", @@ -1476,7 +1477,7 @@ def do_evaluation_listeetuds_groups( and E.id = %(evaluation_id)s """ ) - if not include_dems: + if not include_demdef: req += " and Isem.etat='I'" req += r cnx = ndb.GetDBConnexion() diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py index 00e61589..2ee8c620 100644 --- a/app/scodoc/sco_liste_notes.py +++ b/app/scodoc/sco_liste_notes.py @@ -309,7 +309,7 @@ def _make_table_notes( anonymous_lst_key = "etudid" etudid_etats = sco_groups.do_evaluation_listeetuds_groups( - E["evaluation_id"], groups, include_dems=True + E["evaluation_id"], groups, include_demdef=True ) for etudid, etat in etudid_etats: css_row_class = None diff --git a/app/scodoc/sco_placement.py b/app/scodoc/sco_placement.py index fb8a35ea..1d5ac6c4 100644 --- a/app/scodoc/sco_placement.py +++ b/app/scodoc/sco_placement.py @@ -307,7 +307,7 @@ class PlacementRunner: self.evaluation_id, self.groups, getallstudents=get_all_students, - include_dems=True, + include_demdef=True, ) listetud = [] # liste de couples (nom,prenom) for etudid, etat in etudid_etats: diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index f79b06ea..997e835e 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -306,8 +306,8 @@ def make_formsemestre_recapcomplet( )[0] parcours = formsemestre.formation.get_parcours() - # nt = sco_cache.NotesTableCache.get(formsemestre_id) - # XXX EXPERIMENTAL + # nt = sco_cache.NotesTableCache.get(formsemestre_id) # sco91 + # sco92 : nt: NotesTableCompat = res_sem.load_formsemestre_result(formsemestre) modimpls = nt.get_modimpls_dict() ues = nt.get_ues_stat_dict() # incluant le(s) UE de sport @@ -434,13 +434,12 @@ def make_formsemestre_recapcomplet( e["admission"] = {} if not hidebac: - if etud_etat == scu.INSCRIT: - e["admission"] = nt.etuds_dict[etudid].admission.first() - if e["admission"]: - bac = nt.etuds_dict[etudid].admission[0].get_bac() - l.append(bac.abbrev()) - else: - l.append("") + e["admission"] = nt.etuds_dict[etudid].admission.first() + if e["admission"]: + bac = nt.etuds_dict[etudid].admission[0].get_bac() + l.append(bac.abbrev()) + else: + l.append("") if format[:3] == "xls" or format == "csv": # tous les groupes for partition in partitions: diff --git a/app/scodoc/sco_saisie_notes.py b/app/scodoc/sco_saisie_notes.py index fc3fd081..a714fb0e 100644 --- a/app/scodoc/sco_saisie_notes.py +++ b/app/scodoc/sco_saisie_notes.py @@ -310,7 +310,7 @@ def do_evaluation_set_missing(evaluation_id, value, dialog_confirmed=False): # NotesDB = sco_evaluation_db.do_evaluation_get_all_notes(evaluation_id) etudid_etats = sco_groups.do_evaluation_listeetuds_groups( - evaluation_id, getallstudents=True, include_dems=False + evaluation_id, getallstudents=True, include_demdef=False ) notes = [] for etudid, _ in etudid_etats: # pour tous les inscrits @@ -482,7 +482,7 @@ def notes_add( inscrits = { x[0] for x in sco_groups.do_evaluation_listeetuds_groups( - evaluation_id, getallstudents=True, include_dems=True + evaluation_id, getallstudents=True, include_demdef=True ) } for (etudid, value) in notes: @@ -833,7 +833,7 @@ def feuille_saisie_notes(evaluation_id, group_ids=[]): etudids = [ x[0] for x in sco_groups.do_evaluation_listeetuds_groups( - evaluation_id, groups, getallstudents=getallstudents, include_dems=True + evaluation_id, groups, getallstudents=getallstudents, include_demdef=True ) ] @@ -1079,7 +1079,7 @@ def _form_saisie_notes(E, M, group_ids, destination=""): etudids = [ x[0] for x in sco_groups.do_evaluation_listeetuds_groups( - evaluation_id, getallstudents=True, include_dems=True + evaluation_id, getallstudents=True, include_demdef=True ) ] if not etudids: