Table recap: UE validables. Closes #260

This commit is contained in:
Emmanuel Viennet 2022-04-02 14:26:16 +02:00
parent c65689b2a3
commit 0d726aa428
5 changed files with 1470 additions and 1010 deletions

View File

@ -419,21 +419,23 @@ class ResultatsSemestre(ResultatsCache):
else: else:
fmt_note = lambda x: x fmt_note = lambda x: x
barre_moy = ( parcours = self.formsemestre.formation.get_parcours()
self.formsemestre.formation.get_parcours().BARRE_MOY - scu.NOTES_TOLERANCE barre_moy = parcours.BARRE_MOY - scu.NOTES_TOLERANCE
) barre_valid_ue = parcours.NOTES_BARRE_VALID_UE
barre_valid_ue = self.formsemestre.formation.get_parcours().NOTES_BARRE_VALID_UE barre_warning_ue = parcours.BARRE_UE_DISPLAY_WARNING
NO_NOTE = "-" # contenu des cellules sans notes NO_NOTE = "-" # contenu des cellules sans notes
rows = [] rows = []
# column_id : title # column_id : title
titles = { titles = {
"rang": "Rg", "rang": "Rg",
# ordre des colonnes: # ordre des colonnes de gauche à droite:
"_civilite_str_col_order": 2, "_civilite_str_col_order": 2,
"_nom_disp_col_order": 3, "_nom_disp_col_order": 3,
"_prenom_col_order": 4, "_prenom_col_order": 4,
"_nom_short_col_order": 5, "_nom_short_col_order": 5,
"_rang_col_order": 6, "_rang_col_order": 6,
# les colonnes des groupes sont à la position 10
"_ues_validables_col_order": 20,
} }
# les titres en footer: les mêmes, mais avec des bulles et liens: # les titres en footer: les mêmes, mais avec des bulles et liens:
titles_bot = {} titles_bot = {}
@ -452,6 +454,7 @@ class ResultatsSemestre(ResultatsCache):
etuds_inscriptions = self.formsemestre.etuds_inscriptions etuds_inscriptions = self.formsemestre.etuds_inscriptions
ues = self.formsemestre.query_ues(with_sport=True) # avec bonus ues = self.formsemestre.query_ues(with_sport=True) # avec bonus
ues_sans_bonus = [ue for ue in ues if ue.type != UE_SPORT]
modimpl_ids = set() # modimpl effectivement présents dans la table modimpl_ids = set() # modimpl effectivement présents dans la table
for etudid in etuds_inscriptions: for etudid in etuds_inscriptions:
etud = Identite.query.get(etudid) etud = Identite.query.get(etudid)
@ -479,7 +482,7 @@ class ResultatsSemestre(ResultatsCache):
if moy_gen is False: if moy_gen is False:
moy_gen = NO_NOTE moy_gen = NO_NOTE
elif isinstance(moy_gen, float) and moy_gen < barre_moy: elif isinstance(moy_gen, float) and moy_gen < barre_moy:
note_class = " moy_inf" note_class = " moy_ue_warning" # en rouge
add_cell( add_cell(
row, row,
"moy_gen", "moy_gen",
@ -491,7 +494,8 @@ class ResultatsSemestre(ResultatsCache):
'title="moyenne indicative"' if self.is_apc else "" 'title="moyenne indicative"' if self.is_apc else ""
) )
# --- Moyenne d'UE # --- Moyenne d'UE
for ue in [ue for ue in ues if ue.type != UE_SPORT]: nb_ues_validables, nb_ues_warning = 0, 0
for ue in ues_sans_bonus:
ue_status = self.get_etud_ue_status(etudid, ue.id) ue_status = self.get_etud_ue_status(etudid, ue.id)
if ue_status is not None: if ue_status is not None:
col_id = f"moy_ue_{ue.id}" col_id = f"moy_ue_{ue.id}"
@ -502,6 +506,10 @@ class ResultatsSemestre(ResultatsCache):
note_class = " moy_inf" note_class = " moy_inf"
elif val >= barre_valid_ue: elif val >= barre_valid_ue:
note_class = " moy_ue_valid" note_class = " moy_ue_valid"
nb_ues_validables += 1
if val < barre_warning_ue:
note_class = " moy_ue_warning" # notes très basses
nb_ues_warning += 1
add_cell( add_cell(
row, row,
col_id, col_id,
@ -557,7 +565,21 @@ class ResultatsSemestre(ResultatsCache):
title="{modimpl.module.titre} title="{modimpl.module.titre}
({sco_users.user_info(modimpl.responsable_id)['nomcomplet']})" """ ({sco_users.user_info(modimpl.responsable_id)['nomcomplet']})" """
modimpl_ids.add(modimpl.id) modimpl_ids.add(modimpl.id)
ue_valid_txt = f"{nb_ues_validables}/{len(ues_sans_bonus)}"
if nb_ues_warning:
ue_valid_txt += " " + scu.EMO_WARNING
add_cell(
row,
"ues_validables",
"Nb UE",
ue_valid_txt,
"col_ue col_ues_validables",
)
if nb_ues_warning:
row["_ues_validables_class"] += " moy_ue_warning"
elif nb_ues_validables < len(ues_sans_bonus):
row["_ues_validables_class"] += " moy_inf"
row["_ues_validables_order"] = nb_ues_validables # pour tri
rows.append(row) rows.append(row)
self._recap_add_partitions(rows, titles) self._recap_add_partitions(rows, titles)
self._recap_add_admissions(rows, titles) self._recap_add_admissions(rows, titles)
@ -565,9 +587,7 @@ class ResultatsSemestre(ResultatsCache):
rows.sort(key=lambda e: e["_rang_order"]) rows.sort(key=lambda e: e["_rang_order"])
# INFOS POUR FOOTER # INFOS POUR FOOTER
bottom_infos = self._recap_bottom_infos( bottom_infos = self._recap_bottom_infos(ues_sans_bonus, modimpl_ids, fmt_note)
[ue for ue in ues if ue.type != UE_SPORT], modimpl_ids, fmt_note
)
# --- TABLE FOOTER: ECTS, moyennes, min, max... # --- TABLE FOOTER: ECTS, moyennes, min, max...
footer_rows = [] footer_rows = []
@ -667,7 +687,7 @@ class ResultatsSemestre(ResultatsCache):
def _recap_add_admissions(self, rows: list[dict], titles: dict): def _recap_add_admissions(self, rows: list[dict], titles: dict):
"""Ajoute les colonnes "admission" """Ajoute les colonnes "admission"
rows est une liste de dict avec un clé "etudid" rows est une liste de dict avec une clé "etudid"
Les colonnes ont la classe css "admission" Les colonnes ont la classe css "admission"
""" """
fields = { fields = {
@ -693,7 +713,7 @@ class ResultatsSemestre(ResultatsCache):
def _recap_add_partitions(self, rows: list[dict], titles: dict): def _recap_add_partitions(self, rows: list[dict], titles: dict):
"""Ajoute les colonnes indiquant les groupes """Ajoute les colonnes indiquant les groupes
rows est une liste de dict avec un clé "etudid" rows est une liste de dict avec une clé "etudid"
Les colonnes ont la classe css "partition" Les colonnes ont la classe css "partition"
""" """
partitions, partitions_etud_groups = sco_groups.get_formsemestre_groups( partitions, partitions_etud_groups = sco_groups.get_formsemestre_groups(

View File

@ -51,8 +51,8 @@ from app.scodoc.sco_formsemestre import (
from app.scodoc.sco_codes_parcours import ( from app.scodoc.sco_codes_parcours import (
DEF, DEF,
UE_SPORT, UE_SPORT,
UE_is_fondamentale, ue_is_fondamentale,
UE_is_professionnelle, ue_is_professionnelle,
) )
from app.scodoc.sco_parcours_dut import formsemestre_get_etud_capitalisation from app.scodoc.sco_parcours_dut import formsemestre_get_etud_capitalisation
from app.scodoc import sco_codes_parcours from app.scodoc import sco_codes_parcours
@ -826,11 +826,11 @@ class NotesTable:
and mu["moy"] >= self.parcours.NOTES_BARRE_VALID_UE and mu["moy"] >= self.parcours.NOTES_BARRE_VALID_UE
): ):
mu["ects_pot"] = ue["ects"] or 0.0 mu["ects_pot"] = ue["ects"] or 0.0
if UE_is_fondamentale(ue["type"]): if ue_is_fondamentale(ue["type"]):
mu["ects_pot_fond"] = mu["ects_pot"] mu["ects_pot_fond"] = mu["ects_pot"]
else: else:
mu["ects_pot_fond"] = 0.0 mu["ects_pot_fond"] = 0.0
if UE_is_professionnelle(ue["type"]): if ue_is_professionnelle(ue["type"]):
mu["ects_pot_pro"] = mu["ects_pot"] mu["ects_pot_pro"] = mu["ects_pot"]
else: else:
mu["ects_pot_pro"] = 0.0 mu["ects_pot_pro"] = 0.0

View File

@ -81,11 +81,11 @@ UE_PROFESSIONNELLE = 5 # UE "professionnelle" (ISCID, ...)
UE_OPTIONNELLE = 6 # UE non fondamentales (ILEPS, ...) UE_OPTIONNELLE = 6 # UE non fondamentales (ILEPS, ...)
def UE_is_fondamentale(ue_type): def ue_is_fondamentale(ue_type):
return ue_type in (UE_STANDARD, UE_STAGE_LP, UE_PROFESSIONNELLE) return ue_type in (UE_STANDARD, UE_STAGE_LP, UE_PROFESSIONNELLE)
def UE_is_professionnelle(ue_type): def ue_is_professionnelle(ue_type):
return ( return (
ue_type == UE_PROFESSIONNELLE ue_type == UE_PROFESSIONNELLE
) # NB: les UE_PROFESSIONNELLE sont à la fois fondamentales et pro ) # NB: les UE_PROFESSIONNELLE sont à la fois fondamentales et pro
@ -211,7 +211,7 @@ DEVENIRS_NEXT2 = {NEXT_OR_NEXT2: 1, NEXT2: 1}
NO_SEMESTRE_ID = -1 # code semestre si pas de semestres NO_SEMESTRE_ID = -1 # code semestre si pas de semestres
# Regles gestion parcours # Règles gestion parcours
class DUTRule(object): class DUTRule(object):
def __init__(self, rule_id, premise, conclusion): def __init__(self, rule_id, premise, conclusion):
self.rule_id = rule_id self.rule_id = rule_id
@ -222,13 +222,13 @@ class DUTRule(object):
def match(self, state): def match(self, state):
"True if state match rule premise" "True if state match rule premise"
assert len(state) == len(self.premise) assert len(state) == len(self.premise)
for i in range(len(state)): for i, stat in enumerate(state):
prem = self.premise[i] prem = self.premise[i]
if isinstance(prem, (list, tuple)): if isinstance(prem, (list, tuple)):
if not state[i] in prem: if not stat in prem:
return False return False
else: else:
if prem != ALL and prem != state[i]: if prem not in (ALL, stat):
return False return False
return True return True
@ -244,6 +244,7 @@ class TypeParcours(object):
COMPENSATION_UE = True # inutilisé COMPENSATION_UE = True # inutilisé
BARRE_MOY = 10.0 BARRE_MOY = 10.0
BARRE_UE_DEFAULT = 8.0 BARRE_UE_DEFAULT = 8.0
BARRE_UE_DISPLAY_WARNING = 8.0
BARRE_UE = {} BARRE_UE = {}
NOTES_BARRE_VALID_UE_TH = 10.0 # seuil pour valider UE NOTES_BARRE_VALID_UE_TH = 10.0 # seuil pour valider UE
NOTES_BARRE_VALID_UE = NOTES_BARRE_VALID_UE_TH - NOTES_TOLERANCE # barre sur UE NOTES_BARRE_VALID_UE = NOTES_BARRE_VALID_UE_TH - NOTES_TOLERANCE # barre sur UE

View File

@ -931,6 +931,9 @@ def icontag(name, file_format="png", no_size=False, **attrs):
ICON_PDF = icontag("pdficon16x20_img", title="Version PDF") ICON_PDF = icontag("pdficon16x20_img", title="Version PDF")
ICON_XLS = icontag("xlsicon_img", title="Version tableur") ICON_XLS = icontag("xlsicon_img", title="Version tableur")
# HTML emojis
EMO_WARNING = "&#9888;&#65039;" # warning /!\
def sort_dates(L, reverse=False): def sort_dates(L, reverse=False):
"""Return sorted list of dates, allowing None items (they are put at the beginning)""" """Return sorted list of dates, allowing None items (they are put at the beginning)"""

File diff suppressed because it is too large Load Diff