195 lines
6.6 KiB
Python
195 lines
6.6 KiB
Python
##############################################################################
|
|
# ScoDoc
|
|
# Copyright (c) 1999 - 2024 Emmanuel Viennet. All rights reserved.
|
|
# See LICENSE
|
|
##############################################################################
|
|
|
|
"""Liste simple d'étudiants
|
|
"""
|
|
|
|
from flask import g, url_for
|
|
from app import log
|
|
from app.models import FormSemestre, Identite, Justificatif
|
|
from app.tables import table_builder as tb
|
|
import app.scodoc.sco_assiduites as scass
|
|
from app.scodoc import sco_preferences
|
|
from app.scodoc import sco_utils as scu
|
|
|
|
|
|
class TableAssi(tb.Table):
|
|
"""Table listant les statistiques d'assiduité des étudiants
|
|
L'id de la ligne est etudid, et le row stocke etud.
|
|
|
|
On considère les assiduités entre les dates indiquées.
|
|
|
|
Si formsemestre_modimpls est spécifié, restreint aux assiduités associées à des
|
|
moduleimpls de ce formsemestre.
|
|
|
|
Si convert_values, transforme les nombre en chaines ("12.34"), pour le html.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
etuds: list[Identite] = None,
|
|
dates: tuple[str, str] = None,
|
|
formsemestre: FormSemestre = None,
|
|
formsemestre_modimpls: FormSemestre | None = None,
|
|
convert_values=False,
|
|
**kwargs,
|
|
):
|
|
self.rows: list["RowAssi"] = [] # juste pour que VSCode nous aide sur .rows
|
|
classes = ["gt_table"]
|
|
self.dates = [str(dates[0]) + "T00:00", str(dates[1]) + "T23:59"]
|
|
self.formsemestre = formsemestre
|
|
self.formsemestre_modimpls = formsemestre_modimpls
|
|
if convert_values:
|
|
self.fmt_num = lambda x: f"{x:2.3g}"
|
|
else:
|
|
self.fmt_num = lambda x: x
|
|
super().__init__(
|
|
row_class=RowAssi,
|
|
classes=classes,
|
|
**kwargs,
|
|
with_foot_titles=False,
|
|
)
|
|
self.add_etuds(etuds)
|
|
|
|
def add_etuds(self, etuds: list[Identite]):
|
|
"Ajoute des étudiants à la table"
|
|
for etud in etuds:
|
|
row = self.row_class(self, etud)
|
|
row.add_etud_cols()
|
|
self.add_row(row)
|
|
|
|
|
|
class RowAssi(tb.Row):
|
|
"Ligne de la table assiduité"
|
|
|
|
# pour le moment très simple, extensible (codes, liens bulletins, ...)
|
|
def __init__(self, table: TableAssi, etud: Identite, *args, **kwargs):
|
|
# Etat de l'inscription au formsemestre
|
|
if "classes" not in kwargs:
|
|
kwargs["classes"] = []
|
|
try:
|
|
inscription = table.formsemestre.etuds_inscriptions[etud.id]
|
|
if inscription.etat == scu.DEMISSION:
|
|
kwargs["classes"].append("etuddem")
|
|
except KeyError:
|
|
log(f"RowAssi: etudid {etud.id} non inscrit à {table.formsemestre.id}")
|
|
kwargs["classes"].append("non_inscrit") # ne devrait pas arriver !
|
|
|
|
super().__init__(table, etud.id, *args, **kwargs)
|
|
self.etud = etud
|
|
self.dates = table.dates
|
|
|
|
def add_etud_cols(self):
|
|
"""Ajoute les colonnes"""
|
|
etud = self.etud
|
|
fmt_num = self.table.fmt_num
|
|
self.table.group_titles.update(
|
|
{
|
|
"etud_codes": "Codes",
|
|
"identite_detail": "",
|
|
"identite_court": "",
|
|
}
|
|
)
|
|
|
|
bilan_etud = url_for(
|
|
"assiduites.bilan_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id
|
|
)
|
|
self.add_cell(
|
|
"nom_disp",
|
|
"Nom",
|
|
etud.nom_disp(),
|
|
"etudinfo",
|
|
attrs={"id": str(etud.id)},
|
|
data={"order": etud.sort_key},
|
|
target=bilan_etud,
|
|
target_attrs={"class": "discretelink"},
|
|
)
|
|
self.add_cell(
|
|
"prenom",
|
|
"Prénom",
|
|
etud.prenom_str,
|
|
"etudinfo",
|
|
attrs={"id": str(etud.id)},
|
|
data={"order": etud.sort_key},
|
|
target=bilan_etud,
|
|
target_attrs={"class": "discretelink"},
|
|
)
|
|
stats = self._get_etud_stats(etud)
|
|
for key, value in stats.items():
|
|
self.add_cell(key, value[0], fmt_num(value[1] - value[2]), "assi_stats")
|
|
if key != "present":
|
|
self.add_cell(
|
|
key + "_justi",
|
|
value[0] + " Justifiées",
|
|
fmt_num(value[2]),
|
|
"assi_stats",
|
|
)
|
|
|
|
compte_justificatifs = scass.filter_by_date(
|
|
etud.justificatifs, Justificatif, self.dates[0], self.dates[1]
|
|
)
|
|
|
|
compte_justificatifs_att = compte_justificatifs.filter(Justificatif.etat == 2)
|
|
|
|
self.add_cell(
|
|
"justificatifs_att",
|
|
"Justificatifs en Attente",
|
|
fmt_num(compte_justificatifs_att.count()),
|
|
)
|
|
self.add_cell(
|
|
"justificatifs", "Justificatifs", fmt_num(compte_justificatifs.count())
|
|
)
|
|
|
|
def _get_etud_stats(self, etud: Identite) -> dict[str, list[str, float, float]]:
|
|
"""
|
|
Renvoie le comptage (dans la métrique du département) des différents états
|
|
d'assiduité d'un étudiant.
|
|
Considère les dates.
|
|
|
|
Returns :
|
|
{
|
|
"<etat>" : [<Etat version lisible>, <nb total etat>, <nb just etat>]
|
|
}
|
|
|
|
"""
|
|
|
|
# Préparation du retour
|
|
retour: dict[str, tuple[str, float, float]] = {
|
|
"absent": ["Absences", 0.0, 0.0],
|
|
"retard": ["Retards", 0.0, 0.0],
|
|
"present": ["Présences", 0.0, 0.0],
|
|
}
|
|
|
|
# Récupération de la métrique du département
|
|
assi_metric = scu.translate_assiduites_metric(
|
|
sco_preferences.get_preference("assi_metrique", dept_id=g.scodoc_dept_id),
|
|
)
|
|
|
|
compte_etat: dict[str, dict] = scass.get_assiduites_stats(
|
|
assiduites=etud.assiduites,
|
|
metric=assi_metric,
|
|
filtered={
|
|
"date_debut": self.dates[0],
|
|
"date_fin": self.dates[1],
|
|
"etat": "absent,present,retard", # pour tout compter d'un coup
|
|
"formsemestre_modimpls": self.table.formsemestre_modimpls,
|
|
"split": 1, # afin d'avoir la division des stats en état, etatjust, etatnonjust
|
|
},
|
|
)
|
|
|
|
# Pour chaque état on met à jour les valeurs de retour
|
|
for etat, valeur in retour.items():
|
|
valeur[1] = compte_etat[etat][assi_metric]
|
|
if etat != "present":
|
|
valeur[2] = compte_etat[etat]["justifie"][assi_metric]
|
|
return retour
|
|
|
|
|
|
def etuds_sorted_from_ids(etudids) -> list[Identite]:
|
|
"Liste triée d'etuds à partir d'une collections d'etudids"
|
|
etuds = [Identite.get_etud(etudid) for etudid in etudids]
|
|
return sorted(etuds, key=lambda etud: etud.sort_key)
|