forked from ScoDoc/ScoDoc
PV: lettres individuelles: affichage des UEs et autres réparations.
This commit is contained in:
parent
9bf505ff11
commit
7e56dc730d
@ -385,7 +385,7 @@ class BulletinBUT:
|
||||
"injustifie": nbabs - nbabsjust,
|
||||
"total": nbabs,
|
||||
}
|
||||
decisions_ues = self.res.get_etud_decision_ues(etud.id) or {}
|
||||
decisions_ues = self.res.get_etud_decisions_ue(etud.id) or {}
|
||||
if self.prefs["bul_show_ects"]:
|
||||
ects_tot = res.etud_ects_tot_sem(etud.id)
|
||||
ects_acquis = res.get_etud_ects_valides(etud.id, decisions_ues)
|
||||
|
@ -271,9 +271,9 @@ class NotesTableCompat(ResultatsSemestre):
|
||||
|
||||
def etud_has_decision(self, etudid):
|
||||
"""True s'il y a une décision de jury pour cet étudiant"""
|
||||
return self.get_etud_decision_ues(etudid) or self.get_etud_decision_sem(etudid)
|
||||
return self.get_etud_decisions_ue(etudid) or self.get_etud_decision_sem(etudid)
|
||||
|
||||
def get_etud_decision_ues(self, etudid: int) -> dict:
|
||||
def get_etud_decisions_ue(self, etudid: int) -> dict:
|
||||
"""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.
|
||||
{ ue_id : { 'code' : ADM|CMP|AJ, 'event_date' : "d/m/y", 'ects' : x }
|
||||
@ -288,10 +288,10 @@ class NotesTableCompat(ResultatsSemestre):
|
||||
def get_etud_ects_valides(self, etudid: int, decisions_ues: dict = False) -> 0:
|
||||
"""Le total des ECTS validés (et enregistrés) par l'étudiant dans ce semestre.
|
||||
NB: avant jury, rien d'enregistré, donc zéro ECTS.
|
||||
Optimisation: si decisions_ues est passé, l'utilise, sinon appelle get_etud_decision_ues()
|
||||
Optimisation: si decisions_ues est passé, l'utilise, sinon appelle get_etud_decisions_ue()
|
||||
"""
|
||||
if decisions_ues is False:
|
||||
decisions_ues = self.get_etud_decision_ues(etudid)
|
||||
decisions_ues = self.get_etud_decisions_ue(etudid)
|
||||
if not decisions_ues:
|
||||
return 0.0
|
||||
return sum([d.get("ects", 0.0) for d in decisions_ues.values()])
|
||||
|
@ -183,6 +183,10 @@ class Identite(db.Model):
|
||||
e["etudid"] = self.id
|
||||
e["date_naissance"] = ndb.DateISOtoDMY(e["date_naissance"])
|
||||
e["ne"] = self.e
|
||||
e["nomprenom"] = self.nomprenom
|
||||
adresse = self.adresses.first()
|
||||
if adresse:
|
||||
e.update(adresse.to_dict())
|
||||
return {k: e[k] or "" for k in e} # convert_null_outputs_to_empty
|
||||
|
||||
def to_dict_bul(self, include_urls=True):
|
||||
|
@ -1102,7 +1102,7 @@ class NotesTable:
|
||||
else:
|
||||
return self.decisions_jury.get(etudid, None)
|
||||
|
||||
def get_etud_decision_ues(self, etudid):
|
||||
def get_etud_decisions_ue(self, etudid):
|
||||
"""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.
|
||||
{ ue_id : { 'code' : ADM|CMP|AJ, 'event_date' : }
|
||||
@ -1122,7 +1122,7 @@ class NotesTable:
|
||||
|
||||
def etud_has_decision(self, etudid):
|
||||
"""True s'il y a une décision de jury pour cet étudiant"""
|
||||
return self.get_etud_decision_ues(etudid) or self.get_etud_decision_sem(etudid)
|
||||
return self.get_etud_decisions_ue(etudid) or self.get_etud_decision_sem(etudid)
|
||||
|
||||
def all_etuds_have_sem_decisions(self):
|
||||
"""True si tous les étudiants du semestre ont une décision de jury.
|
||||
|
@ -433,7 +433,7 @@ class ApoEtud(dict):
|
||||
return VOID_APO_RES
|
||||
|
||||
# Elements UE
|
||||
decisions_ue = nt.get_etud_decision_ues(etudid)
|
||||
decisions_ue = nt.get_etud_decisions_ue(etudid)
|
||||
for ue in nt.get_ues_stat_dict():
|
||||
if ue["code_apogee"] and code in {
|
||||
x.strip() for x in ue["code_apogee"].split(",")
|
||||
|
@ -124,6 +124,24 @@ def replacement_function(match):
|
||||
)
|
||||
|
||||
|
||||
class WrapDict(object):
|
||||
"""Wrap a dict so that getitem returns '' when values are None"""
|
||||
|
||||
def __init__(self, adict, NoneValue=""):
|
||||
self.dict = adict
|
||||
self.NoneValue = NoneValue
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
value = self.dict[key]
|
||||
except KeyError:
|
||||
return f"XXX {key} invalide XXX"
|
||||
if value is None:
|
||||
return self.NoneValue
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def process_field(field, cdict, style, suppress_empty_pars=False, format="pdf"):
|
||||
"""Process a field given in preferences, returns
|
||||
- if format = 'pdf': a list of Platypus objects
|
||||
@ -137,18 +155,19 @@ def process_field(field, cdict, style, suppress_empty_pars=False, format="pdf"):
|
||||
If format = 'html', replaces <para> by <p>. HTML does not allow logos.
|
||||
"""
|
||||
try:
|
||||
text = (field or "") % scu.WrapDict(
|
||||
cdict
|
||||
) # note that None values are mapped to empty strings
|
||||
# None values are mapped to empty strings by WrapDict
|
||||
text = (field or "") % WrapDict(cdict)
|
||||
except KeyError as exc:
|
||||
missing_key = exc.args[0] if len(exc.args) > 0 else "?"
|
||||
log(
|
||||
f"""process_field: KeyError on field={field!r}
|
||||
f"""process_field: KeyError {missing_key} on field={field!r}
|
||||
values={pprint.pformat(cdict)}
|
||||
"""
|
||||
)
|
||||
if len(exc.args) > 0:
|
||||
missing_field = exc.args[0]
|
||||
text = f"""<para><i>format invalide: champs</i> {missing_field} <i>inexistant !</i></para>"""
|
||||
text = f"""<para><i>format invalide: champs</i> {missing_key} <i>inexistant !</i></para>"""
|
||||
scu.flash_once(
|
||||
f"Attention: format PDF invalide (champs {field}, clef {missing_key})"
|
||||
)
|
||||
except: # pylint: disable=bare-except
|
||||
log(
|
||||
f"""process_field: invalid format. field={field!r}
|
||||
@ -156,7 +175,7 @@ def process_field(field, cdict, style, suppress_empty_pars=False, format="pdf"):
|
||||
"""
|
||||
)
|
||||
# ne sera pas visible si lien vers pdf:
|
||||
scu.flash_once(f"Attention: format PDF invalide (champs {field}")
|
||||
scu.flash_once(f"Attention: format PDF invalide (champs {field})")
|
||||
text = (
|
||||
"<para><i>format invalide !</i></para><para>"
|
||||
+ traceback.format_exc()
|
||||
|
@ -42,6 +42,7 @@ from app.models import (
|
||||
but_validations,
|
||||
)
|
||||
from app.scodoc import codes_cursus
|
||||
from app.scodoc import sco_edit_ue
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_formsemestre
|
||||
from app.scodoc import sco_cursus
|
||||
@ -109,7 +110,7 @@ def dict_pvjury(
|
||||
etudid
|
||||
) # I|D|DEF (inscription ou démission ou défaillant)
|
||||
d["decision_sem"] = nt.get_etud_decision_sem(etudid)
|
||||
d["decisions_ue"] = nt.get_etud_decision_ues(etudid)
|
||||
d["decisions_ue"] = nt.get_etud_decisions_ue(etudid)
|
||||
if formsemestre.formation.is_apc():
|
||||
d.update(but_validations.dict_decision_jury(etud, formsemestre))
|
||||
d["last_formsemestre_id"] = Se.get_semestres()[
|
||||
@ -241,17 +242,17 @@ def _comp_ects_capitalises_by_ue_code(nt: NotesTableCompat, etudid: int):
|
||||
return ects_by_ue_code
|
||||
|
||||
|
||||
def _comp_ects_by_ue_code(nt, decision_ues):
|
||||
def _comp_ects_by_ue_code(nt, decisions_ue):
|
||||
"""Calcul somme des ECTS validés dans ce semestre (sans les UE capitalisées)
|
||||
decision_ues est le resultat de nt.get_etud_decision_ues
|
||||
decisions_ue est le resultat de nt.get_etud_decisions_ue
|
||||
Chaque resultat est un dict: { ue_code : ects }
|
||||
"""
|
||||
if not decision_ues:
|
||||
if not decisions_ue:
|
||||
return {}
|
||||
|
||||
ects_by_ue_code = {}
|
||||
for ue_id in decision_ues:
|
||||
d = decision_ues[ue_id]
|
||||
for ue_id in decisions_ue:
|
||||
d = decisions_ue[ue_id]
|
||||
ue = UniteEns.query.get(ue_id)
|
||||
ects_by_ue_code[ue.ue_code] = d["ects"]
|
||||
|
||||
@ -269,26 +270,22 @@ def _descr_decisions_ues(nt, etudid, decisions_ue, decision_sem) -> list[dict]:
|
||||
return []
|
||||
uelist = []
|
||||
# Les UE validées dans ce semestre:
|
||||
for ue_id in decisions_ue.keys():
|
||||
try:
|
||||
if decisions_ue[ue_id] and (
|
||||
codes_cursus.code_ue_validant(decisions_ue[ue_id]["code"])
|
||||
or (
|
||||
(not nt.is_apc)
|
||||
and (
|
||||
# XXX ceci devrait dépendre du parcours et non pas être une option ! #sco8
|
||||
decision_sem
|
||||
and scu.CONFIG.CAPITALIZE_ALL_UES
|
||||
and codes_cursus.code_semestre_validant(decision_sem["code"])
|
||||
)
|
||||
for ue_id in decisions_ue:
|
||||
if decisions_ue[ue_id] and (
|
||||
codes_cursus.code_ue_validant(decisions_ue[ue_id].get("code"))
|
||||
or (
|
||||
(not nt.is_apc)
|
||||
and (
|
||||
# XXX ceci devrait dépendre du parcours et non pas être une option ! #sco8
|
||||
decision_sem
|
||||
and scu.CONFIG.CAPITALIZE_ALL_UES
|
||||
and decision_sem
|
||||
and codes_cursus.code_semestre_validant(decision_sem.get("code"))
|
||||
)
|
||||
):
|
||||
ue = sco_edit_ue.ue_list(args={"ue_id": ue_id})[0]
|
||||
uelist.append(ue)
|
||||
except:
|
||||
log(
|
||||
f"Exception in descr_decisions_ues: ue_id={ue_id} decisions_ue={decisions_ue}"
|
||||
)
|
||||
):
|
||||
ue = sco_edit_ue.ue_list(args={"ue_id": ue_id})[0]
|
||||
uelist.append(ue)
|
||||
# Les UE capitalisées dans d'autres semestres:
|
||||
if etudid in nt.validations.ue_capitalisees.index:
|
||||
for ue_id in nt.validations.ue_capitalisees.loc[[etudid]]["ue_id"]:
|
||||
|
@ -47,7 +47,6 @@ from app.models import FormSemestre, Identite
|
||||
import app.scodoc.sco_utils as scu
|
||||
from app.scodoc import sco_bulletins_pdf
|
||||
from app.scodoc import sco_pv_dict
|
||||
from app.scodoc import sco_etud
|
||||
from app.scodoc import sco_pdf
|
||||
from app.scodoc import sco_preferences
|
||||
from app.scodoc.sco_exceptions import ScoValueError
|
||||
@ -70,9 +69,6 @@ def pdf_lettres_individuelles(
|
||||
dpv = sco_pv_dict.dict_pvjury(formsemestre_id, etudids=etudids, with_prev=True)
|
||||
if not dpv:
|
||||
return ""
|
||||
# Ajoute infos sur etudiants
|
||||
etuds = [x["identite"] for x in dpv["decisions"]]
|
||||
sco_etud.fill_etuds_info(etuds)
|
||||
#
|
||||
formsemestre: FormSemestre = FormSemestre.query.get(formsemestre_id)
|
||||
prefs = sco_preferences.SemPreferences(formsemestre_id)
|
||||
@ -95,9 +91,10 @@ def pdf_lettres_individuelles(
|
||||
decision["decision_sem"]
|
||||
or decision.get("decision_annee")
|
||||
or decision.get("decision_rcue")
|
||||
or decision.get("decisions_ue")
|
||||
): # decision prise
|
||||
etud: Identite = Identite.query.get(decision["identite"]["etudid"])
|
||||
params["nomEtud"] = etud.nomprenom
|
||||
params["nomEtud"] = etud.nomprenom # backward compat
|
||||
bookmarks[npages + 1] = scu.suppress_accents(etud.nomprenom)
|
||||
try:
|
||||
objects += pdf_lettre_individuelle(
|
||||
@ -217,7 +214,7 @@ def pdf_lettre_individuelle(sem, decision, etud: Identite, params, signature=Non
|
||||
|
||||
params.update(decision["identite"])
|
||||
# fix domicile
|
||||
if params["domicile"]:
|
||||
if params.get("domicile"):
|
||||
params["domicile"] = params["domicile"].replace("\\n", "<br/>")
|
||||
|
||||
# UE capitalisées:
|
||||
|
@ -953,7 +953,7 @@ def has_existing_decision(M, E, etudid):
|
||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
if nt.get_etud_decision_sem(etudid):
|
||||
return True
|
||||
dec_ues = nt.get_etud_decision_ues(etudid)
|
||||
dec_ues = nt.get_etud_decisions_ue(etudid)
|
||||
if dec_ues:
|
||||
mod = sco_edit_module.module_list({"module_id": M["module_id"]})[0]
|
||||
ue_id = mod["ue_id"]
|
||||
|
@ -291,21 +291,6 @@ class DictDefault(dict): # obsolete, use collections.defaultdict
|
||||
return value
|
||||
|
||||
|
||||
class WrapDict(object):
|
||||
"""Wrap a dict so that getitem returns '' when values are None"""
|
||||
|
||||
def __init__(self, adict, NoneValue=""):
|
||||
self.dict = adict
|
||||
self.NoneValue = NoneValue
|
||||
|
||||
def __getitem__(self, key):
|
||||
value = self.dict[key]
|
||||
if value is None:
|
||||
return self.NoneValue
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
def group_by_key(d, key):
|
||||
gr = DictDefault(defaultvalue=[])
|
||||
for e in d:
|
||||
|
@ -158,7 +158,7 @@ class TableJury(TableRecap):
|
||||
titre,
|
||||
validation_rcue.code,
|
||||
group="cursus_" + annee,
|
||||
classes=["recorded_code"],
|
||||
classes=[],
|
||||
column_classes=["cursus_but" + (" first" if first else "")],
|
||||
target_attrs={
|
||||
"title": f"{niveau.competence.titre} niveau {niveau.ordre}"
|
||||
@ -221,7 +221,7 @@ class RowJury(RowRecap):
|
||||
"Ajoute 2 colonnes: moyenne d'UE et code jury"
|
||||
# table recap standard (mais avec group différent)
|
||||
super().add_ue_cols(ue, ue_status, col_group=col_group or "col_ue")
|
||||
dues = self.table.res.get_etud_decision_ues(self.etud.id)
|
||||
dues = self.table.res.get_etud_decisions_ue(self.etud.id)
|
||||
due = dues.get(ue.id) if dues else None
|
||||
|
||||
col_id = f"moy_ue_{ue.id}_code"
|
||||
|
@ -233,7 +233,7 @@ def run_sco_basic(verbose=False) -> FormSemestre:
|
||||
formsemestre: FormSemestre = FormSemestre.query.get_or_404(formsemestre_id)
|
||||
nt: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
for etud in etuds[:5]:
|
||||
dec_ues = nt.get_etud_decision_ues(etud["etudid"])
|
||||
dec_ues = nt.get_etud_decisions_ue(etud["etudid"])
|
||||
for ue_id in dec_ues:
|
||||
assert dec_ues[ue_id]["code"] in {"ADM", "CMP"}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user