ScoDoc-PE/app/tables/visu_assiduites.py
2024-01-18 17:05:43 +01:00

177 lines
5.9 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 etuid, et le row stocke etud.
"""
def __init__(
self,
etuds: list[Identite] = None,
dates: tuple[str, str] = None,
formsemestre: FormSemestre = None,
**kwargs,
):
self.rows: list["RowEtud"] = [] # 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
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
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], f"{value[1] - value[2]}", "assi_stats")
if key != "present":
self.add_cell(
key + "_justi",
value[0] + " Justifiées",
f"{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",
f"{compte_justificatifs_att.count()}",
)
self.add_cell(
"justificatifs", "Justificatifs", f"{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
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
"split": 1, # afin d'avoir la division des stats en état, etatjust, etatnonjust
},
)
# Pour chaque état on mets à 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)