From 872e741d9f8cd40646abffc426e9456c654f4b90 Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Sat, 17 Dec 2022 17:27:14 -0300 Subject: [PATCH] Check APC conformity: cas UE de parcours --- app/comp/moy_mod.py | 10 ++-- app/models/moduleimpls.py | 4 +- app/scodoc/sco_liste_notes.py | 93 +++++++++++++++-------------- app/scodoc/sco_moduleimpl_status.py | 2 +- 4 files changed, 55 insertions(+), 54 deletions(-) diff --git a/app/comp/moy_mod.py b/app/comp/moy_mod.py index 5d6e80aaf..963cae78b 100644 --- a/app/comp/moy_mod.py +++ b/app/comp/moy_mod.py @@ -437,7 +437,7 @@ def load_evaluations_poids(moduleimpl_id: int) -> tuple[pd.DataFrame, list]: def moduleimpl_is_conforme( - moduleimpl, evals_poids: pd.DataFrame, modules_coefficients: pd.DataFrame + moduleimpl, evals_poids: pd.DataFrame, modimpl_coefs_df: pd.DataFrame ) -> bool: """Vérifie que les évaluations de ce moduleimpl sont bien conformes au PN. @@ -446,7 +446,7 @@ def moduleimpl_is_conforme( Arguments: evals_poids: DataFrame, colonnes: UEs, Lignes: EVALs - modules_coefficients: DataFrame, cols module_id, lignes UEs + modimpl_coefs_df: DataFrame, cols: modimpl_id, lignes: UEs du formsemestre NB: les UEs dans evals_poids sont sans le bonus sport """ nb_evals, nb_ues = evals_poids.shape @@ -454,18 +454,18 @@ def moduleimpl_is_conforme( return True # modules vides conformes if nb_ues == 0: return False # situation absurde (pas d'UE) - if len(modules_coefficients) != nb_ues: + if len(modimpl_coefs_df) != nb_ues: # il arrive (#bug) que le cache ne soit pas à jour... sco_cache.invalidate_formsemestre() raise ScoBugCatcher("moduleimpl_is_conforme: nb ue incoherent") - if moduleimpl.module_id not in modules_coefficients: + if moduleimpl.id not in modimpl_coefs_df: # soupçon de bug cache coef ? sco_cache.invalidate_formsemestre() raise ScoBugCatcher("Erreur 454 - merci de ré-essayer") module_evals_poids = evals_poids.transpose().sum(axis=1) != 0 - return all((modules_coefficients[moduleimpl.module_id] != 0).eq(module_evals_poids)) + return all((modimpl_coefs_df[moduleimpl.id] != 0).eq(module_evals_poids)) class ModuleImplResultsClassic(ModuleImplResults): diff --git a/app/models/moduleimpls.py b/app/models/moduleimpls.py index 984f3a290..5b81fa1b4 100644 --- a/app/models/moduleimpls.py +++ b/app/models/moduleimpls.py @@ -62,7 +62,7 @@ class ModuleImpl(db.Model): """Invalide poids cachés""" df_cache.EvaluationsPoidsCache.delete(self.id) - def check_apc_conformity(self) -> bool: + def check_apc_conformity(self, res: "ResultatsSemestreBUT") -> bool: """true si les poids des évaluations du module permettent de satisfaire les coefficients du PN. """ @@ -76,7 +76,7 @@ class ModuleImpl(db.Model): return moy_mod.moduleimpl_is_conforme( self, self.get_evaluations_poids(), - self.module.formation.get_module_coefs(self.module.semestre_id), + res.modimpl_coefs_df, ) def to_dict(self, convert_objects=False, with_module=True): diff --git a/app/scodoc/sco_liste_notes.py b/app/scodoc/sco_liste_notes.py index 48ff7ce7b..ba27b1f4a 100644 --- a/app/scodoc/sco_liste_notes.py +++ b/app/scodoc/sco_liste_notes.py @@ -40,7 +40,7 @@ from app.comp import moy_mod from app.comp.moy_mod import ModuleImplResults from app.comp.res_compat import NotesTableCompat from app.comp.res_but import ResultatsSemestreBUT -from app.models import FormSemestre +from app.models import FormSemestre, Module from app.models.etudiants import Identite from app.models.evaluations import Evaluation from app.models.moduleimpls import ModuleImpl @@ -50,9 +50,7 @@ from app.scodoc.TrivialFormulator import TrivialFormulator from app.scodoc.sco_etud import etud_sort_key from app.scodoc import sco_evaluations from app.scodoc import sco_evaluation_db -from app.scodoc import sco_formsemestre from app.scodoc import sco_groups -from app.scodoc import sco_moduleimpl from app.scodoc import sco_preferences from app.scodoc import sco_users import app.scodoc.sco_utils as scu @@ -198,8 +196,11 @@ def do_evaluation_listenotes( elif tf[0] == -1: return ( flask.redirect( - "%s/Notes/moduleimpl_status?moduleimpl_id=%s" - % (scu.ScoURL(), E["moduleimpl_id"]) + url_for( + "notes.moduleimpl_status", + scodoc_dept=g.scodoc_dept, + moduleimpl_id=E["moduleimpl_id"], + ) ), "", ) @@ -213,7 +214,7 @@ def do_evaluation_listenotes( _make_table_notes( tf[1], evals, - format=format, + fmt=format, note_sur_20=note_sur_20, anonymous_listing=anonymous_listing, group_ids=group_ids, @@ -228,45 +229,46 @@ def do_evaluation_listenotes( def _make_table_notes( html_form, evals, - format="", + fmt: str = "", note_sur_20=False, anonymous_listing=False, hide_groups=False, with_emails=False, - group_ids=[], + group_ids: list[int] = None, mode="module", # "eval" or "module" -): +) -> str: """Table liste notes (une seule évaluation ou toutes celles d'un module)""" - # Code à ré-écrire ! + group_ids = group_ids or [] if not evals: return "

Aucune évaluation !

" E = evals[0] moduleimpl_id = E["moduleimpl_id"] - modimpl_o = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0] - module = models.Module.query.get(modimpl_o["module_id"]) + modimpl = ModuleImpl.query.get_or_404(moduleimpl_id) + modimpl_o = modimpl.to_dict() # TODO temporaire - à refactorer + module: Module = modimpl.module + formsemestre: FormSemestre = modimpl.formsemestre is_apc = module.formation.get_parcours().APC_SAE if is_apc: - modimpl = ModuleImpl.query.get(moduleimpl_id) - is_conforme = modimpl.check_apc_conformity() + res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre) + is_conforme = modimpl.check_apc_conformity(res) evals_poids, ues = moy_mod.load_evaluations_poids(moduleimpl_id) if not ues: is_apc = False else: evals_poids, ues = None, None is_conforme = True - sem = sco_formsemestre.get_formsemestre(modimpl_o["formsemestre_id"]) # (debug) check that all evals are in same module: for e in evals: if e["moduleimpl_id"] != moduleimpl_id: raise ValueError("invalid evaluations list") - if format == "xls": + if fmt == "xls": keep_numeric = True # pas de conversion des notes en strings else: keep_numeric = False # Si pas de groupe, affiche tout if not group_ids: - group_ids = [sco_groups.get_default_group(modimpl_o["formsemestre_id"])] + group_ids = [sco_groups.get_default_group(formsemestre.id)] groups = sco_groups.listgroups(group_ids) gr_title = sco_groups.listgroups_abbrev(groups) @@ -275,7 +277,7 @@ def _make_table_notes( if anonymous_listing: columns_ids = ["code"] # cols in table else: - if format == "xls" or format == "xml": + if fmt == "xls" or fmt == "xml": columns_ids = ["nom", "prenom"] else: columns_ids = ["nomprenom"] @@ -326,7 +328,7 @@ def _make_table_notes( continue if etat == scu.INSCRIT: # si inscrit, indique groupe - groups = sco_groups.get_etud_groups(etudid, modimpl_o["formsemestre_id"]) + groups = sco_groups.get_etud_groups(etudid, formsemestre.id) grc = sco_groups.listgroups_abbrev(groups) else: if etat == scu.DEMISSION: @@ -348,7 +350,7 @@ def _make_table_notes( "_nomprenom_target": url_for( "notes.formsemestre_bulletinetud", scodoc_dept=g.scodoc_dept, - formsemestre_id=modimpl_o["formsemestre_id"], + formsemestre_id=formsemestre.id, etudid=etudid, ), "_nomprenom_td_attrs": f"""id="{etudid}" class="etudinfo" data-sort="{etud.sort_key}" """, @@ -415,7 +417,7 @@ def _make_table_notes( key_mgr, note_sur_20, keep_numeric, - format=format, + format=fmt, ) columns_ids.append(e["evaluation_id"]) # @@ -431,7 +433,7 @@ def _make_table_notes( # Moyenne de l'étudiant dans le module # Affichée même en APC à titre indicatif _add_moymod_column( - sem["formsemestre_id"], + formsemestre.id, moduleimpl_id, rows, columns_ids, @@ -464,7 +466,7 @@ def _make_table_notes( if with_emails: columns_ids += ["email", "emailperso"] # Ajoute lignes en tête et moyennes - if len(evals) > 0 and format != "bordereau": + if len(evals) > 0 and fmt != "bordereau": rows_head = [row_coefs] if is_apc: rows_head.append(row_poids) @@ -472,7 +474,7 @@ def _make_table_notes( rows = rows_head + rows rows.append(row_moys) # ajout liens HTMl vers affichage une evaluation: - if format == "html" and len(evals) > 1: + if fmt == "html" and len(evals) > 1: rlinks = {"_table_part": "head"} for e in evals: rlinks[e["evaluation_id"]] = "afficher" @@ -488,11 +490,11 @@ def _make_table_notes( rows.append(rlinks) if len(evals) == 1: # colonne "Rem." seulement si une eval - if format == "html": # pas d'indication d'origine en pdf (pour affichage) + if fmt == "html": # pas d'indication d'origine en pdf (pour affichage) columns_ids.append("expl_key") - elif format == "xls" or format == "xml": + elif fmt == "xls" or fmt == "xml": columns_ids.append("comment") - elif format == "bordereau": + elif fmt == "bordereau": columns_ids.append("signatures") # titres divers: @@ -510,7 +512,7 @@ def _make_table_notes( hh = "%s, %s (%d étudiants)" % (E["description"], gr_title, len(etudid_etats)) filename = scu.make_filename("notes_%s_%s" % (evalname, gr_title_filename)) - if format == "bordereau": + if fmt == "bordereau": hh = " %d étudiants" % (len(etudid_etats)) hh += " %d absent" % (nb_abs) if nb_abs > 1: @@ -518,15 +520,13 @@ def _make_table_notes( hh += ", %d en attente." % (nb_att) # Attention: ReportLab supporte seulement '
', pas '
' ! - pdf_title = "
BORDEREAU DE SIGNATURES" - pdf_title += "

%(titre)s" % sem - pdf_title += "
(%(mois_debut)s - %(mois_fin)s)" % sem - pdf_title += " semestre %s %s" % ( - sem["semestre_id"], - sem.get("modalite", ""), - ) - pdf_title += f"
Notes du module {module.code} - {module.titre}" - pdf_title += "
Évaluation : %(description)s " % e + pdf_title = f"""
BORDEREAU DE SIGNATURES +

{formsemestre.titre or ''} +
({formsemestre.mois_debut()} - {formsemestre.mois_fin()}) + semestre {formsemestre.semestre_id} {formsemestre.modalite or ""} +
Notes du module {module.code} - {module.titre} +
Évaluation : {e["description"]} + """ if len(e["jour"]) > 0: pdf_title += " (%(jour)s)" % e pdf_title += "(noté sur %(note_max)s )

" % e @@ -551,12 +551,12 @@ def _make_table_notes( else: filename = scu.make_filename("notes_%s_%s" % (module.code, gr_title_filename)) title = f"Notes {module.type_name()} {module.code} {module.titre}" - title += " semestre %(titremois)s" % sem + title += f""" semestre {formsemestre.titre_mois()}""" if gr_title and gr_title != "tous": title += " %s" % gr_title caption = title html_next_section = "" - if format == "pdf" or format == "bordereau": + if fmt == "pdf" or fmt == "bordereau": caption = "" # same as pdf_title pdf_title = title html_title = f"""

Notes {module.type_name()} 1: @@ -599,7 +599,8 @@ def _make_table_notes( if not e["eval_state"]["evalcomplete"]: all_complete = False if all_complete: - eval_info = 'Evaluations prises en compte dans les moyennes.' + eval_info = """Évaluations + prises en compte dans les moyennes.""" else: eval_info = """ Les évaluations en vert et orange sont prises en compte dans les moyennes. diff --git a/app/scodoc/sco_moduleimpl_status.py b/app/scodoc/sco_moduleimpl_status.py index 9f2b0cdf1..67b4a8d90 100644 --- a/app/scodoc/sco_moduleimpl_status.py +++ b/app/scodoc/sco_moduleimpl_status.py @@ -367,7 +367,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None): H.append("") # - if not modimpl.check_apc_conformity(): + if not modimpl.check_apc_conformity(nt): H.append( """
Les poids des évaluations de ce module ne sont pas encore conformes au PN.