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

WIP
This commit is contained in:
Emmanuel Viennet 2022-01-09 22:33:08 +01:00
commit 782e291725
6 changed files with 169 additions and 127 deletions

View File

@ -30,17 +30,18 @@ class BulletinBUT(ResultatsSemestreBUT):
ue_idx = self.modimpl_coefs_df.index.get_loc(ue.id) ue_idx = self.modimpl_coefs_df.index.get_loc(ue.id)
etud_moy_module = self.sem_cube[etud_idx] # module x UE etud_moy_module = self.sem_cube[etud_idx] # module x UE
for modimpl in modimpls: for modimpl in modimpls:
coef = self.modimpl_coefs_df[modimpl.id][ue.id] if self.modimpl_inscr_df[str(modimpl.id)][etud.id]: # si inscrit
if coef > 0: coef = self.modimpl_coefs_df[modimpl.id][ue.id]
d[modimpl.module.code] = { if coef > 0:
"id": modimpl.id, d[modimpl.module.code] = {
"coef": coef, "id": modimpl.id,
"moyenne": fmt_note( "coef": coef,
etud_moy_module[ "moyenne": fmt_note(
self.modimpl_coefs_df.columns.get_loc(modimpl.id) etud_moy_module[
][ue_idx] self.modimpl_coefs_df.columns.get_loc(modimpl.id)
), ][ue_idx]
} ),
}
return d return d
def etud_ue_results(self, etud, ue): def etud_ue_results(self, etud, ue):
@ -87,29 +88,30 @@ class BulletinBUT(ResultatsSemestreBUT):
# 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 = self.modimpls_results[modimpl.id]
d[modimpl.module.code] = { if self.modimpl_inscr_df[str(modimpl.id)][etud.id]: # si inscrit
"id": modimpl.id, d[modimpl.module.code] = {
"titre": modimpl.module.titre, "id": modimpl.id,
"code_apogee": modimpl.module.code_apogee, "titre": modimpl.module.titre,
"url": url_for( "code_apogee": modimpl.module.code_apogee,
"notes.moduleimpl_status", "url": url_for(
scodoc_dept=g.scodoc_dept, "notes.moduleimpl_status",
moduleimpl_id=modimpl.id, scodoc_dept=g.scodoc_dept,
), moduleimpl_id=modimpl.id,
"moyenne": { ),
# # moyenne indicative de module: moyenne des UE, ignorant celles sans notes (nan) "moyenne": {
# "value": fmt_note(moy_indicative_mod), # # moyenne indicative de module: moyenne des UE, ignorant celles sans notes (nan)
# "min": fmt_note(moyennes_etuds.min()), # "value": fmt_note(moy_indicative_mod),
# "max": fmt_note(moyennes_etuds.max()), # "min": fmt_note(moyennes_etuds.min()),
# "moy": fmt_note(moyennes_etuds.mean()), # "max": fmt_note(moyennes_etuds.max()),
}, # "moy": fmt_note(moyennes_etuds.mean()),
"evaluations": [ },
self.etud_eval_results(etud, e) "evaluations": [
for e in modimpl.evaluations self.etud_eval_results(etud, e)
if e.visibulletin for e in modimpl.evaluations
and modimpl_results.evaluations_etat[e.id].is_complete if e.visibulletin
], and modimpl_results.evaluations_etat[e.id].is_complete
} ],
}
return d return d
def etud_eval_results(self, etud, e) -> dict: def etud_eval_results(self, etud, e) -> dict:

View File

@ -68,11 +68,12 @@ def bulletin_but_xml_compat(
"bulletin_but_xml_compat( formsemestre_id=%s, etudid=%s )" "bulletin_but_xml_compat( formsemestre_id=%s, etudid=%s )"
% (formsemestre_id, etudid) % (formsemestre_id, etudid)
) )
sem = FormSemestre.query.get_or_404(formsemestre_id) formsemestre = FormSemestre.query.get_or_404(formsemestre_id)
etud = Identite.query.get_or_404(etudid) etud = Identite.query.get_or_404(etudid)
results = bulletin_but.ResultatsSemestreBUT(sem) results = bulletin_but.ResultatsSemestreBUT(formsemestre)
nb_inscrits = len(results.etuds) nb_inscrits = len(results.etuds)
if (not sem.bul_hide_xml) or force_publishing: etat_inscription = etud.etat_inscription(formsemestre.id)
if (not formsemestre.bul_hide_xml) or force_publishing:
published = 1 published = 1
else: else:
published = 0 published = 0
@ -86,10 +87,10 @@ def bulletin_but_xml_compat(
"date": docdate, "date": docdate,
"publie": str(published), "publie": str(published),
} }
if sem.etapes: if formsemestre.etapes:
el["etape_apo"] = sem.etapes[0].etape_apo or "" el["etape_apo"] = formsemestre.etapes[0].etape_apo or ""
n = 2 n = 2
for et in sem.etapes[1:]: for et in formsemestre.etapes[1:]:
el["etape_apo" + str(n)] = et.etape_apo or "" el["etape_apo" + str(n)] = et.etape_apo or ""
n += 1 n += 1
x = Element("bulletinetud", **el) x = Element("bulletinetud", **el)
@ -120,78 +121,72 @@ def bulletin_but_xml_compat(
return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode( return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode(
scu.SCO_ENCODING scu.SCO_ENCODING
) # stop ! ) # stop !
# Moyenne générale:
doc.append( if etat_inscription == scu.INSCRIT:
Element( # Moyenne générale:
"note", doc.append(
value=scu.fmt_note(results.etud_moy_gen[etud.id]),
min=scu.fmt_note(results.etud_moy_gen.min()),
max=scu.fmt_note(results.etud_moy_gen.max()),
moy=scu.fmt_note(results.etud_moy_gen.mean()), # moyenne des moy. gen.
)
)
rang = 0 # XXX TODO rang de l'étduiant selon la moy gen indicative
bonus = 0 # XXX TODO valeur du bonus sport
doc.append(Element("rang", value=str(rang), ninscrits=str(nb_inscrits)))
# XXX TODO: ajouter "rang_group" : rangs dans les partitions
doc.append(Element("note_max", value="20")) # notes toujours sur 20
doc.append(Element("bonus_sport_culture", value=str(bonus)))
# Liste les UE / modules /evals
for ue in results.ues:
rang_ue = 0 # XXX TODO rang de l'étudiant dans cette UE
nb_inscrits_ue = (
nb_inscrits # approx: compliqué de définir le "nb d'inscrit à une UE"
)
x_ue = Element(
"ue",
id=str(ue.id),
numero=scu.quote_xml_attr(ue.numero),
acronyme=scu.quote_xml_attr(ue.acronyme or ""),
titre=scu.quote_xml_attr(ue.titre or ""),
code_apogee=scu.quote_xml_attr(ue.code_apogee or ""),
)
doc.append(x_ue)
if ue.type != sco_codes_parcours.UE_SPORT:
v = results.etud_moy_ue[ue.id][etud.id]
else:
v = 0 # XXX TODO valeur bonus sport pour cet étudiant
x_ue.append(
Element( Element(
"note", "note",
value=scu.fmt_note(v), value=scu.fmt_note(results.etud_moy_gen[etud.id]),
min=scu.fmt_note(results.etud_moy_ue[ue.id].min()), min=scu.fmt_note(results.etud_moy_gen.min()),
max=scu.fmt_note(results.etud_moy_ue[ue.id].max()), max=scu.fmt_note(results.etud_moy_gen.max()),
moy=scu.fmt_note(results.etud_moy_gen.mean()), # moyenne des moy. gen.
) )
) )
x_ue.append(Element("ects", value=str(ue.ects if ue.ects else 0))) rang = 0 # XXX TODO rang de l'étduiant selon la moy gen indicative
x_ue.append(Element("rang", value=str(rang_ue))) bonus = 0 # XXX TODO valeur du bonus sport
x_ue.append(Element("effectif", value=str(nb_inscrits_ue))) doc.append(Element("rang", value=str(rang), ninscrits=str(nb_inscrits)))
# Liste les modules rattachés à cette UE # XXX TODO: ajouter "rang_group" : rangs dans les partitions
for modimpl in results.modimpls: doc.append(Element("note_max", value="20")) # notes toujours sur 20
# Liste ici uniquement les modules rattachés à cette UE doc.append(Element("bonus_sport_culture", value=str(bonus)))
if modimpl.module.ue.id == ue.id: # Liste les UE / modules /evals
mod_moy = scu.fmt_note(results.etud_moy_ue[ue.id][etud.id]) for ue in results.ues:
coef = results.modimpl_coefs_df[modimpl.id][ue.id] rang_ue = 0 # XXX TODO rang de l'étudiant dans cette UE
x_mod = Element( nb_inscrits_ue = (
"module", nb_inscrits # approx: compliqué de définir le "nb d'inscrit à une UE"
id=str(modimpl.id), )
code=str(modimpl.module.code or ""), x_ue = Element(
coefficient=str(coef), "ue",
numero=str(modimpl.module.numero or 0), id=str(ue.id),
titre=scu.quote_xml_attr(modimpl.module.titre or ""), numero=scu.quote_xml_attr(ue.numero),
abbrev=scu.quote_xml_attr(modimpl.module.abbrev or ""), acronyme=scu.quote_xml_attr(ue.acronyme or ""),
code_apogee=scu.quote_xml_attr(modimpl.module.code_apogee or ""), titre=scu.quote_xml_attr(ue.titre or ""),
code_apogee=scu.quote_xml_attr(ue.code_apogee or ""),
)
doc.append(x_ue)
if ue.type != sco_codes_parcours.UE_SPORT:
v = results.etud_moy_ue[ue.id][etud.id]
else:
v = 0 # XXX TODO valeur bonus sport pour cet étudiant
x_ue.append(
Element(
"note",
value=scu.fmt_note(v),
min=scu.fmt_note(results.etud_moy_ue[ue.id].min()),
max=scu.fmt_note(results.etud_moy_ue[ue.id].max()),
) )
x_ue.append(x_mod) )
x_mod.append( x_ue.append(Element("ects", value=str(ue.ects if ue.ects else 0)))
Element( x_ue.append(Element("rang", value=str(rang_ue)))
"note", x_ue.append(Element("effectif", value=str(nb_inscrits_ue)))
value=mod_moy, # Liste les modules rattachés à cette UE
min=scu.fmt_note(results.etud_moy_ue[ue.id].min()), for modimpl in results.modimpls:
max=scu.fmt_note(results.etud_moy_ue[ue.id].max()), # Liste ici uniquement les modules rattachés à cette UE
moy=scu.fmt_note(results.etud_moy_ue[ue.id].mean()), if modimpl.module.ue.id == ue.id:
# mod_moy = scu.fmt_note(results.etud_moy_ue[ue.id][etud.id])
coef = results.modimpl_coefs_df[modimpl.id][ue.id]
x_mod = Element(
"module",
id=str(modimpl.id),
code=str(modimpl.module.code or ""),
coefficient=str(coef),
numero=str(modimpl.module.numero or 0),
titre=scu.quote_xml_attr(modimpl.module.titre or ""),
abbrev=scu.quote_xml_attr(modimpl.module.abbrev or ""),
code_apogee=scu.quote_xml_attr(
modimpl.module.code_apogee or ""
),
) )
)
# XXX TODO rangs et effectifs # XXX TODO rangs et effectifs
# --- notes de chaque eval: # --- notes de chaque eval:
if version != "short": if version != "short":
@ -226,11 +221,11 @@ def bulletin_but_xml_compat(
) )
) )
# XXX TODO: Evaluations incomplètes ou futures: XXX # XXX TODO: Evaluations incomplètes ou futures: XXX
# XXX TODO UE capitalisee (listee seulement si meilleure que l'UE courante) # XXX TODO UE capitalisee (listee seulement si meilleure que l'UE courante)
# --- Absences # --- Absences
if sco_preferences.get_preference("bul_show_abs", formsemestre_id): if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
nbabs, nbabsjust = sem.get_abs_count(etud.id) nbabs, nbabsjust = formsemestre.get_abs_count(etud.id)
doc.append(Element("absences", nbabs=str(nbabs), nbabsjust=str(nbabsjust))) doc.append(Element("absences", nbabs=str(nbabs), nbabsjust=str(nbabsjust)))
# -------- LA SUITE EST COPIEE SANS MODIF DE sco_bulletins_xml.py --------- # -------- LA SUITE EST COPIEE SANS MODIF DE sco_bulletins_xml.py ---------

View File

@ -44,6 +44,9 @@ class ModuleImpl(db.Model):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(ModuleImpl, self).__init__(**kwargs) super(ModuleImpl, self).__init__(**kwargs)
def __repr__(self):
return f"<{self.__class__.__name__} {self.id} module={repr(self.module)}>"
def get_evaluations_poids(self) -> pd.DataFrame: def get_evaluations_poids(self) -> pd.DataFrame:
"""Les poids des évaluations vers les UE (accès via cache)""" """Les poids des évaluations vers les UE (accès via cache)"""
evaluations_poids = df_cache.EvaluationsPoidsCache.get(self.id) evaluations_poids = df_cache.EvaluationsPoidsCache.get(self.id)

View File

@ -470,7 +470,13 @@ def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False):
if ue.modules.all(): if ue.modules.all():
raise ScoValueError( raise ScoValueError(
f"""Suppression de l'UE {ue.titre} impossible car f"""Suppression de l'UE {ue.titre} impossible car
des modules (ou SAÉ ou ressources) lui sont rattachés.""" des modules (ou SAÉ ou ressources) lui sont rattachés.""",
dest_url=url_for(
"notes.ue_table",
scodoc_dept=g.scodoc_dept,
formation_id=ue.formation.id,
semestre_idx=ue.semestre_idx,
),
) )
if not can_delete_ue(ue): if not can_delete_ue(ue):
raise ScoNonEmptyFormationObject( raise ScoNonEmptyFormationObject(

View File

@ -77,6 +77,17 @@ section>div:nth-child(1){
display: flex !important; display: flex !important;
} }
.listeOff .ue::before,
.listeOff .module::before,
.moduleOnOff .ue::before,
.moduleOnOff .module::before{
transform: rotate(0);
}
.listeOff .moduleOnOff .ue::before,
.listeOff .moduleOnOff .module::before{
transform: rotate(180deg) !important;
}
/***********************/ /***********************/
/* Options d'affichage */ /* Options d'affichage */
/***********************/ /***********************/
@ -118,11 +129,16 @@ section>div:nth-child(1){
/************/ /************/
/* Semestre */ /* Semestre */
/************/ /************/
.flex{
display: flex;
gap: 16px;
}
.infoSemestre{ .infoSemestre{
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
gap: 4px; gap: 4px;
flex: none;
} }
.infoSemestre>div{ .infoSemestre>div{
border: 1px solid var(--couleurIntense); border: 1px solid var(--couleurIntense);
@ -141,7 +157,12 @@ section>div:nth-child(1){
.rang{ .rang{
text-decoration: underline var(--couleurIntense); text-decoration: underline var(--couleurIntense);
} }
.decision{
margin: 5px 0;
font-weight: bold;
font-size: 20px;
text-decoration: underline var(--couleurIntense);
}
.enteteSemestre{ .enteteSemestre{
color: black; color: black;
font-weight: bold; font-weight: bold;
@ -174,8 +195,21 @@ section>div:nth-child(1){
display: flex; display: flex;
gap: 16px; gap: 16px;
margin: 4px 0 2px 0; margin: 4px 0 2px 0;
overflow: auto; overflow-x: auto;
overflow-y: hidden;
cursor: pointer; cursor: pointer;
position: relative;
}
.module::before, .ue::before {
content:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='26px' height='26px' fill='black'><path d='M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z' /></svg>");
width: 26px;
height: 26px;
position: absolute;
bottom: 0;
left: 50%;
margin-left: -13px;
transform: rotate(180deg);
transition: 0.2s;
} }
h3{ h3{
display: flex; display: flex;

View File

@ -75,10 +75,15 @@ class releveBUT extends HTMLElement {
<!---------------------------> <!--------------------------->
<section> <section>
<h2>Semestre </h2> <h2>Semestre </h2>
<div class=dateInscription>Inscrit le </div> <div class=flex>
<em>Les moyennes servent à situer l'étudiant dans la promotion et ne correspondent pas à des validations de <div class=infoSemestre></div>
compétences ou d'UE.</em> <div>
<div class=infoSemestre></div> <div class=decision>Validé !</div>
<div class=dateInscription>Inscrit le </div>
<em>Les moyennes servent à situer l'étudiant dans la promotion et ne correspondent pas à des validations de compétences ou d'UE.</em>
</div>
</div>
</section> </section>
<!---------------------------> <!--------------------------->
@ -91,8 +96,7 @@ class releveBUT extends HTMLElement {
<em>La moyenne des ressources dans une UE dépend des poids donnés aux évaluations.</em> <em>La moyenne des ressources dans une UE dépend des poids donnés aux évaluations.</em>
</div> </div>
<div class=CTA_Liste> <div class=CTA_Liste>
Liste <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" Liste <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 15l-6-6-6 6" /> <path d="M18 15l-6-6-6 6" />
</svg> </svg>
</div> </div>
@ -107,8 +111,7 @@ class releveBUT extends HTMLElement {
<div> <div>
<h2>Ressources</h2> <h2>Ressources</h2>
<div class=CTA_Liste> <div class=CTA_Liste>
Liste <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" Liste <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 15l-6-6-6 6" /> <path d="M18 15l-6-6-6 6" />
</svg> </svg>
</div> </div>
@ -120,8 +123,7 @@ class releveBUT extends HTMLElement {
<div> <div>
<h2>SAÉ</h2> <h2>SAÉ</h2>
<div class=CTA_Liste> <div class=CTA_Liste>
Liste <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" Liste <svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 15l-6-6-6 6" /> <path d="M18 15l-6-6-6 6" />
</svg> </svg>
</div> </div>
@ -187,9 +189,9 @@ class releveBUT extends HTMLElement {
<div>Max. promo. :</div><div>${data.semestre.notes.max}</div> <div>Max. promo. :</div><div>${data.semestre.notes.max}</div>
<div>Moy. promo. :</div><div>${data.semestre.notes.moy}</div> <div>Moy. promo. :</div><div>${data.semestre.notes.moy}</div>
<div>Min. promo. :</div><div>${data.semestre.notes.min}</div> <div>Min. promo. :</div><div>${data.semestre.notes.min}</div>
</div> </div>`;
${data.semestre.groupes.map(groupe => { /*${data.semestre.groupes.map(groupe => {
return ` return `
<div> <div>
<div class=enteteSemestre>Groupe</div><div class=enteteSemestre>${groupe.nom}</div> <div class=enteteSemestre>Groupe</div><div class=enteteSemestre>${groupe.nom}</div>
<div class=rang>Rang :</div><div class=rang>${groupe.rang.value} / ${groupe.rang.total}</div> <div class=rang>Rang :</div><div class=rang>${groupe.rang.value} / ${groupe.rang.total}</div>
@ -198,10 +200,10 @@ class releveBUT extends HTMLElement {
<div>Min. groupe :</div><div>${groupe.notes.min}</div> <div>Min. groupe :</div><div>${groupe.notes.min}</div>
</div> </div>
`; `;
}).join("") }).join("")
} }*/
`;
this.shadow.querySelector(".infoSemestre").innerHTML = output; this.shadow.querySelector(".infoSemestre").innerHTML = output;
this.shadow.querySelector(".decision").innerHTML = data.semestre.decision.code;
} }
/*******************************/ /*******************************/