diff --git a/app/scodoc/sco_bulletins_json.py b/app/scodoc/sco_bulletins_json.py index e0cf10442..f4e067234 100644 --- a/app/scodoc/sco_bulletins_json.py +++ b/app/scodoc/sco_bulletins_json.py @@ -36,6 +36,7 @@ from flask import abort from app.comp import res_sem from app.comp.res_compat import NotesTableCompat from app.models import but_validations +from app.models import Matiere, ModuleImpl, UniteEns from app.models.etudiants import Identite from app.models.formsemestre import FormSemestre @@ -50,6 +51,7 @@ from app.scodoc import sco_groups from app.scodoc import sco_photos from app.scodoc import sco_preferences from app.scodoc import sco_etud +from app.scodoc.sco_preferences import SemPreferences from app.scodoc.sco_xml import quote_xml_attr # -------- Bulletin en JSON @@ -88,9 +90,21 @@ def formsemestre_bulletinetud_published_dict( ) -> dict: """Dictionnaire representant les informations _publiees_ du bulletin de notes Utilisé pour JSON, devrait l'être aussi pour XML. (todo) + + version: + short (sans les évaluations) + long (avec les évaluations) + + short_mat (sans évaluations, et structuration en matières) + long_mat (avec évaluations, et structuration en matières) """ from app.scodoc import sco_bulletins + with_matieres = False + if version.endswith("_mat"): + version = version[:-4] # enlève le "_mat" + with_matieres = True + formsemestre = FormSemestre.query.get_or_404(formsemestre_id) prefs = sco_preferences.SemPreferences(formsemestre_id) etud = Identite.query.get(etudid) @@ -224,107 +238,41 @@ def formsemestre_bulletinetud_published_dict( code_apogee=quote_xml_attr(ue["code_apogee"]), ) d["ue"].append(u) - u["module"] = [] - # Liste les modules de l'UE - ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]] - for modimpl in ue_modimpls: - mod_moy = scu.fmt_note( - nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid) + + if with_matieres: + u["module"] = [] + # Structure UE/Matière/Module + # Recodé en 2022 + ue = UniteEns.query.get(ue["ue_id"]) + u["matiere"] = [ + { + "matiere_id": mat.id, + "note": scu.fmt_note(nt.get_etud_mat_moy(mat.id, etudid)), + "titre": mat.titre, + "module": _list_modimpls( + nt, + etudid, + [ + mod + for mod in modimpls + if mod["module"]["matiere_id"] == mat.id + ], + prefs, + version, + ), + } + for mat in ue.matieres.order_by(Matiere.numero) + ] + + else: + # Liste les modules de l'UE + u["module"] = _list_modimpls( + nt, + etudid, + [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]], + prefs, + version, ) - if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit - continue - mod = modimpl["module"] - # if mod['ects'] is None: - # ects = '' - # else: - # ects = str(mod['ects']) - modstat = nt.get_mod_stats(modimpl["moduleimpl_id"]) - - m = dict( - id=modimpl["moduleimpl_id"], - code=mod["code"], - coefficient=mod["coefficient"], - numero=mod["numero"], - titre=quote_xml_attr(mod["titre"]), - abbrev=quote_xml_attr(mod["abbrev"]), - # ects=ects, ects des modules maintenant inutilisés - note=dict(value=mod_moy), - code_apogee=quote_xml_attr(mod["code_apogee"]), - matiere_id=mod["matiere_id"], - ) - m["note"].update(modstat) - for k in ("min", "max", "moy"): # formatte toutes les notes - m["note"][k] = scu.fmt_note(m["note"][k]) - - u["module"].append(m) - if prefs["bul_show_mod_rangs"] and nt.mod_rangs is not None: - m["rang"] = dict( - value=nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid] - ) - m["effectif"] = dict(value=nt.mod_rangs[modimpl["moduleimpl_id"]][1]) - - # --- notes de chaque eval: - evals = nt.get_evals_in_mod(modimpl["moduleimpl_id"]) - m["evaluation"] = [] - if version != "short": - for e in evals: - if e["visibulletin"] or version == "long": - val = e["notes"].get(etudid, {"value": "NP"})["value"] - # nb: val est NA si etud démissionnaire - val = scu.fmt_note(val, note_max=e["note_max"]) - eval_dict = dict( - jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True), - heure_debut=ndb.TimetoISO8601( - e["heure_debut"], null_is_empty=True - ), - heure_fin=ndb.TimetoISO8601( - e["heure_fin"], null_is_empty=True - ), - coefficient=e["coefficient"], - evaluation_type=e["evaluation_type"], - # CM : ajout pour permettre de faire le lien sur - # les bulletins en ligne avec l'évaluation: - evaluation_id=e["evaluation_id"], - description=quote_xml_attr(e["description"]), - note=val, - ) - if prefs["bul_show_minmax_eval"] or prefs["bul_show_moypromo"]: - etat = sco_evaluations.do_evaluation_etat( - e["evaluation_id"] - ) - if prefs["bul_show_minmax_eval"]: - eval_dict["min"] = scu.fmt_note(etat["mini"]) - eval_dict["max"] = scu.fmt_note(etat["maxi"]) - if prefs["bul_show_moypromo"]: - eval_dict["moy"] = scu.fmt_note(etat["moy"]) - - m["evaluation"].append(eval_dict) - - # Evaluations incomplètes ou futures: - complete_eval_ids = set([e["evaluation_id"] for e in evals]) - if prefs["bul_show_all_evals"]: - all_evals = sco_evaluation_db.do_evaluation_list( - args={"moduleimpl_id": modimpl["moduleimpl_id"]} - ) - all_evals.reverse() # plus ancienne d'abord - for e in all_evals: - if e["evaluation_id"] not in complete_eval_ids: - m["evaluation"].append( - dict( - jour=ndb.DateDMYtoISO( - e["jour"], null_is_empty=True - ), - heure_debut=ndb.TimetoISO8601( - e["heure_debut"], null_is_empty=True - ), - heure_fin=ndb.TimetoISO8601( - e["heure_fin"], null_is_empty=True - ), - coefficient=e["coefficient"], - description=quote_xml_attr(e["description"]), - incomplete="1", - ) - ) # UE capitalisee (listee seulement si meilleure que l'UE courante) if ue_status["is_capitalized"]: @@ -345,23 +293,15 @@ def formsemestre_bulletinetud_published_dict( ) ) - # --- Matières: - # for matiere_id in nt.moyennes_matieres: - d["matiere"] = [ - { - "matiere_id": matiere_id, - "note": scu.fmt_note(nt.get_etud_mat_moy(matiere_id, etudid)), - } - for matiere_id in nt.moyennes_matieres - ] # --- Absences if prefs["bul_show_abs"]: nbabs, nbabsjust = sco_abs.get_abs_count(etudid, sem) d["absences"] = dict(nbabs=nbabs, nbabsjust=nbabsjust) - # --- Decision Jury + # --- Décision Jury d.update(dict_decision_jury(etud, formsemestre, with_decisions=xml_with_decisions)) - # --- Appreciations + + # --- Appréciations cnx = ndb.GetDBConnexion() apprecs = sco_etud.appreciations_list( cnx, args={"etudid": etudid, "formsemestre_id": formsemestre_id} @@ -379,6 +319,107 @@ def formsemestre_bulletinetud_published_dict( return d +def _list_modimpls( + nt: NotesTableCompat, + etudid: int, + modimpls: list[ModuleImpl], + prefs: SemPreferences, + version: str, +) -> list[dict]: + modules_dict = [] + for modimpl in modimpls: + mod_moy = scu.fmt_note(nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid)) + if mod_moy == "NI": # ne mentionne pas les modules ou n'est pas inscrit + continue + mod = modimpl["module"] + # if mod['ects'] is None: + # ects = '' + # else: + # ects = str(mod['ects']) + modstat = nt.get_mod_stats(modimpl["moduleimpl_id"]) + + mod_dict = dict( + id=modimpl["moduleimpl_id"], + code=mod["code"], + coefficient=mod["coefficient"], + numero=mod["numero"], + titre=quote_xml_attr(mod["titre"]), + abbrev=quote_xml_attr(mod["abbrev"]), + # ects=ects, ects des modules maintenant inutilisés + note=dict(value=mod_moy), + code_apogee=quote_xml_attr(mod["code_apogee"]), + matiere_id=mod["matiere_id"], + ) + mod_dict["note"].update(modstat) + for k in ("min", "max", "moy"): # formatte toutes les notes + mod_dict["note"][k] = scu.fmt_note(mod_dict["note"][k]) + + if prefs["bul_show_mod_rangs"] and nt.mod_rangs is not None: + mod_dict["rang"] = dict( + value=nt.mod_rangs[modimpl["moduleimpl_id"]][0][etudid] + ) + mod_dict["effectif"] = dict(value=nt.mod_rangs[modimpl["moduleimpl_id"]][1]) + + # --- notes de chaque eval: + evals = nt.get_evals_in_mod(modimpl["moduleimpl_id"]) + mod_dict["evaluation"] = [] + if version != "short": + for e in evals: + if e["visibulletin"] or version == "long": + val = e["notes"].get(etudid, {"value": "NP"})["value"] + # nb: val est NA si etud démissionnaire + val = scu.fmt_note(val, note_max=e["note_max"]) + eval_dict = dict( + jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True), + heure_debut=ndb.TimetoISO8601( + e["heure_debut"], null_is_empty=True + ), + heure_fin=ndb.TimetoISO8601(e["heure_fin"], null_is_empty=True), + coefficient=e["coefficient"], + evaluation_type=e["evaluation_type"], + # CM : ajout pour permettre de faire le lien sur + # les bulletins en ligne avec l'évaluation: + evaluation_id=e["evaluation_id"], + description=quote_xml_attr(e["description"]), + note=val, + ) + if prefs["bul_show_minmax_eval"] or prefs["bul_show_moypromo"]: + etat = sco_evaluations.do_evaluation_etat(e["evaluation_id"]) + if prefs["bul_show_minmax_eval"]: + eval_dict["min"] = scu.fmt_note(etat["mini"]) + eval_dict["max"] = scu.fmt_note(etat["maxi"]) + if prefs["bul_show_moypromo"]: + eval_dict["moy"] = scu.fmt_note(etat["moy"]) + + mod_dict["evaluation"].append(eval_dict) + + # Evaluations incomplètes ou futures: + complete_eval_ids = set([e["evaluation_id"] for e in evals]) + if prefs["bul_show_all_evals"]: + all_evals = sco_evaluation_db.do_evaluation_list( + args={"moduleimpl_id": modimpl["moduleimpl_id"]} + ) + all_evals.reverse() # plus ancienne d'abord + for e in all_evals: + if e["evaluation_id"] not in complete_eval_ids: + mod_dict["evaluation"].append( + dict( + jour=ndb.DateDMYtoISO(e["jour"], null_is_empty=True), + heure_debut=ndb.TimetoISO8601( + e["heure_debut"], null_is_empty=True + ), + heure_fin=ndb.TimetoISO8601( + e["heure_fin"], null_is_empty=True + ), + coefficient=e["coefficient"], + description=quote_xml_attr(e["description"]), + incomplete="1", + ) + ) + modules_dict.append(mod_dict) + return modules_dict + + def dict_decision_jury( etud: Identite, formsemestre: FormSemestre, with_decisions: bool = False ) -> dict: