From a467ef27db1b689dc5b2905727da11d544ecdc63 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 8 Jan 2022 19:56:09 +0100 Subject: [PATCH] WIP: recap but avec UEs --- app/comp/res_common.py | 21 +++++++++++++++++++-- app/models/formations.py | 9 ++++++++- app/scodoc/sco_recapcomplet.py | 16 ++++++++++++++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 73d003696..01549fdaf 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -11,6 +11,7 @@ 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.ues import UniteEns from app.scodoc import sco_utils as scu from app.scodoc.sco_cache import ResultatsSemestreCache from app.scodoc.sco_codes_parcours import UE_SPORT, ATT, DEF @@ -38,8 +39,9 @@ class ResultatsSemestre: # BUT ou standard ? (apc == "approche par compétences") self.is_apc = formsemestre.formation.is_apc() # Attributs "virtuels", définis dans les sous-classes - # ResultatsSemestreBUT ou ResultatsSemestreStd + # ResultatsSemestreBUT ou ResultatsSemestreClassic self.etud_moy_ue = {} + "etud_moy_ue: DataFrame columns UE, rows etudid" self.etud_moy_gen = {} self.etud_moy_gen_ranks = {} self.modimpls_results: ModuleImplResults = None @@ -78,7 +80,7 @@ class ResultatsSemestre: return {e.id: idx for idx, e in enumerate(self.etuds)} @cached_property - def ues(self): + def ues(self) -> list: "Liste des UE du semestre" return self.formsemestre.query_ues().all() @@ -114,6 +116,21 @@ class ResultatsSemestre: "Liste des SAÉs du semestre, triées par numéro de module" return [m for m in self.modimpls if m.module.module_type == scu.ModuleType.SAE] + @cached_property + def ue_validables(self) -> list: + """Liste des UE du semestre qui doivent être validées + (toutes sauf le sport) + """ + return self.formsemestre.query_ues().filter(UniteEns.type != UE_SPORT).all() + + @cached_property + def ue_au_dessus(self, seuil=10.0) -> pd.DataFrame: + """DataFrame columns UE, rows etudid, valeurs: bool + Par exemple, pour avoir le nombre d'UE au dessus de 10 pour l'étudiant etudid + nb_ues_ok = sum(res.ue_au_dessus().loc[etudid]) + """ + return self.etud_moy_ue > (seuil - scu.NOTES_TOLERANCE) + # Pour raccorder le code des anciens codes qui attendent une NoteTable class NotesTableCompat(ResultatsSemestre): diff --git a/app/models/formations.py b/app/models/formations.py index e926471c2..e2273c3b6 100644 --- a/app/models/formations.py +++ b/app/models/formations.py @@ -5,6 +5,7 @@ from app import db from app.comp import df_cache from app.models import SHORT_STR_LEN from app.models.modules import Module +from app.models.ues import UniteEns from app.scodoc import notesdb as ndb from app.scodoc import sco_cache from app.scodoc import sco_codes_parcours @@ -130,8 +131,14 @@ class Formation(db.Model): db.session.add(mod) change = True # --- Numéros de modules - if Module.query.filter_by(formation_id=220, numero=None).count() > 0: + if Module.query.filter_by(formation_id=self.id, numero=None).count() > 0: scu.objects_renumber(db, self.modules.all()) + # --- Types d'UE (avant de rendre le type non nullable) + ues_sans_type = UniteEns.query.filter_by(formation_id=self.id, type=None) + if ues_sans_type.count() > 0: + for ue in ues_sans_type: + ue.type = 0 + db.session.add(ue) db.session.commit() if change: diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index 714f5eaa3..e6e31b91b 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -38,6 +38,7 @@ from flask import make_response from app import log from app.but import bulletin_but from app.comp import res_sem +from app.comp.res_common import NotesTableCompat from app.models import FormSemestre from app.models.etudiants import Identite @@ -307,7 +308,7 @@ def make_formsemestre_recapcomplet( # nt = sco_cache.NotesTableCache.get(formsemestre_id) # XXX EXPERIMENTAL - nt = res_sem.load_formsemestre_result(formsemestre) + 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 # @@ -460,6 +461,10 @@ def make_formsemestre_recapcomplet( for partition in partitions: l.append(rang_gr[partition["partition_id"]]) + # Nombre d'UE au dessus de 10 + nb_ue_ok = sum( + [t[i] > 10 for i, ue in enumerate(ues, start=1) if ue["type"] != UE_SPORT] + ) for i, ue in enumerate(ues, start=1): if ue["type"] != UE_SPORT: l.append( @@ -656,7 +661,9 @@ def make_formsemestre_recapcomplet( if disable_etudlink: etudlink = "%(name)s" else: - etudlink = '%(name)s' + etudlink = """%(name)s""" ir = 0 nblines = len(F) - 1 for l in F[1:]: @@ -790,6 +797,11 @@ def make_formsemestre_recapcomplet( for cod in cods: H.append("%s%d" % (cod, codes_nb[cod])) H.append("") + # Avertissements + if formsemestre.formation.is_apc(): + H.append( + """

Pour les formations par compétences (comme le BUT), la moyenne générale est purement indicative et ne devrait pas être communiquée aux étudiants.

""" + ) return "\n".join(H), "", "html" elif format == "csv": CSV = scu.CSV_LINESEP.join(