diff --git a/app/comp/res_but.py b/app/comp/res_but.py index c5267596a4..f70ed0b086 100644 --- a/app/comp/res_but.py +++ b/app/comp/res_but.py @@ -6,6 +6,7 @@ """Résultats semestres BUT """ +import numpy as np import pandas as pd from app.comp import moy_ue, moy_sem, inscr_mod @@ -113,7 +114,9 @@ class ResultatsSemestreBUT(NotesTableCompat): mod_idx = self.modimpl_coefs_df.columns.get_loc(moduleimpl_id) etud_idx = self.etud_index[etudid] # moyenne sur les UE: - return self.sem_cube[etud_idx, mod_idx].mean() + if len(self.sem_cube[etud_idx, mod_idx]): + return np.nanmean(self.sem_cube[etud_idx, mod_idx]) + return np.nan def compute_etud_ue_coef(self, etudid: int, ue: UniteEns) -> float: """Détermine le coefficient de l'UE pour cet étudiant. diff --git a/app/comp/res_common.py b/app/comp/res_common.py index 09d3ed75f0..1aa993e853 100644 --- a/app/comp/res_common.py +++ b/app/comp/res_common.py @@ -216,11 +216,24 @@ class ResultatsSemestre(ResultatsCache): def get_etud_ue_status(self, etudid: int, ue_id: int) -> dict: """L'état de l'UE pour cet étudiant. - Result: dict + L'UE doit être du semestre. + Result: dict. """ if not self.validations: self.validations = res_sem.load_formsemestre_validations(self.formsemestre) ue = UniteEns.query.get(ue_id) # TODO cacher nos UEs ? + if ue.type == UE_SPORT: + return { + "is_capitalized": False, + "is_external": False, + "coef_ue": 0.0, + "cur_moy_ue": 0.0, + "moy": 0.0, + "event_date": None, + "ue": ue.to_dict(), + "formsemestre_id": None, + "capitalized_ue_id": None, + } cur_moy_ue = self.etud_moy_ue[ue_id][etudid] moy_ue = cur_moy_ue is_capitalized = False @@ -464,7 +477,7 @@ class NotesTableCompat(ResultatsSemestre): ects_pot += ue.ects return { "ects_pot": ects_pot, - "ects_fond": 0.0, # not implemented (anciennemment pour école ingé) + "ects_pot_fond": 0.0, # not implemented (anciennemment pour école ingé) } def get_etud_rang(self, etudid: int): diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py index 932e3fecb3..9ed1636a4f 100644 --- a/app/models/formsemestre.py +++ b/app/models/formsemestre.py @@ -132,7 +132,47 @@ class FormSemestre(db.Model): else: d["date_fin"] = d["date_fin_iso"] = "" d["responsables"] = [u.id for u in self.responsables] + return d + def get_infos_dict(self) -> dict: + """Un dict avec des informations sur le semestre + pour les bulletins et autres templates + (contenu compatible scodoc7 / anciens templates) + """ + d = self.to_dict() + d["anneescolaire"] = self.annee_scolaire_str() + d["annee_debut"] = str(self.date_debut.year) + d["annee"] = d["annee_debut"] + d["annee_fin"] = str(self.date_fin.year) + d["mois_debut_ord"] = self.date_debut.month + d["mois_fin_ord"] = self.date_fin.month + # La période: considère comme "S1" (ou S3) les débuts en aout-sept-octobre + # devrait sans doute pouvoir etre changé... + if self.date_debut.month >= 8 and self.date_debut.month <= 10: + d["periode"] = 1 # typiquement, début en septembre: S1, S3... + else: + d["periode"] = 2 # typiquement, début en février: S2, S4... + d["titre_num"] = self.titre_num + d["titreannee"] = "%s %s %s" % ( + d["titre_num"], + self.modalite or "", + self.date_debut.year, + ) + if d["annee_fin"] != d["annee_debut"]: + d["titreannee"] += "-" + str(d["annee_fin"]) + d["annee"] += "-" + str(d["annee_fin"]) + d["mois_debut"] = f"{self.date_debut.month} {self.date_debut.year}" + d["mois_fin"] = f"{self.date_fin.month} {self.date_fin.year}" + d["titremois"] = "%s %s (%s - %s)" % ( + d["titre_num"], + self.modalite or "", + d["mois_debut"], + d["mois_fin"], + ) + d["session_id"] = self.session_id() + d["etapes"] = self.etapes_apo_vdi() + d["etapes_apo_str"] = self.etapes_apo_str() + d["responsables"] = [u.id for u in self.responsables] # liste des ids return d def query_ues(self, with_sport=False) -> flask_sqlalchemy.BaseQuery: @@ -231,6 +271,11 @@ class FormSemestre(db.Model): not self.semestre_id % 2 and self.date_debut.month > 6 ) + def etapes_apo_vdi(self) -> list[ApoEtapeVDI]: + "Liste des vdis" + # was read_formsemestre_etapes + return [e.as_apovdi() for e in self.etapes if e.etape_apo] + def etapes_apo_str(self) -> str: """Chaine décrivant les étapes de ce semestre ex: "V1RT, V1RT3, V1RT4" diff --git a/app/models/modules.py b/app/models/modules.py index ac82b127e5..393cc8c0f4 100644 --- a/app/models/modules.py +++ b/app/models/modules.py @@ -63,6 +63,7 @@ class Module(db.Model): e["numero"] = 0 if self.numero is None else self.numero e["coefficient"] = 0.0 if self.coefficient is None else self.coefficient e["module_type"] = 0 if self.module_type is None else self.module_type + e["code_apogee"] = e["code_apogee"] or "" # pas de None return e def is_apc(self): diff --git a/app/models/ues.py b/app/models/ues.py index 3497414c0e..09469fb051 100644 --- a/app/models/ues.py +++ b/app/models/ues.py @@ -62,6 +62,7 @@ class UniteEns(db.Model): e["numero"] = e["numero"] if e["numero"] else 0 e["ects"] = e["ects"] if e["ects"] else 0.0 e["coefficient"] = e["coefficient"] if e["coefficient"] else 0.0 + e["code_apogee"] = e["code_apogee"] or "" # pas de None return e def is_locked(self): diff --git a/app/scodoc/sco_apogee_csv.py b/app/scodoc/sco_apogee_csv.py index 04a2fe2c56..4cae177240 100644 --- a/app/scodoc/sco_apogee_csv.py +++ b/app/scodoc/sco_apogee_csv.py @@ -413,7 +413,7 @@ class ApoEtud(dict): # Elements UE decisions_ue = nt.get_etud_decision_ues(etudid) for ue in nt.get_ues_stat_dict(): - if code in ue["code_apogee"].split(","): + if ue["code_apogee"] and code in ue["code_apogee"].split(","): if self.export_res_ues: if decisions_ue and ue["ue_id"] in decisions_ue: ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"]) @@ -434,7 +434,9 @@ class ApoEtud(dict): modimpls = nt.get_modimpls_dict() module_code_found = False for modimpl in modimpls: - if code in modimpl["module"]["code_apogee"].split(","): + if modimpl["module"]["code_apogee"] and code in modimpl["module"][ + "code_apogee" + ].split(","): n = nt.get_etud_mod_moy(modimpl["moduleimpl_id"], etudid) if n != "NI" and self.export_res_modules: return dict(N=_apo_fmt_note(n), B=20, J="", R="") @@ -947,13 +949,15 @@ class ApoData(object): # associé à une UE: nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"]) for ue in nt.get_ues_stat_dict(): - if code in ue["code_apogee"].split(","): + if ue["code_apogee"] and code in ue["code_apogee"].split(","): s.add(code) continue # associé à un module: modimpls = nt.get_modimpls_dict() for modimpl in modimpls: - if code in modimpl["module"]["code_apogee"].split(","): + if modimpl["module"]["code_apogee"] and code in modimpl["module"][ + "code_apogee" + ].split(","): s.add(code) continue # log('codes_by_sem=%s' % pprint.pformat(codes_by_sem)) diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py index d1127110c4..37299c3c38 100644 --- a/app/scodoc/sco_bulletins.py +++ b/app/scodoc/sco_bulletins.py @@ -148,7 +148,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"): I = scu.DictDefault(defaultvalue="") I["etudid"] = etudid I["formsemestre_id"] = formsemestre_id - I["sem"] = nt.sem + I["sem"] = formsemestre.get_infos_dict() I["server_name"] = request.url_root # Formation et parcours diff --git a/app/scodoc/sco_bulletins_pdf.py b/app/scodoc/sco_bulletins_pdf.py index 4e81ce7add..2195d1eef2 100644 --- a/app/scodoc/sco_bulletins_pdf.py +++ b/app/scodoc/sco_bulletins_pdf.py @@ -141,7 +141,7 @@ def process_field(field, cdict, style, suppress_empty_pars=False, format="pdf"): except: log("process_field: invalid format=%s" % field) text = ( - "format invalide !" + "format invalide !" + traceback.format_exc() + "" ) diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py index e835f1dd82..425d139461 100644 --- a/app/scodoc/sco_formsemestre_validation.py +++ b/app/scodoc/sco_formsemestre_validation.py @@ -702,17 +702,14 @@ def formsemestre_recap_parcours_table( ) # total ECTS (affiché sous la moyenne générale) H.append( - 'ECTS:%g %g' - % (etud_ects_infos["ects_pot"], etud_ects_infos["ects_pot_fond"]) + 'ECTS:%g' + % (etud_ects_infos["ects_pot"]) ) H.append('') # ECTS validables dans chaque UE for ue in ues: ue_status = nt.get_etud_ue_status(etudid, ue["ue_id"]) - H.append( - '%g %g' - % (ue_status["ects_pot"], ue_status["ects_pot_fond"]) - ) + H.append('%g' % (ue_status["ects_pot"])) H.append("") H.append("") diff --git a/app/scodoc/sco_recapcomplet.py b/app/scodoc/sco_recapcomplet.py index 16830b0811..3b45330d8a 100644 --- a/app/scodoc/sco_recapcomplet.py +++ b/app/scodoc/sco_recapcomplet.py @@ -85,8 +85,8 @@ def formsemestre_recapcomplet( sem = sco_formsemestre.get_formsemestre(formsemestre_id) F = sco_formations.formation_list(args={"formation_id": sem["formation_id"]})[0] parcours = sco_codes_parcours.get_parcours_from_code(F["type_parcours"]) - # Options pour APC BUT: cache les modules par défaut car moyenne n'a pas de sens formsemestre = FormSemestre.query.get_or_404(formsemestre_id) + # Pour APC (BUT): cache les modules par défaut car moyenne n'a pas de sens if formsemestre.formation.is_apc(): hidemodules = True # traduit du DTML @@ -312,10 +312,7 @@ def make_formsemestre_recapcomplet( nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre) modimpls = formsemestre.modimpls_sorted ues = nt.get_ues_stat_dict() # incluant le(s) UE de sport - # - # if formsemestre.formation.is_apc(): - # nt.apc_recompute_moyennes() - # + partitions, partitions_etud_groups = sco_groups.get_formsemestre_groups( formsemestre_id ) diff --git a/sco_version.py b/sco_version.py index 84e9b0f57b..a75f9a9403 100644 --- a/sco_version.py +++ b/sco_version.py @@ -1,7 +1,7 @@ # -*- mode: python -*- # -*- coding: utf-8 -*- -SCOVERSION = "9.2.0a" +SCOVERSION = "9.1.50a" SCONAME = "ScoDoc"