Merge branch 'refactor_nt' of https://scodoc.org/git/ScoDoc/ScoDoc into entreprises

This commit is contained in:
Arthur ZHU 2022-02-10 16:50:46 +01:00
commit c983ed6d99
19 changed files with 257 additions and 148 deletions

View File

@ -9,6 +9,7 @@
import datetime import datetime
from flask import url_for, g from flask import url_for, g
from app.models.formsemestre import FormSemestre
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.scodoc import sco_bulletins_json from app.scodoc import sco_bulletins_json
@ -18,30 +19,35 @@ from app.scodoc.sco_utils import fmt_note
from app.comp.res_but import ResultatsSemestreBUT from app.comp.res_but import ResultatsSemestreBUT
class BulletinBUT(ResultatsSemestreBUT): class BulletinBUT:
"""Génération du bulletin BUT. """Génération du bulletin BUT.
Cette classe génère des dictionnaires avec toutes les informations Cette classe génère des dictionnaires avec toutes les informations
du bulletin, qui sont immédiatement traduisibles en JSON. du bulletin, qui sont immédiatement traduisibles en JSON.
""" """
def __init__(self, formsemestre: FormSemestre):
""" """
self.res = ResultatsSemestreBUT(formsemestre)
def etud_ue_mod_results(self, etud, ue, modimpls) -> dict: def etud_ue_mod_results(self, etud, ue, modimpls) -> dict:
"dict synthèse résultats dans l'UE pour les modules indiqués" "dict synthèse résultats dans l'UE pour les modules indiqués"
res = self.res
d = {} d = {}
etud_idx = self.etud_index[etud.id] etud_idx = res.etud_index[etud.id]
if ue.type != UE_SPORT: if ue.type != UE_SPORT:
ue_idx = self.modimpl_coefs_df.index.get_loc(ue.id) ue_idx = res.modimpl_coefs_df.index.get_loc(ue.id)
etud_moy_module = self.sem_cube[etud_idx] # module x UE etud_moy_module = res.sem_cube[etud_idx] # module x UE
for modimpl in modimpls: for modimpl in modimpls:
if self.modimpl_inscr_df[modimpl.id][etud.id]: # si inscrit if res.modimpl_inscr_df[modimpl.id][etud.id]: # si inscrit
if ue.type != UE_SPORT: if ue.type != UE_SPORT:
coef = self.modimpl_coefs_df[modimpl.id][ue.id] coef = res.modimpl_coefs_df[modimpl.id][ue.id]
if coef > 0: if coef > 0:
d[modimpl.module.code] = { d[modimpl.module.code] = {
"id": modimpl.id, "id": modimpl.id,
"coef": coef, "coef": coef,
"moyenne": fmt_note( "moyenne": fmt_note(
etud_moy_module[ etud_moy_module[
self.modimpl_coefs_df.columns.get_loc(modimpl.id) res.modimpl_coefs_df.columns.get_loc(modimpl.id)
][ue_idx] ][ue_idx]
), ),
} }
@ -55,40 +61,39 @@ class BulletinBUT(ResultatsSemestreBUT):
def etud_ue_results(self, etud, ue): def etud_ue_results(self, etud, ue):
"dict synthèse résultats UE" "dict synthèse résultats UE"
res = self.res
d = { d = {
"id": ue.id, "id": ue.id,
"titre": ue.titre, "titre": ue.titre,
"numero": ue.numero, "numero": ue.numero,
"type": ue.type, "type": ue.type,
"ECTS": { "ECTS": {
"acquis": 0, # XXX TODO voir jury "acquis": 0, # XXX TODO voir jury #sco92
"total": ue.ects, "total": ue.ects,
}, },
"color": ue.color, "color": ue.color,
"competence": None, # XXX TODO lien avec référentiel "competence": None, # XXX TODO lien avec référentiel
"moyenne": None, "moyenne": None,
# Le bonus sport appliqué sur cette UE # Le bonus sport appliqué sur cette UE
"bonus": fmt_note(self.bonus_ues[ue.id][etud.id]) "bonus": fmt_note(res.bonus_ues[ue.id][etud.id])
if self.bonus_ues is not None and ue.id in self.bonus_ues if res.bonus_ues is not None and ue.id in res.bonus_ues
else fmt_note(0.0), else fmt_note(0.0),
"malus": self.malus[ue.id][etud.id], "malus": res.malus[ue.id][etud.id],
"capitalise": None, # "AAAA-MM-JJ" TODO "capitalise": None, # "AAAA-MM-JJ" TODO #sco92
"ressources": self.etud_ue_mod_results(etud, ue, self.ressources), "ressources": self.etud_ue_mod_results(etud, ue, res.ressources),
"saes": self.etud_ue_mod_results(etud, ue, self.saes), "saes": self.etud_ue_mod_results(etud, ue, res.saes),
} }
if ue.type != UE_SPORT: if ue.type != UE_SPORT:
if sco_preferences.get_preference( if sco_preferences.get_preference("bul_show_ue_rangs", res.formsemestre.id):
"bul_show_ue_rangs", self.formsemestre.id rangs, effectif = res.ue_rangs[ue.id]
):
rangs, effectif = self.ue_rangs[ue.id]
rang = rangs[etud.id] rang = rangs[etud.id]
else: else:
rang, effectif = "", 0 rang, effectif = "", 0
d["moyenne"] = { d["moyenne"] = {
"value": fmt_note(self.etud_moy_ue[ue.id][etud.id]), "value": fmt_note(res.etud_moy_ue[ue.id][etud.id]),
"min": fmt_note(self.etud_moy_ue[ue.id].min()), "min": fmt_note(res.etud_moy_ue[ue.id].min()),
"max": fmt_note(self.etud_moy_ue[ue.id].max()), "max": fmt_note(res.etud_moy_ue[ue.id].max()),
"moy": fmt_note(self.etud_moy_ue[ue.id].mean()), "moy": fmt_note(res.etud_moy_ue[ue.id].mean()),
"rang": rang, "rang": rang,
"total": effectif, # nb etud avec note dans cette UE "total": effectif, # nb etud avec note dans cette UE
} }
@ -98,7 +103,7 @@ class BulletinBUT(ResultatsSemestreBUT):
d["bonus_description"] = self.etud_bonus_description(etud.id) d["bonus_description"] = self.etud_bonus_description(etud.id)
modimpls_spo = [ modimpls_spo = [
modimpl modimpl
for modimpl in self.formsemestre.modimpls_sorted for modimpl in res.formsemestre.modimpls_sorted
if modimpl.module.ue.type == UE_SPORT if modimpl.module.ue.type == UE_SPORT
] ]
d["modules"] = self.etud_mods_results(etud, modimpls_spo) d["modules"] = self.etud_mods_results(etud, modimpls_spo)
@ -107,6 +112,7 @@ class BulletinBUT(ResultatsSemestreBUT):
def etud_mods_results(self, etud, modimpls) -> dict: def etud_mods_results(self, etud, modimpls) -> dict:
"""dict synthèse résultats des modules indiqués, """dict synthèse résultats des modules indiqués,
avec évaluations de chacun.""" avec évaluations de chacun."""
res = self.res
d = {} d = {}
# etud_idx = self.etud_index[etud.id] # etud_idx = self.etud_index[etud.id]
for modimpl in modimpls: for modimpl in modimpls:
@ -117,14 +123,15 @@ class BulletinBUT(ResultatsSemestreBUT):
# np.nanmean(self.sem_cube[:, mod_idx, :], axis=1), # np.nanmean(self.sem_cube[:, mod_idx, :], axis=1),
# copy=False, # copy=False,
# ) # )
# except RuntimeWarning: # all nans in np.nanmean (sur certains etuds sans notes valides) # except RuntimeWarning:
# # all nans in np.nanmean (sur certains etuds sans notes valides)
# pass # pass
# try: # try:
# moy_indicative_mod = np.nanmean(self.sem_cube[etud_idx, mod_idx]) # moy_indicative_mod = np.nanmean(self.sem_cube[etud_idx, mod_idx])
# except RuntimeWarning: # all nans in np.nanmean # except RuntimeWarning: # all nans in np.nanmean
# pass # pass
modimpl_results = self.modimpls_results[modimpl.id] modimpl_results = res.modimpls_results[modimpl.id]
if self.modimpl_inscr_df[modimpl.id][etud.id]: # si inscrit if res.modimpl_inscr_df[modimpl.id][etud.id]: # si inscrit
d[modimpl.module.code] = { d[modimpl.module.code] = {
"id": modimpl.id, "id": modimpl.id,
"titre": modimpl.module.titre, "titre": modimpl.module.titre,
@ -135,7 +142,8 @@ class BulletinBUT(ResultatsSemestreBUT):
moduleimpl_id=modimpl.id, moduleimpl_id=modimpl.id,
), ),
"moyenne": { "moyenne": {
# # moyenne indicative de module: moyenne des UE, ignorant celles sans notes (nan) # # moyenne indicative de module: moyenne des UE,
# # ignorant celles sans notes (nan)
# "value": fmt_note(moy_indicative_mod), # "value": fmt_note(moy_indicative_mod),
# "min": fmt_note(moyennes_etuds.min()), # "min": fmt_note(moyennes_etuds.min()),
# "max": fmt_note(moyennes_etuds.max()), # "max": fmt_note(moyennes_etuds.max()),
@ -153,7 +161,7 @@ class BulletinBUT(ResultatsSemestreBUT):
def etud_eval_results(self, etud, e) -> dict: def etud_eval_results(self, etud, e) -> dict:
"dict resultats d'un étudiant à une évaluation" "dict resultats d'un étudiant à une évaluation"
# eval_notes est une pd.Series avec toutes les notes des étudiants inscrits # eval_notes est une pd.Series avec toutes les notes des étudiants inscrits
eval_notes = self.modimpls_results[e.moduleimpl_id].evals_notes[e.id] eval_notes = self.res.modimpls_results[e.moduleimpl_id].evals_notes[e.id]
notes_ok = eval_notes.where(eval_notes > scu.NOTES_ABSENCE).dropna() notes_ok = eval_notes.where(eval_notes > scu.NOTES_ABSENCE).dropna()
d = { d = {
"id": e.id, "id": e.id,
@ -182,18 +190,18 @@ class BulletinBUT(ResultatsSemestreBUT):
def etud_bonus_description(self, etudid): def etud_bonus_description(self, etudid):
"""description du bonus affichée dans la section "UE bonus".""" """description du bonus affichée dans la section "UE bonus"."""
if self.bonus_ues is None or self.bonus_ues.shape[1] == 0: res = self.res
if res.bonus_ues is None or res.bonus_ues.shape[1] == 0:
return "" return ""
import random
bonus_vect = self.bonus_ues.loc[etudid] bonus_vect = res.bonus_ues.loc[etudid]
if bonus_vect.nunique() > 1: if bonus_vect.nunique() > 1:
# détail UE par UE # détail UE par UE
details = [ details = [
f"{fmt_note(bonus_vect[ue.id])} sur {ue.acronyme}" f"{fmt_note(bonus_vect[ue.id])} sur {ue.acronyme}"
for ue in self.ues for ue in res.ues
if self.modimpls_in_ue(ue.id, etudid) if res.modimpls_in_ue(ue.id, etudid)
and ue.id in self.bonus_ues and ue.id in res.bonus_ues
and bonus_vect[ue.id] > 0.0 and bonus_vect[ue.id] > 0.0
] ]
if details: if details:
@ -208,8 +216,9 @@ class BulletinBUT(ResultatsSemestreBUT):
Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai
(bulletins non publiés). (bulletins non publiés).
""" """
res = self.res
etat_inscription = etud.etat_inscription(formsemestre.id) etat_inscription = etud.etat_inscription(formsemestre.id)
nb_inscrits = self.get_inscriptions_counts()[scu.INSCRIT] nb_inscrits = self.res.get_inscriptions_counts()[scu.INSCRIT]
published = (not formsemestre.bul_hide_xml) or force_publishing published = (not formsemestre.bul_hide_xml) or force_publishing
d = { d = {
"version": "0", "version": "0",
@ -235,7 +244,7 @@ class BulletinBUT(ResultatsSemestreBUT):
"etapes": [str(x.etape_apo) for x in formsemestre.etapes if x.etape_apo], "etapes": [str(x.etape_apo) for x in formsemestre.etapes if x.etape_apo],
"date_debut": formsemestre.date_debut.isoformat(), "date_debut": formsemestre.date_debut.isoformat(),
"date_fin": formsemestre.date_fin.isoformat(), "date_fin": formsemestre.date_fin.isoformat(),
"annee_universitaire": self.formsemestre.annee_scolaire_str(), "annee_universitaire": formsemestre.annee_scolaire_str(),
"numero": formsemestre.semestre_id, "numero": formsemestre.semestre_id,
"inscription": "", # inutilisé mais nécessaire pour le js de Seb. "inscription": "", # inutilisé mais nécessaire pour le js de Seb.
"groupes": [], # XXX TODO "groupes": [], # XXX TODO
@ -251,25 +260,25 @@ class BulletinBUT(ResultatsSemestreBUT):
semestre_infos.update( semestre_infos.update(
{ {
"notes": { # moyenne des moyennes générales du semestre "notes": { # moyenne des moyennes générales du semestre
"value": fmt_note(self.etud_moy_gen[etud.id]), "value": fmt_note(res.etud_moy_gen[etud.id]),
"min": fmt_note(self.etud_moy_gen.min()), "min": fmt_note(res.etud_moy_gen.min()),
"moy": fmt_note(self.etud_moy_gen.mean()), "moy": fmt_note(res.etud_moy_gen.mean()),
"max": fmt_note(self.etud_moy_gen.max()), "max": fmt_note(res.etud_moy_gen.max()),
}, },
"rang": { # classement wrt moyenne général, indicatif "rang": { # classement wrt moyenne général, indicatif
"value": self.etud_moy_gen_ranks[etud.id], "value": res.etud_moy_gen_ranks[etud.id],
"total": nb_inscrits, "total": nb_inscrits,
}, },
}, },
) )
d.update( d.update(
{ {
"ressources": self.etud_mods_results(etud, self.ressources), "ressources": self.etud_mods_results(etud, res.ressources),
"saes": self.etud_mods_results(etud, self.saes), "saes": self.etud_mods_results(etud, res.saes),
"ues": { "ues": {
ue.acronyme: self.etud_ue_results(etud, ue) ue.acronyme: self.etud_ue_results(etud, ue)
for ue in self.ues for ue in res.ues
if self.modimpls_in_ue( if self.res.modimpls_in_ue(
ue.id, etud.id ue.id, etud.id
) # si l'UE comporte des modules auxquels on est inscrit ) # si l'UE comporte des modules auxquels on est inscrit
}, },

View File

@ -9,8 +9,6 @@ from functools import cached_property
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from flask import g
from app.comp.aux_stats import StatsMoyenne from app.comp.aux_stats import StatsMoyenne
from app.comp import moy_sem from app.comp import moy_sem
from app.comp.res_cache import ResultatsCache from app.comp.res_cache import ResultatsCache
@ -20,7 +18,6 @@ from app.models import FormSemestre, Identite, ModuleImpl
from app.models import FormSemestreUECoef from app.models import FormSemestreUECoef
from app.models.ues import UniteEns from app.models.ues import UniteEns
from app.scodoc import sco_utils as scu from app.scodoc import sco_utils as scu
from app.scodoc import sco_evaluations
from app.scodoc.sco_cache import ResultatsSemestreCache from app.scodoc.sco_cache import ResultatsSemestreCache
from app.scodoc.sco_codes_parcours import UE_SPORT, ATT, DEF from app.scodoc.sco_codes_parcours import UE_SPORT, ATT, DEF
from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_exceptions import ScoValueError
@ -233,24 +230,29 @@ class ResultatsSemestre(ResultatsCache):
"ue": ue.to_dict(), "ue": ue.to_dict(),
"formsemestre_id": None, "formsemestre_id": None,
"capitalized_ue_id": None, "capitalized_ue_id": None,
"ects_pot": 0.0,
} }
cur_moy_ue = self.etud_moy_ue[ue_id][etudid] cur_moy_ue = self.etud_moy_ue[ue_id][etudid]
moy_ue = cur_moy_ue moy_ue = cur_moy_ue
is_capitalized = False is_capitalized = False
if etudid in self.validations.ue_capitalisees.index: if etudid in self.validations.ue_capitalisees.index:
ue_cap = self._get_etud_ue_cap(etudid, ue) ue_cap = self._get_etud_ue_cap(etudid, ue)
if ue_cap is not None and not ue_cap.empty: if (
if ue_cap["moy_ue"] > cur_moy_ue: ue_cap is not None
and not ue_cap.empty
and not np.isnan(ue_cap["moy_ue"])
):
if ue_cap["moy_ue"] > cur_moy_ue or np.isnan(cur_moy_ue):
moy_ue = ue_cap["moy_ue"] moy_ue = ue_cap["moy_ue"]
is_capitalized = True is_capitalized = True
if is_capitalized:
coef_ue = 1.0
coef_ue = self.etud_coef_ue_df[ue_id][etudid] coef_ue = self.etud_coef_ue_df[ue_id][etudid]
return { return {
"is_capitalized": is_capitalized, "is_capitalized": is_capitalized,
"is_external": ue_cap["is_external"] if is_capitalized else ue.is_external, "is_external": ue_cap["is_external"] if is_capitalized else ue.is_external,
"coef_ue": coef_ue, "coef_ue": coef_ue,
"ects_pot": ue.ects or 0.0,
"cur_moy_ue": cur_moy_ue, "cur_moy_ue": cur_moy_ue,
"moy": moy_ue, "moy": moy_ue,
"event_date": ue_cap["event_date"] if is_capitalized else None, "event_date": ue_cap["event_date"] if is_capitalized else None,
@ -383,7 +385,7 @@ class NotesTableCompat(ResultatsSemestre):
def compute_rangs(self): def compute_rangs(self):
"""Calcule les classements """Calcule les classements
Moyenne générale: etud_moy_gen_ranks Moyenne générale: etud_moy_gen_ranks
Par UE: Par UE (sauf ue bonus)
""" """
self.etud_moy_gen_ranks = moy_sem.comp_ranks_series(self.etud_moy_gen) self.etud_moy_gen_ranks = moy_sem.comp_ranks_series(self.etud_moy_gen)
for ue in self.formsemestre.query_ues(): for ue in self.formsemestre.query_ues():
@ -394,6 +396,37 @@ class NotesTableCompat(ResultatsSemestre):
) )
# .count() -> nb of non NaN values # .count() -> nb of non NaN values
def get_etud_ue_rang(self, ue_id, etudid) -> tuple[str, int]:
"""Le rang de l'étudiant dans cette ue
Result: rang:str, effectif:str
"""
rangs, effectif = self.ue_rangs[ue_id]
if rangs is not None:
rang = rangs[etudid]
else:
return "", ""
return rang, effectif
def etud_check_conditions_ues(self, etudid):
"""Vrai si les conditions sur les UE sont remplies.
Ne considère que les UE ayant des notes (moyenne calculée).
(les UE sans notes ne sont pas comptées comme sous la barre)
Prend en compte les éventuelles UE capitalisées.
Pour les parcours habituels, cela revient à vérifier que
les moyennes d'UE sont toutes > à leur barre (sauf celles sans notes)
Pour les parcours non standards (LP2014), cela peut être plus compliqué.
Return: True|False, message explicatif
"""
return self.parcours.check_barre_ues(
[
self.get_etud_ue_status(etudid, ue.id)
for ue in self.formsemestre.query_ues()
]
)
def get_etud_decision_ues(self, etudid: int) -> dict: def get_etud_decision_ues(self, etudid: int) -> dict:
"""Decisions du jury pour les UE de cet etudiant, ou None s'il n'y en pas eu. """Decisions du jury pour les UE de cet etudiant, ou None s'il n'y en pas eu.
Ne tient pas compte des UE capitalisées. Ne tient pas compte des UE capitalisées.
@ -449,7 +482,7 @@ class NotesTableCompat(ResultatsSemestre):
def get_etud_moy_gen(self, etudid): # -> float | str def get_etud_moy_gen(self, etudid): # -> float | str
"""Moyenne générale de cet etudiant dans ce semestre. """Moyenne générale de cet etudiant dans ce semestre.
Prend(ra) en compte les UE capitalisées. (TODO) XXX Prend en compte les UE capitalisées.
Si apc, moyenne indicative. Si apc, moyenne indicative.
Si pas de notes: 'NA' Si pas de notes: 'NA'
""" """
@ -516,6 +549,8 @@ class NotesTableCompat(ResultatsSemestre):
def get_evaluations_etats(self): def get_evaluations_etats(self):
"""[ {...evaluation et son etat...} ]""" """[ {...evaluation et son etat...} ]"""
# TODO: à moderniser # TODO: à moderniser
from app.scodoc import sco_evaluations
if not hasattr(self, "_evaluations_etats"): if not hasattr(self, "_evaluations_etats"):
self._evaluations_etats = sco_evaluations.do_evaluation_list_in_sem( self._evaluations_etats = sco_evaluations.do_evaluation_list_in_sem(
self.formsemestre.id self.formsemestre.id
@ -573,7 +608,7 @@ class NotesTableCompat(ResultatsSemestre):
""" """
table_moyennes = [] table_moyennes = []
etuds_inscriptions = self.formsemestre.etuds_inscriptions etuds_inscriptions = self.formsemestre.etuds_inscriptions
ues = self.formsemestre.query_ues() # sans bonus
for etudid in etuds_inscriptions: for etudid in etuds_inscriptions:
moy_gen = self.etud_moy_gen.get(etudid, False) moy_gen = self.etud_moy_gen.get(etudid, False)
if moy_gen is False: if moy_gen is False:
@ -584,10 +619,18 @@ class NotesTableCompat(ResultatsSemestre):
+ ["NI"] * len(self.formsemestre.modimpls_sorted) + ["NI"] * len(self.formsemestre.modimpls_sorted)
) )
else: else:
moy_ues = self.etud_moy_ue.loc[etudid] moy_ues = []
ue_is_cap = {}
for ue in ues:
ue_status = self.get_etud_ue_status(etudid, ue.id)
moy_ues.append(ue_status["moy"])
ue_is_cap[ue.id] = ue_status["is_capitalized"]
t = [moy_gen] + list(moy_ues) t = [moy_gen] + list(moy_ues)
# TODO UE capitalisées: ne pas afficher moyennes modules # Moyennes modules:
for modimpl in self.formsemestre.modimpls_sorted: for modimpl in self.formsemestre.modimpls_sorted:
if ue_is_cap.get(modimpl.module.ue.id, False):
val = "-c-"
else:
val = self.get_etud_mod_moy(modimpl.id, etudid) val = self.get_etud_mod_moy(modimpl.id, etudid)
t.append(val) t.append(val)
t.append(etudid) t.append(etudid)

View File

@ -123,6 +123,7 @@ class Identite(db.Model):
e = dict(self.__dict__) e = dict(self.__dict__)
e.pop("_sa_instance_state", None) e.pop("_sa_instance_state", None)
# ScoDoc7 output_formators: (backward compat) # ScoDoc7 output_formators: (backward compat)
e["etudid"] = self.id
e["date_naissance"] = ndb.DateISOtoDMY(e["date_naissance"]) e["date_naissance"] = ndb.DateISOtoDMY(e["date_naissance"])
return {k: e[k] or "" for k in e} # convert_null_outputs_to_empty return {k: e[k] or "" for k in e} # convert_null_outputs_to_empty

View File

@ -37,6 +37,7 @@ Created on Fri Sep 9 09:15:05 2016
""" """
from app import log from app import log
from app.models.ues import UniteEns
from app.scodoc import sco_codes_parcours from app.scodoc import sco_codes_parcours
from app.scodoc import sco_cache from app.scodoc import sco_cache
from app.scodoc import sco_tag_module from app.scodoc import sco_tag_module
@ -238,7 +239,7 @@ class SemestreTag(pe_tagtable.TableTag):
etudid etudid
) # les ue capitalisées des étudiants ) # les ue capitalisées des étudiants
ue_capitalisees_id = [ ue_capitalisees_id = [
ue["ue_id"] for ue in ue_capitalisees ue.id for ue in ue_capitalisees
] # les id des ue capitalisées ] # les id des ue capitalisées
# Si le module ne fait pas partie des UE capitalisées # Si le module ne fait pas partie des UE capitalisées
@ -260,7 +261,7 @@ class SemestreTag(pe_tagtable.TableTag):
fids_prec = [ fids_prec = [
ue["formsemestre_id"] ue["formsemestre_id"]
for ue in ue_capitalisees for ue in ue_capitalisees
if ue["ue_code"] == modimpl["ue"]["ue_code"] if ue.ue_code == modimpl["ue"]["ue_code"]
] # and ue['semestre_id'] == semestre_id] ] # and ue['semestre_id'] == semestre_id]
if len(fids_prec) > 0: if len(fids_prec) > 0:
# => le formsemestre_id du semestre dont vient la capitalisation # => le formsemestre_id du semestre dont vient la capitalisation
@ -299,10 +300,13 @@ class SemestreTag(pe_tagtable.TableTag):
return (note, coeff_norm) return (note, coeff_norm)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def get_ue_capitalisees(self, etudid): def get_ue_capitalisees(self, etudid) -> list[UniteEns]:
"""Renvoie la liste des ue_id effectivement capitalisées par un étudiant""" """Renvoie la liste des ue_id effectivement capitalisées par un étudiant"""
# return [ ue for ue in self.nt.ue_capitalisees[etudid] if self.nt.get_etud_ue_status(etudid,ue['ue_id'])['is_capitalized'] ] ue_ids = [
return self.nt.ue_capitalisees[etudid] ue_id
for ue_id in self.nt.validations.ue_capitalisees.loc[[etudid]]["ue_id"]
]
return [UniteEns.query.get(ue_id) for ue_id in ue_ids]
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid): def get_listesNotesEtCoeffsTagEtudiant(self, tag, etudid):

View File

@ -171,7 +171,7 @@ class NotesTable:
def __init__(self, formsemestre_id): def __init__(self, formsemestre_id):
# log(f"NotesTable( formsemestre_id={formsemestre_id} )") # log(f"NotesTable( formsemestre_id={formsemestre_id} )")
# raise NotImplementedError() # XXX raise NotImplementedError() # XXX
if not formsemestre_id: if not formsemestre_id:
raise ValueError("invalid formsemestre_id (%s)" % formsemestre_id) raise ValueError("invalid formsemestre_id (%s)" % formsemestre_id)
self.formsemestre_id = formsemestre_id self.formsemestre_id = formsemestre_id
@ -410,7 +410,7 @@ class NotesTable:
return "" return ""
def get_etud_etat_html(self, etudid): def get_etud_etat_html(self, etudid):
etat = self.inscrdict[etudid]["etat"]
if etat == "I": if etat == "I":
return "" return ""
elif etat == "D": elif etat == "D":
@ -1169,7 +1169,7 @@ class NotesTable:
and moy_ue_cap >= self.parcours.NOTES_BARRE_VALID_UE and moy_ue_cap >= self.parcours.NOTES_BARRE_VALID_UE
): ):
if not cnx: if not cnx:
cnx = ndb.GetDBConnexion(autocommit=False) cnx = ndb.GetDBConnexion()
sco_parcours_dut.do_formsemestre_validate_ue( sco_parcours_dut.do_formsemestre_validate_ue(
cnx, cnx,
nt_cap, nt_cap,
@ -1314,10 +1314,6 @@ class NotesTable:
return self._evaluations_etats return self._evaluations_etats
def get_sem_evaluation_etat_list(self):
"""Liste des evaluations de ce semestre, avec leur etat"""
return self.get_evaluations_etats()
def get_mod_evaluation_etat_list(self, moduleimpl_id) -> list[dict]: def get_mod_evaluation_etat_list(self, moduleimpl_id) -> list[dict]:
"""Liste des évaluations de ce module""" """Liste des évaluations de ce module"""
return [ return [

View File

@ -352,23 +352,27 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
] = [] # modules de l'UE capitalisée (liste vide si pas capitalisée) ] = [] # modules de l'UE capitalisée (liste vide si pas capitalisée)
if ue_status["is_capitalized"]: if ue_status["is_capitalized"]:
sem_origin = sco_formsemestre.get_formsemestre(ue_status["formsemestre_id"]) sem_origin = sco_formsemestre.get_formsemestre(ue_status["formsemestre_id"])
u["ue_descr_txt"] = "Capitalisée le %s" % ndb.DateISOtoDMY( u["ue_descr_txt"] = "capitalisée le %s" % ndb.DateISOtoDMY(
ue_status["event_date"] ue_status["event_date"]
) )
u[ u[
"ue_descr_html" "ue_descr_html"
] = '<a href="formsemestre_bulletinetud?formsemestre_id=%s&etudid=%s" title="%s" class="bull_link">%s</a>' % ( ] = f"""<a href="{ url_for( 'notes.formsemestre_bulletinetud',
sem_origin["formsemestre_id"], scodoc_dept=g.scodoc_dept, formsemestre_id=sem_origin['formsemestre_id'], etudid=etudid)}"
etudid, title="{sem_origin['titreannee']}" class="bull_link"
sem_origin["titreannee"], >{u["ue_descr_txt"]} pouet</a>
u["ue_descr_txt"], """
)
# log('cap details %s' % ue_status['moy'])
if ue_status["moy"] != "NA" and ue_status["formsemestre_id"]: if ue_status["moy"] != "NA" and ue_status["formsemestre_id"]:
# detail des modules de l'UE capitalisee # detail des modules de l'UE capitalisee
nt_cap = sco_cache.NotesTableCache.get( # nt_cap = sco_cache.NotesTableCache.get(
# ue_status["formsemestre_id"]
# ) # > toutes notes
formsemestre_cap = FormSemestre.query.get_or_404(
ue_status["formsemestre_id"] ue_status["formsemestre_id"]
) # > toutes notes )
nt_cap: NotesTableCompat = res_sem.load_formsemestre_results(
formsemestre_cap
)
u["modules_capitalized"], _ = _ue_mod_bulletin( u["modules_capitalized"], _ = _ue_mod_bulletin(
etudid, etudid,

View File

@ -32,13 +32,14 @@ import datetime
import json import json
from app.but import bulletin_but from app.but import bulletin_but
from app.comp import res_sem
from app.comp.res_common import NotesTableCompat
from app.models.formsemestre import FormSemestre from app.models.formsemestre import FormSemestre
from app.models.etudiants import Identite from app.models.etudiants import Identite
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app.scodoc import sco_abs from app.scodoc import sco_abs
from app.scodoc import sco_cache
from app.scodoc import sco_edit_ue from app.scodoc import sco_edit_ue
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_formsemestre
@ -90,11 +91,7 @@ def formsemestre_bulletinetud_published_dict(
etud = Identite.query.get(etudid) etud = Identite.query.get(etudid)
sem = sco_formsemestre.get_formsemestre(formsemestre_id) sem = sco_formsemestre.get_formsemestre(formsemestre_id)
if formsemestre.formation.is_apc(): nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
nt = bulletin_but.APCNotesTableCompat(formsemestre)
else:
nt = sco_cache.NotesTableCache.get(formsemestre_id)
d = {} d = {}
if (not sem["bul_hide_xml"]) or force_publishing: if (not sem["bul_hide_xml"]) or force_publishing:
@ -205,6 +202,7 @@ def formsemestre_bulletinetud_published_dict(
ects_txt = "" ects_txt = ""
else: else:
ects_txt = f"{ue['ects']:2.3g}" ects_txt = f"{ue['ects']:2.3g}"
rang, effectif = nt.get_etud_ue_rang(ue["ue_id"], etudid)
u = dict( u = dict(
id=ue["ue_id"], id=ue["ue_id"],
numero=scu.quote_xml_attr(ue["numero"]), numero=scu.quote_xml_attr(ue["numero"]),
@ -218,8 +216,8 @@ def formsemestre_bulletinetud_published_dict(
ue["moy"] ue["moy"]
), # CM : ajout pour faire apparaitre la moyenne des UE ), # CM : ajout pour faire apparaitre la moyenne des UE
), ),
rang=str(nt.ue_rangs[ue["ue_id"]][0][etudid]), rang=rang,
effectif=str(nt.ue_rangs[ue["ue_id"]][1]), effectif=effectif,
ects=ects_txt, ects=ects_txt,
code_apogee=scu.quote_xml_attr(ue["code_apogee"]), code_apogee=scu.quote_xml_attr(ue["code_apogee"]),
) )

View File

@ -169,7 +169,7 @@ class BulletinGeneratorLegacy(sco_bulletins_generator.BulletinGenerator):
) )
) )
# Contenu table: UE apres UE # Contenu table: UE après UE
for ue in I["ues"]: for ue in I["ues"]:
ue_descr = ue["ue_descr_html"] ue_descr = ue["ue_descr_html"]
coef_ue = ue["coef_ue_txt"] coef_ue = ue["coef_ue_txt"]

View File

@ -430,7 +430,13 @@ class BulletinGeneratorStandard(sco_bulletins_generator.BulletinGenerator):
t = { t = {
"titre": ue["acronyme"] + " " + ue["titre"], "titre": ue["acronyme"] + " " + ue["titre"],
"_titre_html": plusminus + ue["acronyme"] + " " + ue["titre"], "_titre_html": plusminus
+ ue["acronyme"]
+ " "
+ ue["titre"]
+ ' <span class="bul_ue_descr">'
+ ue["ue_descr_txt"]
+ "</span>",
"_titre_help": ue["ue_descr_txt"], "_titre_help": ue["ue_descr_txt"],
"_titre_colspan": 2, "_titre_colspan": 2,
"module": ue_descr, "module": ue_descr,

View File

@ -44,6 +44,8 @@ import datetime
from xml.etree import ElementTree from xml.etree import ElementTree
from xml.etree.ElementTree import Element from xml.etree.ElementTree import Element
from app.comp import res_sem
from app.comp.res_common import NotesTableCompat
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app import log from app import log
@ -152,7 +154,8 @@ def make_xml_formsemestre_bulletinetud(
pid = partition["partition_id"] pid = partition["partition_id"]
partitions_etud_groups[pid] = sco_groups.get_etud_groups_in_partition(pid) partitions_etud_groups[pid] = sco_groups.get_etud_groups_in_partition(pid)
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > toutes notes formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
ues = nt.get_ues_stat_dict() ues = nt.get_ues_stat_dict()
modimpls = nt.get_modimpls_dict() modimpls = nt.get_modimpls_dict()
nbetuds = len(nt.etud_moy_gen_ranks) nbetuds = len(nt.etud_moy_gen_ranks)
@ -230,8 +233,9 @@ def make_xml_formsemestre_bulletinetud(
except (ValueError, TypeError): except (ValueError, TypeError):
ects_txt = "" ects_txt = ""
x_ue.append(Element("ects", value=ects_txt)) x_ue.append(Element("ects", value=ects_txt))
x_ue.append(Element("rang", value=str(nt.ue_rangs[ue["ue_id"]][0][etudid]))) rang, effectif = nt.get_etud_ue_rang(ue["ue_id"], etudid)
x_ue.append(Element("effectif", value=str(nt.ue_rangs[ue["ue_id"]][1]))) x_ue.append(Element("rang", value=str(rang)))
x_ue.append(Element("effectif", value=str(effectif)))
# Liste les modules de l'UE # Liste les modules de l'UE
ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]] ue_modimpls = [mod for mod in modimpls if mod["module"]["ue_id"] == ue["ue_id"]]
for modimpl in ue_modimpls: for modimpl in ue_modimpls:

View File

@ -31,13 +31,17 @@ import datetime
import operator import operator
import time import time
import flask
from flask import url_for from flask import url_for
from flask import g from flask import g
from flask_login import current_user from flask_login import current_user
from flask import request from flask import request
from app import log from app import log
from app.comp import res_sem
from app.comp.res_common import NotesTableCompat
from app.models import FormSemestre
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.sco_utils import ModuleType from app.scodoc.sco_utils import ModuleType
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
@ -379,10 +383,9 @@ def _eval_etat(evals):
def do_evaluation_etat_in_sem(formsemestre_id): def do_evaluation_etat_in_sem(formsemestre_id):
"""-> nb_eval_completes, nb_evals_en_cours, nb_evals_vides, """-> nb_eval_completes, nb_evals_en_cours, nb_evals_vides,
date derniere modif, attente""" date derniere modif, attente"""
nt = sco_cache.NotesTableCache.get( formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
formsemestre_id nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
) # > liste evaluations et moduleimpl en attente evals = nt.get_evaluations_etats()
evals = nt.get_sem_evaluation_etat_list()
etat = _eval_etat(evals) etat = _eval_etat(evals)
# Ajoute information sur notes en attente # Ajoute information sur notes en attente
etat["attente"] = len(nt.get_moduleimpls_attente()) > 0 etat["attente"] = len(nt.get_moduleimpls_attente()) > 0
@ -403,7 +406,7 @@ def formsemestre_evaluations_cal(formsemestre_id):
sem = sco_formsemestre.get_formsemestre(formsemestre_id) sem = sco_formsemestre.get_formsemestre(formsemestre_id)
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations
evals = nt.get_sem_evaluation_etat_list() evals = nt.get_evaluations_etats()
nb_evals = len(evals) nb_evals = len(evals)
color_incomplete = "#FF6060" color_incomplete = "#FF6060"
@ -538,7 +541,7 @@ def formsemestre_evaluations_delai_correction(formsemestre_id, format="html"):
sem = sco_formsemestre.get_formsemestre(formsemestre_id) sem = sco_formsemestre.get_formsemestre(formsemestre_id)
nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations nt = sco_cache.NotesTableCache.get(formsemestre_id) # > liste evaluations
evals = nt.get_sem_evaluation_etat_list() evals = nt.get_evaluations_etats()
T = [] T = []
for e in evals: for e in evals:
M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0] M = sco_moduleimpl.moduleimpl_list(moduleimpl_id=e["moduleimpl_id"])[0]

View File

@ -342,7 +342,7 @@ def do_formsemestre_uecoef_delete(cnx, formsemestre_id, ue_id):
formsemestre_uecoef_delete(cnx, coefs[0]["formsemestre_uecoef_id"]) formsemestre_uecoef_delete(cnx, coefs[0]["formsemestre_uecoef_id"])
def read_formsemestre_etapes(formsemestre_id): def read_formsemestre_etapes(formsemestre_id): # OBSOLETE
"""recupere liste des codes etapes associés à ce semestre """recupere liste des codes etapes associés à ce semestre
:returns: liste d'instance de ApoEtapeVDI :returns: liste d'instance de ApoEtapeVDI
""" """

View File

@ -560,7 +560,7 @@ def formsemestre_recap_parcours_table(
else: else:
type_sem = "" type_sem = ""
class_sem = "sem_autre" class_sem = "sem_autre"
if sem["formation_code"] != Se.formation["formation_code"]: if sem["formation_code"] != Se.formation.formation_code:
class_sem += " sem_autre_formation" class_sem += " sem_autre_formation"
if sem["bul_bgcolor"]: if sem["bul_bgcolor"]:
bgcolor = sem["bul_bgcolor"] bgcolor = sem["bul_bgcolor"]
@ -628,7 +628,7 @@ def formsemestre_recap_parcours_table(
if not sem["etat"]: # locked if not sem["etat"]: # locked
lockicon = scu.icontag("lock32_img", title="verrouillé", border="0") lockicon = scu.icontag("lock32_img", title="verrouillé", border="0")
default_sem_info += lockicon default_sem_info += lockicon
if sem["formation_code"] != Se.formation["formation_code"]: if sem["formation_code"] != Se.formation.formation_code:
default_sem_info += "Autre formation: %s" % sem["formation_code"] default_sem_info += "Autre formation: %s" % sem["formation_code"]
H.append( H.append(
'<td class="datefin">%s</td><td class="sem_info">%s</td>' '<td class="datefin">%s</td><td class="sem_info">%s</td>'
@ -702,7 +702,7 @@ def formsemestre_recap_parcours_table(
) )
# total ECTS (affiché sous la moyenne générale) # total ECTS (affiché sous la moyenne générale)
H.append( H.append(
'<td class="sem_ects_tit"><a title="crédit potentiels (dont nb de fondamentaux)">ECTS:</a></td><td class="sem_ects">%g</td>' '<td class="sem_ects_tit"><a title="crédit potentiels">ECTS:</a></td><td class="sem_ects">%g</td>'
% (etud_ects_infos["ects_pot"]) % (etud_ects_infos["ects_pot"])
) )
H.append('<td class="rcp_abs"></td>') H.append('<td class="rcp_abs"></td>')

View File

@ -33,10 +33,14 @@ from flask import g, url_for
from flask_login import current_user from flask_login import current_user
from app.auth.models import User from app.auth.models import User
from app.comp import res_sem
from app.comp.res_common import NotesTableCompat
from app.models import FormSemestre
from app.models import ModuleImpl from app.models import ModuleImpl
from app.models.evaluations import Evaluation from app.models.evaluations import Evaluation
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.sco_exceptions import ScoInvalidIdType from app.scodoc.sco_exceptions import ScoInvalidIdType
from app.scodoc.sco_parcours_dut import formsemestre_has_decisions
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
@ -199,7 +203,9 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
moduleimpl_id=M["moduleimpl_id"] moduleimpl_id=M["moduleimpl_id"]
) )
nt = sco_cache.NotesTableCache.get(formsemestre_id) # nt = sco_cache.NotesTableCache.get(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(modimpl.formsemestre)
mod_evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id}) mod_evals = sco_evaluation_db.do_evaluation_list({"moduleimpl_id": moduleimpl_id})
mod_evals.sort( mod_evals.sort(
key=lambda x: (x["numero"], x["jour"], x["heure_debut"]), reverse=True key=lambda x: (x["numero"], x["jour"], x["heure_debut"]), reverse=True
@ -335,7 +341,7 @@ def moduleimpl_status(moduleimpl_id=None, partition_id=None):
if has_expression and nt.expr_diagnostics: if has_expression and nt.expr_diagnostics:
H.append(sco_formsemestre_status.html_expr_diagnostic(nt.expr_diagnostics)) H.append(sco_formsemestre_status.html_expr_diagnostic(nt.expr_diagnostics))
# #
if nt.sem_has_decisions(): if formsemestre_has_decisions(formsemestre_id):
H.append( H.append(
"""<ul class="tf-msg"><li class="tf-msg warning">Décisions de jury saisies: seul le responsable du semestre peut saisir des notes (il devra modifier les décisions de jury).</li></ul>""" """<ul class="tf-msg"><li class="tf-msg warning">Décisions de jury saisies: seul le responsable du semestre peut saisir des notes (il devra modifier les décisions de jury).</li></ul>"""
) )

View File

@ -28,7 +28,10 @@
"""Semestres: gestion parcours DUT (Arreté du 13 août 2005) """Semestres: gestion parcours DUT (Arreté du 13 août 2005)
""" """
from app.models.ues import UniteEns from app.comp import res_sem
from app.comp.res_common import NotesTableCompat
from app.models import FormSemestre, UniteEns
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
from app import log from app import log
@ -108,9 +111,11 @@ class DecisionSem(object):
def SituationEtudParcours(etud, formsemestre_id): def SituationEtudParcours(etud, formsemestre_id):
"""renvoie une instance de SituationEtudParcours (ou sous-classe spécialisée)""" """renvoie une instance de SituationEtudParcours (ou sous-classe spécialisée)"""
nt = sco_cache.NotesTableCache.get( # nt = sco_cache.NotesTableCache.get(
formsemestre_id # formsemestre_id
) # > get_etud_decision_sem, get_etud_moy_gen, get_ues_stat_dict, get_etud_ue_status, etud_check_conditions_ues # ) # > get_etud_decision_sem, get_etud_moy_gen, get_ues_stat_dict, get_etud_ue_status, etud_check_conditions_ues
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
parcours = nt.parcours parcours = nt.parcours
# #
if parcours.ECTS_ONLY: if parcours.ECTS_ONLY:
@ -131,7 +136,7 @@ class SituationEtudParcoursGeneric(object):
self.formsemestre_id = formsemestre_id self.formsemestre_id = formsemestre_id
self.sem = sco_formsemestre.get_formsemestre(formsemestre_id) self.sem = sco_formsemestre.get_formsemestre(formsemestre_id)
self.nt = nt self.nt = nt
self.formation = self.nt.formation self.formation = self.nt.formsemestre.formation
self.parcours = self.nt.parcours self.parcours = self.nt.parcours
# Ce semestre est-il le dernier de la formation ? (e.g. semestre 4 du DUT) # Ce semestre est-il le dernier de la formation ? (e.g. semestre 4 du DUT)
# pour le DUT, le dernier est toujours S4. # pour le DUT, le dernier est toujours S4.
@ -295,11 +300,15 @@ class SituationEtudParcoursGeneric(object):
for sem in self.get_semestres(): for sem in self.get_semestres():
if ( if (
sem["semestre_id"] == n1 sem["semestre_id"] == n1
and sem["formation_code"] == self.formation["formation_code"] and sem["formation_code"] == self.formation.formation_code
): ):
nt = sco_cache.NotesTableCache.get( # nt = sco_cache.NotesTableCache.get(
sem["formsemestre_id"] # sem["formsemestre_id"]
) # > get_etud_decision_sem # ) # > get_etud_decision_sem
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
nt: NotesTableCompat = res_sem.load_formsemestre_results(
formsemestre
)
decision = nt.get_etud_decision_sem(self.etudid) decision = nt.get_etud_decision_sem(self.etudid)
if decision and ( if decision and (
code_semestre_validant(decision["code"]) code_semestre_validant(decision["code"])
@ -312,10 +321,12 @@ class SituationEtudParcoursGeneric(object):
"""True si les semestres dont les indices sont donnés en argument (modifié) """True si les semestres dont les indices sont donnés en argument (modifié)
sont validés. En sortie, sem_idx_set contient ceux qui n'ont pas été validés.""" sont validés. En sortie, sem_idx_set contient ceux qui n'ont pas été validés."""
for sem in self.get_semestres(): for sem in self.get_semestres():
if sem["formation_code"] == self.formation["formation_code"]: if sem["formation_code"] == self.formation.formation_code:
nt = sco_cache.NotesTableCache.get( # nt = sco_cache.NotesTableCache.get(
sem["formsemestre_id"] # sem["formsemestre_id"]
) # > get_etud_decision_sem # ) # > get_etud_decision_sem
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
decision = nt.get_etud_decision_sem(self.etudid) decision = nt.get_etud_decision_sem(self.etudid)
if decision and code_semestre_validant(decision["code"]): if decision and code_semestre_validant(decision["code"]):
# validé # validé
@ -331,9 +342,11 @@ class SituationEtudParcoursGeneric(object):
ue_acros = {} # acronyme ue : 1 ue_acros = {} # acronyme ue : 1
nb_max_ue = 0 nb_max_ue = 0
for sem in sems: for sem in sems:
nt = sco_cache.NotesTableCache.get( # nt = sco_cache.NotesTableCache.get(
sem["formsemestre_id"] # sem["formsemestre_id"]
) # > get_ues_stat_dict # ) # > get_ues_stat_dict
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
ues = nt.get_ues_stat_dict(filter_sport=True) ues = nt.get_ues_stat_dict(filter_sport=True)
for ue in ues: for ue in ues:
ue_acros[ue["acronyme"]] = 1 ue_acros[ue["acronyme"]] = 1
@ -401,9 +414,11 @@ class SituationEtudParcoursGeneric(object):
if not sem: if not sem:
code = "" # non inscrit à ce semestre code = "" # non inscrit à ce semestre
else: else:
nt = sco_cache.NotesTableCache.get( # nt = sco_cache.NotesTableCache.get(
sem["formsemestre_id"] # sem["formsemestre_id"]
) # > get_etud_decision_sem # ) # > get_etud_decision_sem
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
decision = nt.get_etud_decision_sem(self.etudid) decision = nt.get_etud_decision_sem(self.etudid)
if decision: if decision:
code = decision["code"] code = decision["code"]
@ -459,7 +474,7 @@ class SituationEtudParcoursGeneric(object):
prev = None prev = None
while i >= 0: while i >= 0:
if ( if (
self.sems[i]["formation_code"] == self.formation["formation_code"] self.sems[i]["formation_code"] == self.formation.formation_code
and self.sems[i]["semestre_id"] == cur["semestre_id"] - 1 and self.sems[i]["semestre_id"] == cur["semestre_id"] - 1
): ):
prev = self.sems[i] prev = self.sems[i]
@ -471,8 +486,9 @@ class SituationEtudParcoursGeneric(object):
# Verifications basiques: # Verifications basiques:
# ? # ?
# Code etat du semestre precedent: # Code etat du semestre precedent:
nt = sco_cache.NotesTableCache.get(prev["formsemestre_id"]) # nt = sco_cache.NotesTableCache.get(prev["formsemestre_id"])
# > get_etud_decision_sem, get_etud_moy_gen, etud_check_conditions_ues formsemestre = FormSemestre.query.get_or_404(prev["formsemestre_id"])
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
self.prev_decision = nt.get_etud_decision_sem(self.etudid) self.prev_decision = nt.get_etud_decision_sem(self.etudid)
self.prev_moy_gen = nt.get_etud_moy_gen(self.etudid) self.prev_moy_gen = nt.get_etud_moy_gen(self.etudid)
self.prev_barres_ue_ok = nt.etud_check_conditions_ues(self.etudid)[0] self.prev_barres_ue_ok = nt.etud_check_conditions_ues(self.etudid)[0]
@ -526,11 +542,15 @@ class SituationEtudParcoursGeneric(object):
validated = False validated = False
for sem in self.sems: for sem in self.sems:
if ( if (
sem["formation_code"] == self.formation["formation_code"] sem["formation_code"] == self.formation.formation_code
and sem["semestre_id"] == s and sem["semestre_id"] == s
): ):
nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"]) # nt = sco_cache.NotesTableCache.get(sem["formsemestre_id"])
# > get_etud_decision_sem # > get_etud_decision_sem
formsemestre = FormSemestre.query.get_or_404(sem["formsemestre_id"])
nt: NotesTableCompat = res_sem.load_formsemestre_results(
formsemestre
)
decision = nt.get_etud_decision_sem(self.etudid) decision = nt.get_etud_decision_sem(self.etudid)
if decision and code_semestre_validant(decision["code"]): if decision and code_semestre_validant(decision["code"]):
validated = True validated = True
@ -642,7 +662,7 @@ class SituationEtudParcoursGeneric(object):
cnx, cnx,
{ {
"etudid": self.etudid, "etudid": self.etudid,
"formation_code": self.formation["formation_code"], "formation_code": self.formation.formation_code,
"semestre_id": next_semestre_id, "semestre_id": next_semestre_id,
"origin_formsemestre_id": self.formsemestre_id, "origin_formsemestre_id": self.formsemestre_id,
}, },
@ -904,9 +924,11 @@ def formsemestre_validate_ues(formsemestre_id, etudid, code_etat_sem, assiduite)
""" """
valid_semestre = CODES_SEM_VALIDES.get(code_etat_sem, False) valid_semestre = CODES_SEM_VALIDES.get(code_etat_sem, False)
cnx = ndb.GetDBConnexion() cnx = ndb.GetDBConnexion()
nt = sco_cache.NotesTableCache.get( # nt = sco_cache.NotesTableCache.get(
formsemestre_id # formsemestre_id
) # > get_ues_stat_dict, get_etud_ue_status # ) # > get_ues_stat_dict, get_etud_ue_status
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
ue_ids = [x["ue_id"] for x in nt.get_ues_stat_dict(filter_sport=True)] ue_ids = [x["ue_id"] for x in nt.get_ues_stat_dict(filter_sport=True)]
for ue_id in ue_ids: for ue_id in ue_ids:
ue_status = nt.get_etud_ue_status(etudid, ue_id) ue_status = nt.get_etud_ue_status(etudid, ue_id)

View File

@ -53,7 +53,10 @@ from reportlab.lib import styles
import flask import flask
from flask import url_for, g, request from flask import url_for, g, request
from app.models.ues import UniteEns
from app.comp import res_sem
from app.comp.res_common import NotesTableCompat
from app.models import FormSemestre, UniteEns
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
import app.scodoc.notesdb as ndb import app.scodoc.notesdb as ndb
@ -98,9 +101,10 @@ def _descr_decisions_ues(nt, etudid, decisions_ue, decision_sem):
except: except:
log("descr_decisions_ues: ue_id=%s decisions_ue=%s" % (ue_id, decisions_ue)) log("descr_decisions_ues: ue_id=%s decisions_ue=%s" % (ue_id, decisions_ue))
# Les UE capitalisées dans d'autres semestres: # Les UE capitalisées dans d'autres semestres:
for ue in nt.ue_capitalisees[etudid]: if etudid in nt.validations.ue_capitalisees.index:
for ue_id in nt.validations.ue_capitalisees.loc[[etudid]]["ue_id"]:
try: try:
uelist.append(nt.get_etud_ue_status(etudid, ue["ue_id"])["ue"]) uelist.append(nt.get_etud_ue_status(etudid, ue_id)["ue"])
except KeyError: except KeyError:
pass pass
uelist.sort(key=itemgetter("numero")) uelist.sort(key=itemgetter("numero"))
@ -213,9 +217,11 @@ def dict_pvjury(
'decisions_dict' : { etudid : decision (comme ci-dessus) }, 'decisions_dict' : { etudid : decision (comme ci-dessus) },
} }
""" """
nt = sco_cache.NotesTableCache.get( # nt = sco_cache.NotesTableCache.get(
formsemestre_id # formsemestre_id
) # > get_etudids, get_etud_etat, get_etud_decision_sem, get_etud_decision_ues # ) # > get_etudids, get_etud_etat, get_etud_decision_sem, get_etud_decision_ues
formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
if etudids is None: if etudids is None:
etudids = nt.get_etudids() etudids = nt.get_etudids()
if not etudids: if not etudids:

View File

@ -495,7 +495,7 @@ def make_formsemestre_recapcomplet(
j += 1 j += 1
if not hidebac: if not hidebac:
for k in admission_extra_cols: for k in admission_extra_cols:
l.append(getattr(e["admission"], k, "")) l.append(getattr(e["admission"], k, "") or "")
l.append( l.append(
nt.identdict[etudid]["code_nip"] or "" nt.identdict[etudid]["code_nip"] or ""
) # avant-derniere colonne = code_nip ) # avant-derniere colonne = code_nip
@ -977,7 +977,7 @@ def _formsemestre_recapcomplet_json(
def formsemestres_bulletins(annee_scolaire): def formsemestres_bulletins(annee_scolaire):
"""Tous les bulletins des semestres publiés des semestres de l'année indiquée. """Tous les bulletins des semestres publiés des semestres de l'année indiquée.
:param annee_scolaire(int): année de début de l'année scoalaire :param annee_scolaire(int): année de début de l'année scolaire
:returns: JSON :returns: JSON
""" """
jslist = [] jslist = []

View File

@ -1959,7 +1959,6 @@ tr.notes_bulletin_row_ue {
tr.bul_row_ue_cur { tr.bul_row_ue_cur {
background-color: rgb(180,180,180); background-color: rgb(180,180,180);
color: rgb(50,50,50);
} }
tr.bul_row_ue_cap { tr.bul_row_ue_cap {
@ -2004,6 +2003,11 @@ tr.notes_bulletin_row_eval td.module {
border-left: 1px dashed rgb(170,170,170); border-left: 1px dashed rgb(170,170,170);
} }
span.bul_ue_descr {
font-weight: normal;
font-style: italic;
}
table.notes_bulletin td.note { table.notes_bulletin td.note {
padding-left: 1em; padding-left: 1em;
} }
@ -2012,10 +2016,13 @@ table.notes_bulletin td.min, table.notes_bulletin td.max, table.notes_bulletin t
} }
table.notes_bulletin tr.notes_bulletin_row_ue_cur td.note, table.notes_bulletin tr.notes_bulletin_row_ue_cur td.min, table.notes_bulletin tr.notes_bulletin_row_ue_cur td.max { table.notes_bulletin tr.notes_bulletin_row_ue_cur td.note, table.notes_bulletin tr.notes_bulletin_row_ue_cur td.min, table.notes_bulletin tr.notes_bulletin_row_ue_cur td.max {
color: rgb(80,80,80);
font-style: italic; font-style: italic;
} }
table.notes_bulletin tr.bul_row_ue_cur td, table.notes_bulletin tr.bul_row_ue_cur td a {
color:rgb(114, 89, 89);
}
.note_bold { .note_bold {
font-weight: bold; font-weight: bold;
} }

View File

@ -133,7 +133,7 @@ from app.scodoc.TrivialFormulator import TrivialFormulator
from app.views import ScoData from app.views import ScoData
def sco_publish(route, function, permission, methods=["GET"]): def sco_publish(route, function, permission, methods=("GET",)):
"""Declare a route for a python function, """Declare a route for a python function,
protected by permission and called following ScoDoc 7 Zope standards. protected by permission and called following ScoDoc 7 Zope standards.
""" """