forked from ScoDoc/ScoDoc
Dispenses d'UE: corrige affichage en table recap. Intègre aux tests unitaires cursus. Légendes.
This commit is contained in:
parent
3ba5318b17
commit
39466bf9b5
@ -260,8 +260,10 @@ class UniteEns(db.Model):
|
||||
|
||||
class DispenseUE(db.Model):
|
||||
"""Dispense d'UE
|
||||
Utilisé en APC (BUT) pour indiquer les étudiants redoublants avec une UE capitalisée
|
||||
qu'ils ne refont pas.
|
||||
Utilisé en APC (BUT) pour indiquer
|
||||
- les étudiants redoublants avec une UE capitalisée qu'ils ne refont pas.
|
||||
- les étudiants "non inscrit" à une UE car elle ne fait pas partie de leur Parcours.
|
||||
|
||||
La dispense d'UE n'est PAS une validation:
|
||||
- elle n'est pas affectée par les décisions de jury (pas effacée)
|
||||
- elle est associée à un formsemestre
|
||||
|
@ -613,11 +613,16 @@ def _list_but_ue_inscriptions(res: NotesTableCompat, read_only: bool = True) ->
|
||||
</table>
|
||||
</form>
|
||||
<div class="help">
|
||||
L'inscription ou désinscription aux UEs du BUT n'affecte pas les inscriptions aux modules
|
||||
<p>L'inscription ou désinscription aux UEs du BUT n'affecte pas les inscriptions aux modules
|
||||
mais permet de "dispenser" un étudiant de suivre certaines UEs de son parcours.
|
||||
Il peut s'agit d'étudiants redoublants ayant déjà acquis l'UE, ou d'autres cas particuliers.
|
||||
La dispense d'UE est réversible à tout moment (avant le jury de fin de semestre)
|
||||
</p>
|
||||
<p>Il peut s'agit d'étudiants redoublants ayant déjà acquis l'UE, ou d'une UE
|
||||
présente dans le semestre mais pas dans le parcours de l'étudiant, ou bien d'autres
|
||||
cas particuliers.
|
||||
</p>
|
||||
<p>La dispense d'UE est réversible à tout moment (avant le jury de fin de semestre)
|
||||
et n'affecte pas les notes saisies.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
@ -242,7 +242,19 @@ def formsemestre_recapcomplet(
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
|
||||
# Légende
|
||||
H.append(
|
||||
"""
|
||||
<div class="table_recap_caption">
|
||||
<div class="title">Codes utilisés dans cette table:</div>
|
||||
<div class="captions">
|
||||
<div><tt>~</tt></div><div>valeur manquante</div>
|
||||
<div><tt>=</tt></div><div>UE dispensée</div>
|
||||
<div><tt>nan</tt></div><div>valeur non disponible</div>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
)
|
||||
H.append(html_sco_header.sco_footer())
|
||||
# HTML or binary data ?
|
||||
if len(H) > 1:
|
||||
|
@ -2672,6 +2672,30 @@ table.notes_recapcomplet a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.table_recap_caption {
|
||||
width: fit-content;
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
background-color: rgb(202, 255, 180);
|
||||
}
|
||||
|
||||
div.table_recap_caption div.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.table_recap_caption div.captions {
|
||||
display: grid;
|
||||
grid-template-columns: 48px 200px;
|
||||
}
|
||||
|
||||
div.table_recap_caption div.captions div:nth-child(odd) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.table_recap_caption div.captions div:nth-child(even) {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* bulletin */
|
||||
div.notes_bulletin {
|
||||
margin-right: 5px;
|
||||
|
@ -154,7 +154,7 @@ class TableJury(TableRecap):
|
||||
niveau: ApcNiveau = validation_rcue.niveau()
|
||||
titre = f"C{niveau.competence.numero}" # à voir (nommer les compétences...)
|
||||
row.add_cell(
|
||||
f"c_{competence_id}_annee",
|
||||
f"c_{competence_id}_{annee}",
|
||||
titre,
|
||||
validation_rcue.code,
|
||||
group="cursus_" + annee,
|
||||
|
@ -285,9 +285,9 @@ class TableRecap(tb.Table):
|
||||
notes = res.modimpl_notes(modimpl.id, ue.id)
|
||||
if np.isnan(notes).all():
|
||||
# aucune note valide
|
||||
row_min.add_cell(col_id, None, np.nan)
|
||||
row_max.add_cell(col_id, None, np.nan)
|
||||
moy = np.nan
|
||||
row_min.add_cell(col_id, None, "")
|
||||
row_max.add_cell(col_id, None, "")
|
||||
moy = ""
|
||||
else:
|
||||
row_min.add_cell(col_id, None, self.fmt_note(np.nanmin(notes)))
|
||||
row_max.add_cell(col_id, None, self.fmt_note(np.nanmax(notes)))
|
||||
@ -297,7 +297,7 @@ class TableRecap(tb.Table):
|
||||
None,
|
||||
self.fmt_note(moy),
|
||||
# aucune note dans ce module ?
|
||||
classes=["col_empty" if np.isnan(moy) else ""],
|
||||
classes=["col_empty" if (moy == "" or np.isnan(moy)) else ""],
|
||||
)
|
||||
row_apo.add_cell(col_id, None, modimpl.module.code_apogee or "")
|
||||
|
||||
@ -618,7 +618,7 @@ class RowRecap(tb.Row):
|
||||
):
|
||||
"""Ajoute cols moy_gen moy_ue et tous les modules..."""
|
||||
etud = self.etud
|
||||
table = self.table
|
||||
table: TableRecap = self.table
|
||||
res = table.res
|
||||
# --- Si DEM ou DEF, ne montre aucun résultat d'UE ni moy. gen.
|
||||
if res.get_etud_etat(etud.id) != scu.INSCRIT:
|
||||
@ -701,13 +701,17 @@ class RowRecap(tb.Row):
|
||||
def add_ue_cols(self, ue: UniteEns, ue_status: dict, col_group: str = None):
|
||||
"Ajoute résultat UE au row (colonne col_ue)"
|
||||
# sous-classé par JuryRow pour ajouter les codes
|
||||
table = self.table
|
||||
table: TableRecap = self.table
|
||||
formsemestre: FormSemestre = table.res.formsemestre
|
||||
table.group_titles[
|
||||
"col_ue"
|
||||
] = f"UEs du S{formsemestre.semestre_id} {formsemestre.annee_scolaire()}"
|
||||
col_id = f"moy_ue_{ue.id}"
|
||||
val = ue_status["moy"]
|
||||
val = (
|
||||
ue_status["moy"]
|
||||
if (self.etud.id, ue.id) not in table.res.dispense_ues
|
||||
else "="
|
||||
)
|
||||
note_classes = []
|
||||
if isinstance(val, float):
|
||||
if val < table.barre_moy:
|
||||
|
@ -134,7 +134,7 @@ FormSemestres:
|
||||
codes_parcours: ['BAT', 'TP']
|
||||
|
||||
Etudiants:
|
||||
A_ok: # Etudiant qui va tout valider directement
|
||||
A_ok: # Etudiant parcours BAT qui va tout valider directement
|
||||
prenom: Étudiant_BAT
|
||||
civilite: M
|
||||
formsemestres:
|
||||
@ -157,9 +157,41 @@ Etudiants:
|
||||
|
||||
S5:
|
||||
parcours: BAT
|
||||
dispense_ues: ['UE5.2']
|
||||
notes_modules:
|
||||
"R5.01": 15 # toutes UE
|
||||
"SAÉ 5.BAT.01": 10 # UE5.1
|
||||
"SAÉ 5.BAT.02": 11 # UE5.4
|
||||
S6:
|
||||
parcours: BAT
|
||||
|
||||
B_ok: # Etudiant parcours TP qui va tout valider directement
|
||||
prenom: Étudiant_TP
|
||||
civilite: M
|
||||
formsemestres:
|
||||
S1:
|
||||
parcours: TP
|
||||
notes_modules:
|
||||
"R1.01": 11 # toutes UEs
|
||||
S2:
|
||||
parcours: TP
|
||||
notes_modules:
|
||||
"R2.01": 12 # toutes UEs
|
||||
S3:
|
||||
parcours: TP
|
||||
notes_modules:
|
||||
"R3.01": 13 # toutes UEs
|
||||
S4:
|
||||
parcours: TP
|
||||
notes_modules:
|
||||
"R4.01": 14 # toutes UE
|
||||
|
||||
S5:
|
||||
parcours: TP
|
||||
dispense_ues: ['UE5.1']
|
||||
notes_modules:
|
||||
"R5.01": 15 # toutes UE
|
||||
"SAÉ 5.BAT.01": 10 # UE5.1
|
||||
"SAÉ 5.BAT.02": 11 # UE5.4
|
||||
S6:
|
||||
parcours: TP
|
||||
|
@ -53,12 +53,14 @@ from app.auth.models import User
|
||||
|
||||
from app.models import (
|
||||
ApcParcours,
|
||||
DispenseUE,
|
||||
Evaluation,
|
||||
Formation,
|
||||
FormSemestre,
|
||||
Identite,
|
||||
Module,
|
||||
ModuleImpl,
|
||||
UniteEns,
|
||||
)
|
||||
|
||||
from app.scodoc import sco_formations
|
||||
@ -263,6 +265,9 @@ def inscrit_les_etudiants(formation: Formation, doc: dict):
|
||||
group_ids = [group.id]
|
||||
else:
|
||||
group_ids = []
|
||||
# Génère des dispenses d'UEs
|
||||
if "dispense_ues" in sem_infos:
|
||||
etud_dispense_ues(formsemestre, etud, sem_infos["dispense_ues"])
|
||||
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
|
||||
formsemestre.id,
|
||||
etud.id,
|
||||
@ -275,6 +280,19 @@ def inscrit_les_etudiants(formation: Formation, doc: dict):
|
||||
formsemestre.update_inscriptions_parcours_from_groups()
|
||||
|
||||
|
||||
def etud_dispense_ues(
|
||||
formsemestre: FormSemestre, etud: Identite, ue_acronymes: list[str]
|
||||
):
|
||||
"""Génère des dispenses d'UE"""
|
||||
for ue_acronyme in set(ue_acronymes):
|
||||
ue: UniteEns = formsemestre.formation.ues.filter_by(
|
||||
acronyme=ue_acronyme
|
||||
).first()
|
||||
assert ue
|
||||
disp = DispenseUE(formsemestre_id=formsemestre.id, ue_id=ue.id, etudid=etud.id)
|
||||
db.session.add(disp)
|
||||
|
||||
|
||||
def setup_from_yaml(filename: str) -> dict:
|
||||
"""Lit le fichier yaml et construit l'ensemble des objets"""
|
||||
with open(filename, encoding="utf-8") as f:
|
||||
|
Loading…
Reference in New Issue
Block a user