Check APC conformity: cas UE de parcours

This commit is contained in:
Emmanuel Viennet 2022-12-17 17:27:14 -03:00
parent 1af92ad6ac
commit 1bd83a748f
4 changed files with 55 additions and 54 deletions

View File

@ -437,7 +437,7 @@ def load_evaluations_poids(moduleimpl_id: int) -> tuple[pd.DataFrame, list]:
def moduleimpl_is_conforme( def moduleimpl_is_conforme(
moduleimpl, evals_poids: pd.DataFrame, modules_coefficients: pd.DataFrame moduleimpl, evals_poids: pd.DataFrame, modimpl_coefs_df: pd.DataFrame
) -> bool: ) -> bool:
"""Vérifie que les évaluations de ce moduleimpl sont bien conformes """Vérifie que les évaluations de ce moduleimpl sont bien conformes
au PN. au PN.
@ -446,7 +446,7 @@ def moduleimpl_is_conforme(
Arguments: Arguments:
evals_poids: DataFrame, colonnes: UEs, Lignes: EVALs 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: les UEs dans evals_poids sont sans le bonus sport
""" """
nb_evals, nb_ues = evals_poids.shape nb_evals, nb_ues = evals_poids.shape
@ -454,18 +454,18 @@ def moduleimpl_is_conforme(
return True # modules vides conformes return True # modules vides conformes
if nb_ues == 0: if nb_ues == 0:
return False # situation absurde (pas d'UE) 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... # il arrive (#bug) que le cache ne soit pas à jour...
sco_cache.invalidate_formsemestre() sco_cache.invalidate_formsemestre()
raise ScoBugCatcher("moduleimpl_is_conforme: nb ue incoherent") 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 ? # soupçon de bug cache coef ?
sco_cache.invalidate_formsemestre() sco_cache.invalidate_formsemestre()
raise ScoBugCatcher("Erreur 454 - merci de ré-essayer") raise ScoBugCatcher("Erreur 454 - merci de ré-essayer")
module_evals_poids = evals_poids.transpose().sum(axis=1) != 0 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): class ModuleImplResultsClassic(ModuleImplResults):

View File

@ -62,7 +62,7 @@ class ModuleImpl(db.Model):
"""Invalide poids cachés""" """Invalide poids cachés"""
df_cache.EvaluationsPoidsCache.delete(self.id) 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 """true si les poids des évaluations du module permettent de satisfaire
les coefficients du PN. les coefficients du PN.
""" """
@ -76,7 +76,7 @@ class ModuleImpl(db.Model):
return moy_mod.moduleimpl_is_conforme( return moy_mod.moduleimpl_is_conforme(
self, self,
self.get_evaluations_poids(), 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): def to_dict(self, convert_objects=False, with_module=True):

View File

@ -40,7 +40,7 @@ from app.comp import moy_mod
from app.comp.moy_mod import ModuleImplResults from app.comp.moy_mod import ModuleImplResults
from app.comp.res_compat import NotesTableCompat from app.comp.res_compat import NotesTableCompat
from app.comp.res_but import ResultatsSemestreBUT 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.etudiants import Identite
from app.models.evaluations import Evaluation from app.models.evaluations import Evaluation
from app.models.moduleimpls import ModuleImpl 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.sco_etud import etud_sort_key
from app.scodoc import sco_evaluations from app.scodoc import sco_evaluations
from app.scodoc import sco_evaluation_db from app.scodoc import sco_evaluation_db
from app.scodoc import sco_formsemestre
from app.scodoc import sco_groups from app.scodoc import sco_groups
from app.scodoc import sco_moduleimpl
from app.scodoc import sco_preferences from app.scodoc import sco_preferences
from app.scodoc import sco_users from app.scodoc import sco_users
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -198,8 +196,11 @@ def do_evaluation_listenotes(
elif tf[0] == -1: elif tf[0] == -1:
return ( return (
flask.redirect( flask.redirect(
"%s/Notes/moduleimpl_status?moduleimpl_id=%s" url_for(
% (scu.ScoURL(), E["moduleimpl_id"]) "notes.moduleimpl_status",
scodoc_dept=g.scodoc_dept,
moduleimpl_id=E["moduleimpl_id"],
)
), ),
"", "",
) )
@ -213,7 +214,7 @@ def do_evaluation_listenotes(
_make_table_notes( _make_table_notes(
tf[1], tf[1],
evals, evals,
format=format, fmt=format,
note_sur_20=note_sur_20, note_sur_20=note_sur_20,
anonymous_listing=anonymous_listing, anonymous_listing=anonymous_listing,
group_ids=group_ids, group_ids=group_ids,
@ -228,45 +229,46 @@ def do_evaluation_listenotes(
def _make_table_notes( def _make_table_notes(
html_form, html_form,
evals, evals,
format="", fmt: str = "",
note_sur_20=False, note_sur_20=False,
anonymous_listing=False, anonymous_listing=False,
hide_groups=False, hide_groups=False,
with_emails=False, with_emails=False,
group_ids=[], group_ids: list[int] = None,
mode="module", # "eval" or "module" mode="module", # "eval" or "module"
): ) -> str:
"""Table liste notes (une seule évaluation ou toutes celles d'un module)""" """Table liste notes (une seule évaluation ou toutes celles d'un module)"""
# Code à ré-écrire ! group_ids = group_ids or []
if not evals: if not evals:
return "<p>Aucune évaluation !</p>" return "<p>Aucune évaluation !</p>"
E = evals[0] E = evals[0]
moduleimpl_id = E["moduleimpl_id"] moduleimpl_id = E["moduleimpl_id"]
modimpl_o = sco_moduleimpl.moduleimpl_list(moduleimpl_id=moduleimpl_id)[0] modimpl = ModuleImpl.query.get_or_404(moduleimpl_id)
module = models.Module.query.get(modimpl_o["module_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 is_apc = module.formation.get_parcours().APC_SAE
if is_apc: if is_apc:
modimpl = ModuleImpl.query.get(moduleimpl_id) res: ResultatsSemestreBUT = res_sem.load_formsemestre_results(formsemestre)
is_conforme = modimpl.check_apc_conformity() is_conforme = modimpl.check_apc_conformity(res)
evals_poids, ues = moy_mod.load_evaluations_poids(moduleimpl_id) evals_poids, ues = moy_mod.load_evaluations_poids(moduleimpl_id)
if not ues: if not ues:
is_apc = False is_apc = False
else: else:
evals_poids, ues = None, None evals_poids, ues = None, None
is_conforme = True is_conforme = True
sem = sco_formsemestre.get_formsemestre(modimpl_o["formsemestre_id"])
# (debug) check that all evals are in same module: # (debug) check that all evals are in same module:
for e in evals: for e in evals:
if e["moduleimpl_id"] != moduleimpl_id: if e["moduleimpl_id"] != moduleimpl_id:
raise ValueError("invalid evaluations list") raise ValueError("invalid evaluations list")
if format == "xls": if fmt == "xls":
keep_numeric = True # pas de conversion des notes en strings keep_numeric = True # pas de conversion des notes en strings
else: else:
keep_numeric = False keep_numeric = False
# Si pas de groupe, affiche tout # Si pas de groupe, affiche tout
if not group_ids: 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) groups = sco_groups.listgroups(group_ids)
gr_title = sco_groups.listgroups_abbrev(groups) gr_title = sco_groups.listgroups_abbrev(groups)
@ -275,7 +277,7 @@ def _make_table_notes(
if anonymous_listing: if anonymous_listing:
columns_ids = ["code"] # cols in table columns_ids = ["code"] # cols in table
else: else:
if format == "xls" or format == "xml": if fmt == "xls" or fmt == "xml":
columns_ids = ["nom", "prenom"] columns_ids = ["nom", "prenom"]
else: else:
columns_ids = ["nomprenom"] columns_ids = ["nomprenom"]
@ -326,7 +328,7 @@ def _make_table_notes(
continue continue
if etat == scu.INSCRIT: # si inscrit, indique groupe 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) grc = sco_groups.listgroups_abbrev(groups)
else: else:
if etat == scu.DEMISSION: if etat == scu.DEMISSION:
@ -348,7 +350,7 @@ def _make_table_notes(
"_nomprenom_target": url_for( "_nomprenom_target": url_for(
"notes.formsemestre_bulletinetud", "notes.formsemestre_bulletinetud",
scodoc_dept=g.scodoc_dept, scodoc_dept=g.scodoc_dept,
formsemestre_id=modimpl_o["formsemestre_id"], formsemestre_id=formsemestre.id,
etudid=etudid, etudid=etudid,
), ),
"_nomprenom_td_attrs": f"""id="{etudid}" class="etudinfo" data-sort="{etud.sort_key}" """, "_nomprenom_td_attrs": f"""id="{etudid}" class="etudinfo" data-sort="{etud.sort_key}" """,
@ -415,7 +417,7 @@ def _make_table_notes(
key_mgr, key_mgr,
note_sur_20, note_sur_20,
keep_numeric, keep_numeric,
format=format, format=fmt,
) )
columns_ids.append(e["evaluation_id"]) columns_ids.append(e["evaluation_id"])
# #
@ -431,7 +433,7 @@ def _make_table_notes(
# Moyenne de l'étudiant dans le module # Moyenne de l'étudiant dans le module
# Affichée même en APC à titre indicatif # Affichée même en APC à titre indicatif
_add_moymod_column( _add_moymod_column(
sem["formsemestre_id"], formsemestre.id,
moduleimpl_id, moduleimpl_id,
rows, rows,
columns_ids, columns_ids,
@ -464,7 +466,7 @@ def _make_table_notes(
if with_emails: if with_emails:
columns_ids += ["email", "emailperso"] columns_ids += ["email", "emailperso"]
# Ajoute lignes en tête et moyennes # 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] rows_head = [row_coefs]
if is_apc: if is_apc:
rows_head.append(row_poids) rows_head.append(row_poids)
@ -472,7 +474,7 @@ def _make_table_notes(
rows = rows_head + rows rows = rows_head + rows
rows.append(row_moys) rows.append(row_moys)
# ajout liens HTMl vers affichage une evaluation: # 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"} rlinks = {"_table_part": "head"}
for e in evals: for e in evals:
rlinks[e["evaluation_id"]] = "afficher" rlinks[e["evaluation_id"]] = "afficher"
@ -488,11 +490,11 @@ def _make_table_notes(
rows.append(rlinks) rows.append(rlinks)
if len(evals) == 1: # colonne "Rem." seulement si une eval 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") columns_ids.append("expl_key")
elif format == "xls" or format == "xml": elif fmt == "xls" or fmt == "xml":
columns_ids.append("comment") columns_ids.append("comment")
elif format == "bordereau": elif fmt == "bordereau":
columns_ids.append("signatures") columns_ids.append("signatures")
# titres divers: # titres divers:
@ -510,7 +512,7 @@ def _make_table_notes(
hh = "%s, %s (%d étudiants)" % (E["description"], gr_title, len(etudid_etats)) hh = "%s, %s (%d étudiants)" % (E["description"], gr_title, len(etudid_etats))
filename = scu.make_filename("notes_%s_%s" % (evalname, gr_title_filename)) 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 étudiants" % (len(etudid_etats))
hh += " %d absent" % (nb_abs) hh += " %d absent" % (nb_abs)
if nb_abs > 1: if nb_abs > 1:
@ -518,15 +520,13 @@ def _make_table_notes(
hh += ", %d en attente." % (nb_att) hh += ", %d en attente." % (nb_att)
# Attention: ReportLab supporte seulement '<br/>', pas '<br>' ! # Attention: ReportLab supporte seulement '<br/>', pas '<br>' !
pdf_title = "<br/> BORDEREAU DE SIGNATURES" pdf_title = f"""<br/> BORDEREAU DE SIGNATURES
pdf_title += "<br/><br/>%(titre)s" % sem <br/><br/>{formsemestre.titre or ''}
pdf_title += "<br/>(%(mois_debut)s - %(mois_fin)s)" % sem <br/>({formsemestre.mois_debut()} - {formsemestre.mois_fin()})
pdf_title += " semestre %s %s" % ( semestre {formsemestre.semestre_id} {formsemestre.modalite or ""}
sem["semestre_id"], <br/>Notes du module {module.code} - {module.titre}
sem.get("modalite", ""), <br/>Évaluation : {e["description"]}
) """
pdf_title += f"<br/>Notes du module {module.code} - {module.titre}"
pdf_title += "<br/>Évaluation : %(description)s " % e
if len(e["jour"]) > 0: if len(e["jour"]) > 0:
pdf_title += " (%(jour)s)" % e pdf_title += " (%(jour)s)" % e
pdf_title += "(noté sur %(note_max)s )<br/><br/>" % e pdf_title += "(noté sur %(note_max)s )<br/><br/>" % e
@ -551,12 +551,12 @@ def _make_table_notes(
else: else:
filename = scu.make_filename("notes_%s_%s" % (module.code, gr_title_filename)) filename = scu.make_filename("notes_%s_%s" % (module.code, gr_title_filename))
title = f"Notes {module.type_name()} {module.code} {module.titre}" 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": if gr_title and gr_title != "tous":
title += " %s" % gr_title title += " %s" % gr_title
caption = title caption = title
html_next_section = "" html_next_section = ""
if format == "pdf" or format == "bordereau": if fmt == "pdf" or fmt == "bordereau":
caption = "" # same as pdf_title caption = "" # same as pdf_title
pdf_title = title pdf_title = title
html_title = f"""<h2 class="formsemestre">Notes {module.type_name()} <a href="{ html_title = f"""<h2 class="formsemestre">Notes {module.type_name()} <a href="{
@ -580,17 +580,17 @@ def _make_table_notes(
origin=f"Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}", origin=f"Généré par {sco_version.SCONAME} le {scu.timedate_human_repr()}",
caption=caption, caption=caption,
html_next_section=html_next_section, html_next_section=html_next_section,
page_title="Notes de " + sem["titremois"], page_title="Notes de " + formsemestre.titre_mois(),
html_title=html_title, html_title=html_title,
pdf_title=pdf_title, pdf_title=pdf_title,
html_class="notes_evaluation", html_class="notes_evaluation",
preferences=sco_preferences.SemPreferences(modimpl_o["formsemestre_id"]), preferences=sco_preferences.SemPreferences(formsemestre.id),
# html_generate_cells=False # la derniere ligne (moyennes) est incomplete # html_generate_cells=False # la derniere ligne (moyennes) est incomplete
) )
if format == "bordereau": if fmt == "bordereau":
format = "pdf" fmt = "pdf"
t = tab.make_page(format=format, with_html_headers=False) t = tab.make_page(format=fmt, with_html_headers=False)
if format != "html": if fmt != "html":
return t return t
if len(evals) > 1: if len(evals) > 1:
@ -599,7 +599,8 @@ def _make_table_notes(
if not e["eval_state"]["evalcomplete"]: if not e["eval_state"]["evalcomplete"]:
all_complete = False all_complete = False
if all_complete: if all_complete:
eval_info = '<span class="eval_info"><span class="eval_complete">Evaluations prises en compte dans les moyennes.</span>' eval_info = """<span class="eval_info"><span class="eval_complete">Évaluations
prises en compte dans les moyennes.</span>"""
else: else:
eval_info = """<span class="eval_info help"> eval_info = """<span class="eval_info help">
Les évaluations en vert et orange sont prises en compte dans les moyennes. Les évaluations en vert et orange sont prises en compte dans les moyennes.

View File

@ -367,7 +367,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
H.append("</td></tr></table>") H.append("</td></tr></table>")
# #
if not modimpl.check_apc_conformity(): if not modimpl.check_apc_conformity(nt):
H.append( H.append(
"""<div class="warning conformite">Les poids des évaluations de ce module ne sont """<div class="warning conformite">Les poids des évaluations de ce module ne sont
pas encore conformes au PN. pas encore conformes au PN.