diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py index 0eb28fe402..3cba7fc542 100644 --- a/app/but/bulletin_but.py +++ b/app/but/bulletin_but.py @@ -30,17 +30,18 @@ class BulletinBUT(ResultatsSemestreBUT): ue_idx = self.modimpl_coefs_df.index.get_loc(ue.id) etud_moy_module = self.sem_cube[etud_idx] # module x UE for modimpl in modimpls: - coef = self.modimpl_coefs_df[modimpl.id][ue.id] - if coef > 0: - d[modimpl.module.code] = { - "id": modimpl.id, - "coef": coef, - "moyenne": fmt_note( - etud_moy_module[ - self.modimpl_coefs_df.columns.get_loc(modimpl.id) - ][ue_idx] - ), - } + if self.modimpl_inscr_df[str(modimpl.id)][etud.id]: # si inscrit + coef = self.modimpl_coefs_df[modimpl.id][ue.id] + if coef > 0: + d[modimpl.module.code] = { + "id": modimpl.id, + "coef": coef, + "moyenne": fmt_note( + etud_moy_module[ + self.modimpl_coefs_df.columns.get_loc(modimpl.id) + ][ue_idx] + ), + } return d def etud_ue_results(self, etud, ue): @@ -87,29 +88,30 @@ class BulletinBUT(ResultatsSemestreBUT): # except RuntimeWarning: # all nans in np.nanmean # pass modimpl_results = self.modimpls_results[modimpl.id] - d[modimpl.module.code] = { - "id": modimpl.id, - "titre": modimpl.module.titre, - "code_apogee": modimpl.module.code_apogee, - "url": url_for( - "notes.moduleimpl_status", - scodoc_dept=g.scodoc_dept, - moduleimpl_id=modimpl.id, - ), - "moyenne": { - # # moyenne indicative de module: moyenne des UE, ignorant celles sans notes (nan) - # "value": fmt_note(moy_indicative_mod), - # "min": fmt_note(moyennes_etuds.min()), - # "max": fmt_note(moyennes_etuds.max()), - # "moy": fmt_note(moyennes_etuds.mean()), - }, - "evaluations": [ - self.etud_eval_results(etud, e) - for e in modimpl.evaluations - if e.visibulletin - and modimpl_results.evaluations_etat[e.id].is_complete - ], - } + if self.modimpl_inscr_df[str(modimpl.id)][etud.id]: # si inscrit + d[modimpl.module.code] = { + "id": modimpl.id, + "titre": modimpl.module.titre, + "code_apogee": modimpl.module.code_apogee, + "url": url_for( + "notes.moduleimpl_status", + scodoc_dept=g.scodoc_dept, + moduleimpl_id=modimpl.id, + ), + "moyenne": { + # # moyenne indicative de module: moyenne des UE, ignorant celles sans notes (nan) + # "value": fmt_note(moy_indicative_mod), + # "min": fmt_note(moyennes_etuds.min()), + # "max": fmt_note(moyennes_etuds.max()), + # "moy": fmt_note(moyennes_etuds.mean()), + }, + "evaluations": [ + self.etud_eval_results(etud, e) + for e in modimpl.evaluations + if e.visibulletin + and modimpl_results.evaluations_etat[e.id].is_complete + ], + } return d def etud_eval_results(self, etud, e) -> dict: diff --git a/app/but/bulletin_but_xml_compat.py b/app/but/bulletin_but_xml_compat.py index 9b0996c134..b3398ef9bb 100644 --- a/app/but/bulletin_but_xml_compat.py +++ b/app/but/bulletin_but_xml_compat.py @@ -68,11 +68,12 @@ def bulletin_but_xml_compat( "bulletin_but_xml_compat( formsemestre_id=%s, etudid=%s )" % (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) - results = bulletin_but.ResultatsSemestreBUT(sem) + results = bulletin_but.ResultatsSemestreBUT(formsemestre) 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 else: published = 0 @@ -86,10 +87,10 @@ def bulletin_but_xml_compat( "date": docdate, "publie": str(published), } - if sem.etapes: - el["etape_apo"] = sem.etapes[0].etape_apo or "" + if formsemestre.etapes: + el["etape_apo"] = formsemestre.etapes[0].etape_apo or "" n = 2 - for et in sem.etapes[1:]: + for et in formsemestre.etapes[1:]: el["etape_apo" + str(n)] = et.etape_apo or "" n += 1 x = Element("bulletinetud", **el) @@ -120,78 +121,72 @@ def bulletin_but_xml_compat( return sco_xml.XML_HEADER + ElementTree.tostring(doc).decode( scu.SCO_ENCODING ) # stop ! - # Moyenne générale: - doc.append( - Element( - "note", - 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( + + if etat_inscription == scu.INSCRIT: + # Moyenne générale: + doc.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()), + 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. ) ) - x_ue.append(Element("ects", value=str(ue.ects if ue.ects else 0))) - x_ue.append(Element("rang", value=str(rang_ue))) - x_ue.append(Element("effectif", value=str(nb_inscrits_ue))) - # Liste les modules rattachés à cette UE - for modimpl in results.modimpls: - # Liste ici uniquement les modules rattachés à cette UE - 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 ""), + 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( + "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( - Element( - "note", - value=mod_moy, - min=scu.fmt_note(results.etud_moy_ue[ue.id].min()), - max=scu.fmt_note(results.etud_moy_ue[ue.id].max()), - moy=scu.fmt_note(results.etud_moy_ue[ue.id].mean()), + ) + x_ue.append(Element("ects", value=str(ue.ects if ue.ects else 0))) + x_ue.append(Element("rang", value=str(rang_ue))) + x_ue.append(Element("effectif", value=str(nb_inscrits_ue))) + # Liste les modules rattachés à cette UE + for modimpl in results.modimpls: + # Liste ici uniquement les modules rattachés à cette UE + 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 # --- notes de chaque eval: if version != "short": @@ -226,11 +221,11 @@ def bulletin_but_xml_compat( ) ) # 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 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))) # -------- LA SUITE EST COPIEE SANS MODIF DE sco_bulletins_xml.py --------- diff --git a/app/models/moduleimpls.py b/app/models/moduleimpls.py index fe48555efa..2aa36da9cb 100644 --- a/app/models/moduleimpls.py +++ b/app/models/moduleimpls.py @@ -44,6 +44,9 @@ class ModuleImpl(db.Model): def __init__(self, **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: """Les poids des évaluations vers les UE (accès via cache)""" evaluations_poids = df_cache.EvaluationsPoidsCache.get(self.id) diff --git a/app/scodoc/sco_edit_ue.py b/app/scodoc/sco_edit_ue.py index 07ff217ab4..6b7884591a 100644 --- a/app/scodoc/sco_edit_ue.py +++ b/app/scodoc/sco_edit_ue.py @@ -470,7 +470,13 @@ def ue_delete(ue_id=None, delete_validations=False, dialog_confirmed=False): if ue.modules.all(): raise ScoValueError( 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): raise ScoNonEmptyFormationObject( diff --git a/app/static/css/releve-but.css b/app/static/css/releve-but.css index 60d4f01c1e..3f132d6a40 100644 --- a/app/static/css/releve-but.css +++ b/app/static/css/releve-but.css @@ -77,6 +77,17 @@ section>div:nth-child(1){ 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 */ /***********************/ @@ -118,11 +129,16 @@ section>div:nth-child(1){ /************/ /* Semestre */ /************/ +.flex{ + display: flex; + gap: 16px; +} .infoSemestre{ display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; + flex: none; } .infoSemestre>div{ border: 1px solid var(--couleurIntense); @@ -141,7 +157,12 @@ section>div:nth-child(1){ .rang{ text-decoration: underline var(--couleurIntense); } - +.decision{ + margin: 5px 0; + font-weight: bold; + font-size: 20px; + text-decoration: underline var(--couleurIntense); +} .enteteSemestre{ color: black; font-weight: bold; @@ -174,8 +195,21 @@ section>div:nth-child(1){ display: flex; gap: 16px; margin: 4px 0 2px 0; - overflow: auto; + overflow-x: auto; + overflow-y: hidden; cursor: pointer; + position: relative; +} +.module::before, .ue::before { + content:url("data:image/svg+xml;utf8,"); + width: 26px; + height: 26px; + position: absolute; + bottom: 0; + left: 50%; + margin-left: -13px; + transform: rotate(180deg); + transition: 0.2s; } h3{ display: flex; diff --git a/app/static/js/releve-but.js b/app/static/js/releve-but.js index 126cb219ea..5042031b37 100644 --- a/app/static/js/releve-but.js +++ b/app/static/js/releve-but.js @@ -75,10 +75,15 @@ class releveBUT extends HTMLElement {

Semestre

-
Inscrit le
- Les moyennes servent à situer l'étudiant dans la promotion et ne correspondent pas à des validations de - compétences ou d'UE. -
+
+
+
+
Validé !
+
Inscrit le
+ Les moyennes servent à situer l'étudiant dans la promotion et ne correspondent pas à des validations de compétences ou d'UE. +
+
+
@@ -91,8 +96,7 @@ class releveBUT extends HTMLElement { La moyenne des ressources dans une UE dépend des poids donnés aux évaluations.
- Liste + Liste
@@ -107,8 +111,7 @@ class releveBUT extends HTMLElement {

Ressources

- Liste + Liste
@@ -120,8 +123,7 @@ class releveBUT extends HTMLElement {

SAÉ

- Liste + Liste
@@ -187,9 +189,9 @@ class releveBUT extends HTMLElement {
Max. promo. :
${data.semestre.notes.max}
Moy. promo. :
${data.semestre.notes.moy}
Min. promo. :
${data.semestre.notes.min}
-
- ${data.semestre.groupes.map(groupe => { - return ` +
`; + /*${data.semestre.groupes.map(groupe => { + return `
Groupe
${groupe.nom}
Rang :
${groupe.rang.value} / ${groupe.rang.total}
@@ -198,10 +200,10 @@ class releveBUT extends HTMLElement {
Min. groupe :
${groupe.notes.min}
`; - }).join("") - } - `; + }).join("") + }*/ this.shadow.querySelector(".infoSemestre").innerHTML = output; + this.shadow.querySelector(".decision").innerHTML = data.semestre.decision.code; } /*******************************/