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