diff --git a/app/api/justificatifs.py b/app/api/justificatifs.py
index f048d1a67..b3528362a 100644
--- a/app/api/justificatifs.py
+++ b/app/api/justificatifs.py
@@ -22,7 +22,6 @@ from app.api import get_model_api_object, tools
from app.decorators import permission_required, scodoc
from app.models import Identite, Justificatif, Departement, FormSemestre, Scolog
from app.models.assiduites import (
- compute_assiduites_justified,
get_formsemestre_from_data,
)
from app.scodoc.sco_archives_justificatifs import JustificatifArchiver
@@ -310,7 +309,6 @@ def justif_create(etudid: int = None, nip=None, ine=None):
errors: list[dict] = []
success: list[dict] = []
- justifs: list[Justificatif] = []
# énumération des justificatifs
for i, data in enumerate(create_list):
@@ -322,11 +320,9 @@ def justif_create(etudid: int = None, nip=None, ine=None):
errors.append({"indice": i, "message": obj})
else:
success.append({"indice": i, "message": obj})
- justifs.append(justi)
+ justi.justifier_assiduites()
scass.simple_invalidate_cache(data, etud.id)
- # Actualisation des assiduités justifiées en fonction de tous les nouveaux justificatifs
- compute_assiduites_justified(etud.etudid, justifs)
return {"errors": errors, "success": success}
@@ -495,6 +491,7 @@ def justif_edit(justif_id: int):
return json_error(404, err)
# Mise à jour du justificatif
+ justificatif_unique.dejustifier_assiduites()
db.session.add(justificatif_unique)
db.session.commit()
@@ -511,11 +508,7 @@ def justif_edit(justif_id: int):
retour = {
"couverture": {
"avant": avant_ids,
- "apres": compute_assiduites_justified(
- justificatif_unique.etudid,
- [justificatif_unique],
- True,
- ),
+ "apres": justificatif_unique.justifier_assiduites(),
}
}
# Invalide le cache
@@ -592,14 +585,10 @@ def _delete_one(justif_id: int) -> tuple[int, str]:
# On invalide le cache
scass.simple_invalidate_cache(justificatif_unique.to_dict())
+ # On actualise les assiduités justifiées de l'étudiant concerné
+ justificatif_unique.dejustifier_assiduites()
# On supprime le justificatif
db.session.delete(justificatif_unique)
- # On actualise les assiduités justifiées de l'étudiant concerné
- compute_assiduites_justified(
- justificatif_unique.etudid,
- Justificatif.query.filter_by(etudid=justificatif_unique.etudid).all(),
- True,
- )
return (200, "OK")
@@ -700,7 +689,6 @@ def justif_export(justif_id: int | None = None, filename: str | None = None):
@as_json
@permission_required(Permission.AbsChange)
def justif_remove(justif_id: int = None):
- # XXX TODO pas de test unitaire
"""
Supression d'un fichier ou d'une archive
{
diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py
index 8eec9ba6a..ab4227b0d 100644
--- a/app/but/bulletin_but.py
+++ b/app/but/bulletin_but.py
@@ -393,7 +393,7 @@ class BulletinBUT:
else:
etud_ues_ids = res.etud_ues_ids(etud.id)
- nbabs, nbabsjust = formsemestre.get_abs_count(etud.id)
+ nbabsnj, nbabsjust, nbabs = formsemestre.get_abs_count(etud.id)
etud_groups = sco_groups.get_etud_formsemestre_groups(
etud, formsemestre, only_to_show=True
)
@@ -408,7 +408,7 @@ class BulletinBUT:
}
if self.prefs["bul_show_abs"]:
semestre_infos["absences"] = {
- "injustifie": nbabs - nbabsjust,
+ "injustifie": nbabsnj,
"total": nbabs,
"metrique": {
"H.": "Heure(s)",
@@ -525,7 +525,7 @@ class BulletinBUT:
d["demission"] = ""
# --- Absences
- d["nbabs"], d["nbabsjust"] = self.res.formsemestre.get_abs_count(etud.id)
+ _, d["nbabsjust"], d["nbabs"] = self.res.formsemestre.get_abs_count(etud.id)
# --- Decision Jury
infos, _ = sco_bulletins.etud_descr_situation_semestre(
@@ -540,9 +540,9 @@ class BulletinBUT:
d.update(infos)
# --- Rangs
- d["rang_nt"] = (
- f"{d['semestre']['rang']['value']} / {d['semestre']['rang']['total']}"
- )
+ d[
+ "rang_nt"
+ ] = f"{d['semestre']['rang']['value']} / {d['semestre']['rang']['total']}"
d["rang_txt"] = "Rang " + d["rang_nt"]
d.update(sco_bulletins.make_context_dict(self.res.formsemestre, d["etud"]))
diff --git a/app/but/bulletin_but_xml_compat.py b/app/but/bulletin_but_xml_compat.py
index 07522f80c..fb9af2056 100644
--- a/app/but/bulletin_but_xml_compat.py
+++ b/app/but/bulletin_but_xml_compat.py
@@ -241,7 +241,7 @@ def bulletin_but_xml_compat(
# --- Absences
if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
- nbabs, nbabsjust = formsemestre.get_abs_count(etud.id)
+ _, nbabsjust, nbabs = 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/assiduites.py b/app/models/assiduites.py
index 8580179bd..db7a25872 100644
--- a/app/models/assiduites.py
+++ b/app/models/assiduites.py
@@ -574,11 +574,7 @@ class Justificatif(ScoDocModel):
db.session.delete(self)
db.session.commit()
# On actualise les assiduités justifiées de l'étudiant concerné
- compute_assiduites_justified(
- self.etudid,
- Justificatif.query.filter_by(etudid=self.etudid).all(),
- True,
- )
+ self.dejustifier_assiduites()
def get_fichiers(self) -> tuple[list[str], int]:
"""Renvoie la liste des noms de fichiers justicatifs
@@ -600,6 +596,64 @@ class Justificatif(ScoDocModel):
accessible_filenames.append(filename[0])
return accessible_filenames, len(filenames)
+ def justifier_assiduites(
+ self,
+ ) -> list[int]:
+ """Justifie les assiduités sur la période de validité du justificatif"""
+ log(f"justifier_assiduites: {self}")
+ assiduites_justifiees: list[int] = []
+ if self.etat != EtatJustificatif.VALIDE:
+ return []
+ # On récupère les assiduités de l'étudiant sur la période donnée
+ assiduites: Query = self.etudiant.assiduites.filter(
+ Assiduite.date_debut >= self.date_debut,
+ Assiduite.date_fin <= self.date_fin,
+ Assiduite.etat != EtatAssiduite.PRESENT,
+ )
+ # Pour chaque assiduité, on la justifie
+ for assi in assiduites:
+ assi.est_just = True
+ assiduites_justifiees.append(assi.assiduite_id)
+ db.session.add(assi)
+
+ db.session.commit()
+
+ return assiduites_justifiees
+
+ def dejustifier_assiduites(self) -> list[int]:
+ """
+ Déjustifie les assiduités sur la période du justificatif
+ """
+ assiduites_dejustifiees: list[int] = []
+
+ # On récupère les assiduités de l'étudiant sur la période donnée
+ assiduites: Query = self.etudiant.assiduites.filter(
+ Assiduite.date_debut >= self.date_debut,
+ Assiduite.date_fin <= self.date_fin,
+ Assiduite.etat != EtatAssiduite.PRESENT,
+ )
+ assi: Assiduite
+ for assi in assiduites:
+ # On récupère les justificatifs qui justifient l'assiduité `assi`
+ assi_justifs: list[int] = get_justifs_from_date(
+ self.etudiant.etudid,
+ assi.date_debut,
+ assi.date_fin,
+ long=False,
+ valid=True,
+ )
+ # Si il n'y a pas d'autre justificatif valide, on déjustifie l'assiduité
+ if len(assi_justifs) == 0 or (
+ len(assi_justifs) == 1 and assi_justifs[0] == self.justif_id
+ ):
+ assi.est_just = False
+ assiduites_dejustifiees.append(assi.assiduite_id)
+ db.session.add(assi)
+
+ db.session.commit()
+
+ return assiduites_dejustifiees
+
def is_period_conflicting(
date_debut: datetime,
@@ -623,72 +677,6 @@ def is_period_conflicting(
return count > 0
-def compute_assiduites_justified(
- etudid: int, justificatifs: list[Justificatif] = None, reset: bool = False
-) -> list[int]:
- """
- Args:
- etudid (int): l'identifiant de l'étudiant
- justificatifs (list[Justificatif]): La liste des justificatifs qui seront utilisés
- reset (bool, optional): remet à false les assiduites non justifiés. Defaults to False.
-
- Returns:
- list[int]: la liste des assiduités qui ont été justifiées.
- """
- # TODO à optimiser (car très long avec 40000 assiduités)
- # On devrait :
- # - récupérer uniquement les assiduités qui sont sur la période des justificatifs donnés
- # - Pour chaque assiduité trouvée, il faut récupérer les justificatifs qui la justifie
- # - Si au moins un justificatif valide couvre la période de l'assiduité alors on la justifie
-
- # Si on ne donne pas de justificatifs on prendra par défaut tous les justificatifs de l'étudiant
- if justificatifs is None:
- justificatifs: list[Justificatif] = Justificatif.query.filter_by(
- etudid=etudid
- ).all()
-
- # On ne prend que les justificatifs valides
- justificatifs = [j for j in justificatifs if j.etat == EtatJustificatif.VALIDE]
-
- # On récupère les assiduités de l'étudiant
- assiduites: Assiduite = Assiduite.query.filter_by(etudid=etudid)
-
- assiduites_justifiees: list[int] = []
-
- for assi in assiduites:
- # On ne justifie pas les Présences
- if assi.etat == EtatAssiduite.PRESENT:
- continue
-
- # On récupère les justificatifs qui justifient l'assiduité `assi`
- assi_justificatifs = Justificatif.query.filter(
- Justificatif.etudid == assi.etudid,
- Justificatif.date_debut <= assi.date_debut,
- Justificatif.date_fin >= assi.date_fin,
- Justificatif.etat == EtatJustificatif.VALIDE,
- ).all()
-
- # Si au moins un justificatif possède une période qui couvre l'assiduité
- if any(
- assi.date_debut >= j.date_debut and assi.date_fin <= j.date_fin
- for j in justificatifs + assi_justificatifs
- ):
- # On justifie l'assiduité
- # On ajoute l'id de l'assiduité à la liste des assiduités justifiées
- assi.est_just = True
- assiduites_justifiees.append(assi.assiduite_id)
- db.session.add(assi)
- elif reset:
- # Si le paramètre reset est Vrai alors les assiduités non justifiées
- # sont remise en "non justifiée"
- assi.est_just = False
- db.session.add(assi)
- # On valide la session
- db.session.commit()
- # On renvoie la liste des assiduite_id des assiduités justifiées
- return assiduites_justifiees
-
-
def get_assiduites_justif(assiduite_id: int, long: bool) -> list[int | dict]:
"""
get_assiduites_justif Récupération des justificatifs d'une assiduité
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index 09c1d3056..5541d1780 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -875,7 +875,7 @@ class FormSemestre(db.Model):
def get_abs_count(self, etudid):
"""Les comptes d'absences de cet étudiant dans ce semestre:
- tuple (nb abs, nb abs justifiées)
+ tuple (nb abs non just, nb abs justifiées, nb abs total)
Utilise un cache.
"""
from app.scodoc import sco_assiduites
diff --git a/app/scodoc/html_sidebar.py b/app/scodoc/html_sidebar.py
index f1c8f8356..2d351e628 100755
--- a/app/scodoc/html_sidebar.py
+++ b/app/scodoc/html_sidebar.py
@@ -175,10 +175,9 @@ def sidebar(etudid: int = None):
inscription = etud.inscription_courante()
if inscription:
formsemestre = inscription.formsemestre
- nbabs, nbabsjust = sco_assiduites.formsemestre_get_assiduites_count(
+ nbabsnj, nbabsjust, _ = sco_assiduites.formsemestre_get_assiduites_count(
etudid, formsemestre
)
- nbabsnj = nbabs - nbabsjust
H.append(
f""" 1 journée)
self.nb_heures_par_jour = (
@@ -661,7 +661,7 @@ def create_absence_billet(
db.session.add(justi)
db.session.commit()
- compute_assiduites_justified(etud.id, [justi])
+ justi.justifier_assiduites()
calculator: CountCalculator = CountCalculator()
calculator.compute_assiduites([assiduite_unique])
@@ -671,7 +671,7 @@ def create_absence_billet(
# Gestion du cache
def get_assiduites_count(etudid: int, sem: dict) -> tuple[int, int]:
"""Les comptes d'absences de cet étudiant dans ce semestre:
- tuple (nb abs non justifiées, nb abs justifiées)
+ tuple (nb abs non justifiées, nb abs justifiées, nb abs total)
Utilise un cache.
"""
metrique = sco_preferences.get_preference("assi_metrique", sem["formsemestre_id"])
@@ -687,17 +687,17 @@ def formsemestre_get_assiduites_count(
etudid: int, formsemestre: FormSemestre, moduleimpl_id: int = None
) -> tuple[int, int]:
"""Les comptes d'absences de cet étudiant dans ce semestre:
- tuple (nb abs non justifiées, nb abs justifiées)
+ tuple (nb abs non justifiées, nb abs justifiées, nb abs total)
Utilise un cache.
"""
metrique = sco_preferences.get_preference("assi_metrique", formsemestre.id)
return get_assiduites_count_in_interval(
etudid,
date_debut=scu.localize_datetime(
- datetime.combine(formsemestre.date_debut, time(8, 0))
+ datetime.combine(formsemestre.date_debut, time(0, 0))
),
date_fin=scu.localize_datetime(
- datetime.combine(formsemestre.date_fin, time(18, 0))
+ datetime.combine(formsemestre.date_fin, time(23, 0))
),
metrique=scu.translate_assiduites_metric(metrique),
moduleimpl_id=moduleimpl_id,
@@ -714,12 +714,12 @@ def get_assiduites_count_in_interval(
moduleimpl_id: int = None,
):
"""Les comptes d'absences de cet étudiant entre ces deux dates, incluses:
- tuple (nb abs, nb abs justifiées)
+ tuple (nb abs non justifiées, nb abs justifiées, nb abs total)
On peut spécifier les dates comme datetime ou iso.
Utilise un cache.
"""
- date_debut_iso = date_debut_iso or date_debut.isoformat()
- date_fin_iso = date_fin_iso or date_fin.isoformat()
+ date_debut_iso = date_debut_iso or date_debut.strftime("%Y-%m-%d")
+ date_fin_iso = date_fin_iso or date_fin.strftime("%Y-%m-%d")
key = f"{etudid}_{date_debut_iso}_{date_fin_iso}_assiduites"
r = sco_cache.AbsSemEtudCache.get(key)
@@ -744,9 +744,10 @@ def get_assiduites_count_in_interval(
if not ans:
log("warning: get_assiduites_count failed to cache")
- nb_abs: dict = r["absent"][metrique]
- nb_abs_just: dict = r["absent_just"][metrique]
- return (nb_abs, nb_abs_just)
+ nb_abs: int = r["absent"][metrique]
+ nb_abs_nj: int = r["absent_non_just"][metrique]
+ nb_abs_just: int = r["absent_just"][metrique]
+ return (nb_abs_nj, nb_abs_just, nb_abs)
def invalidate_assiduites_count(etudid: int, sem: dict):
diff --git a/app/scodoc/sco_bulletins.py b/app/scodoc/sco_bulletins.py
index 1b70d3858..d1c32795d 100644
--- a/app/scodoc/sco_bulletins.py
+++ b/app/scodoc/sco_bulletins.py
@@ -196,7 +196,7 @@ def formsemestre_bulletinetud_dict(formsemestre_id, etudid, version="long"):
pid = partition["partition_id"]
partitions_etud_groups[pid] = sco_groups.get_etud_groups_in_partition(pid)
# --- Absences
- I["nbabs"], I["nbabsjust"] = sco_assiduites.get_assiduites_count(etudid, nt.sem)
+ _, I["nbabsjust"], I["nbabs"] = sco_assiduites.get_assiduites_count(etudid, nt.sem)
# --- Decision Jury
infos, dpv = etud_descr_situation_semestre(
@@ -471,7 +471,7 @@ def _ue_mod_bulletin(
) # peut etre 'NI'
is_malus = mod["module"]["module_type"] == ModuleType.MALUS
if bul_show_abs_modules:
- nbabs, nbabsjust = sco_assiduites.get_assiduites_count(etudid, sem)
+ _, nbabsjust, nbabs = sco_assiduites.get_assiduites_count(etudid, sem)
mod_abs = [nbabs, nbabsjust]
mod["mod_abs_txt"] = scu.fmt_abs(mod_abs)
else:
diff --git a/app/scodoc/sco_bulletins_json.py b/app/scodoc/sco_bulletins_json.py
index 0481e6f9c..a7848b39e 100644
--- a/app/scodoc/sco_bulletins_json.py
+++ b/app/scodoc/sco_bulletins_json.py
@@ -296,7 +296,7 @@ def formsemestre_bulletinetud_published_dict(
# --- Absences
if prefs["bul_show_abs"]:
- nbabs, nbabsjust = sco_assiduites.get_assiduites_count(etudid, sem)
+ _, nbabsjust, nbabs = sco_assiduites.get_assiduites_count(etudid, sem)
d["absences"] = dict(nbabs=nbabs, nbabsjust=nbabsjust)
# --- Décision Jury
diff --git a/app/scodoc/sco_bulletins_xml.py b/app/scodoc/sco_bulletins_xml.py
index 25f2cfa64..77f95ac28 100644
--- a/app/scodoc/sco_bulletins_xml.py
+++ b/app/scodoc/sco_bulletins_xml.py
@@ -260,7 +260,7 @@ def make_xml_formsemestre_bulletinetud(
numero=str(mod["numero"]),
titre=quote_xml_attr(mod["titre"]),
abbrev=quote_xml_attr(mod["abbrev"]),
- code_apogee=quote_xml_attr(mod["code_apogee"])
+ code_apogee=quote_xml_attr(mod["code_apogee"]),
# ects=ects ects des modules maintenant inutilisés
)
x_ue.append(x_mod)
@@ -347,7 +347,7 @@ def make_xml_formsemestre_bulletinetud(
# --- Absences
if sco_preferences.get_preference("bul_show_abs", formsemestre_id):
- nbabs, nbabsjust = sco_assiduites.get_assiduites_count(etudid, sem)
+ _, nbabsjust, nbabs = sco_assiduites.get_assiduites_count(etudid, sem)
doc.append(Element("absences", nbabs=str(nbabs), nbabsjust=str(nbabsjust)))
# --- Decision Jury
if (
diff --git a/app/scodoc/sco_formsemestre_validation.py b/app/scodoc/sco_formsemestre_validation.py
index df4770fa3..27d99fffd 100644
--- a/app/scodoc/sco_formsemestre_validation.py
+++ b/app/scodoc/sco_formsemestre_validation.py
@@ -722,8 +722,8 @@ def formsemestre_recap_parcours_table(
f"""
{scu.fmt_note(nt.get_etud_moy_gen(etudid))} | """
)
# Absences (nb d'abs non just. dans ce semestre)
- nbabs, nbabsjust = sco_assiduites.get_assiduites_count(etudid, sem)
- H.append(f"""{nbabs - nbabsjust} | """)
+ nbabsnj = sco_assiduites.get_assiduites_count(etudid, sem)[0]
+ H.append(f"""{nbabsnj} | """)
# UEs
for ue in ues:
diff --git a/app/scodoc/sco_poursuite_dut.py b/app/scodoc/sco_poursuite_dut.py
index c271628a2..475d59808 100644
--- a/app/scodoc/sco_poursuite_dut.py
+++ b/app/scodoc/sco_poursuite_dut.py
@@ -105,7 +105,9 @@ def etud_get_poursuite_info(sem: dict, etud: dict) -> dict:
rangs.append(["rang_" + code_module, rang_module])
# Absences
- nbabs, nbabsjust = sco_assiduites.get_assiduites_count(etudid, nt.sem)
+ nbabsnj, nbabsjust, _ = sco_assiduites.get_assiduites_count(
+ etudid, nt.sem
+ )
# En BUT, prend tout, sinon ne prend que les semestre validés par le jury
if nt.is_apc or (
dec
@@ -125,7 +127,7 @@ def etud_get_poursuite_info(sem: dict, etud: dict) -> dict:
("date_debut", s["date_debut"]),
("date_fin", s["date_fin"]),
("periode", "%s - %s" % (s["mois_debut"], s["mois_fin"])),
- ("AbsNonJust", nbabs - nbabsjust),
+ ("AbsNonJust", nbabsnj),
("AbsJust", nbabsjust),
]
# ajout des 2 champs notes des modules et classement dans chaque module
diff --git a/app/tables/recap.py b/app/tables/recap.py
index f26535edc..0c853c352 100644
--- a/app/tables/recap.py
+++ b/app/tables/recap.py
@@ -620,7 +620,7 @@ class RowRecap(tb.Row):
def add_abs(self):
"Ajoute les colonnes absences"
# Absences (nb d'abs non just. dans ce semestre)
- nbabs, nbabsjust = self.table.res.formsemestre.get_abs_count(self.etud.id)
+ _, nbabsjust, nbabs = self.table.res.formsemestre.get_abs_count(self.etud.id)
self.add_cell("nbabs", "Abs", f"{nbabs:1.0f}", "abs", raw_content=nbabs)
self.add_cell(
"nbabsjust", "Just.", f"{nbabsjust:1.0f}", "abs", raw_content=nbabsjust
@@ -691,9 +691,9 @@ class RowRecap(tb.Row):
self.add_ue_modimpls_cols(ue, ue_status["is_capitalized"])
self.nb_ues_etud_parcours = len(res.etud_parcours_ues_ids(etud.id))
- ue_valid_txt = ue_valid_txt_html = (
- f"{self.nb_ues_validables}/{self.nb_ues_etud_parcours}"
- )
+ ue_valid_txt = (
+ ue_valid_txt_html
+ ) = f"{self.nb_ues_validables}/{self.nb_ues_etud_parcours}"
if self.nb_ues_warning:
ue_valid_txt_html += " " + scu.EMO_WARNING
cell_class = ""
@@ -717,9 +717,9 @@ class RowRecap(tb.Row):
# sous-classé par JuryRow pour ajouter les codes
table: TableRecap = self.table
formsemestre: FormSemestre = table.res.formsemestre
- table.group_titles["col_ue"] = (
- f"UEs du S{formsemestre.semestre_id} {formsemestre.annee_scolaire()}"
- )
+ 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"]
diff --git a/app/templates/assiduites/pages/bilan_etud.j2 b/app/templates/assiduites/pages/bilan_etud.j2
index 15fed8aad..ae494bdbe 100644
--- a/app/templates/assiduites/pages/bilan_etud.j2
+++ b/app/templates/assiduites/pages/bilan_etud.j2
@@ -66,7 +66,6 @@ Bilan assiduité de {{sco.etud.nomprenom}}
{% endblock styles %}
{% block app_content %}
-{% include "assiduites/widgets/tableau_base.j2" %}
Bilan de l'assiduité de {{sco.etud.html_link_fiche()|safe}}
diff --git a/app/templates/assiduites/pages/signal_assiduites_group.j2 b/app/templates/assiduites/pages/signal_assiduites_group.j2
index 12380afaa..4eb21e413 100644
--- a/app/templates/assiduites/pages/signal_assiduites_group.j2
+++ b/app/templates/assiduites/pages/signal_assiduites_group.j2
@@ -1,23 +1,23 @@
{% extends "sco_page.j2" %}
{% block title %}
- {{title}}
+{{title}}
{% endblock title %}
{% block scripts %}
- {{ super() }}
-
-
-
-
-
-
+{{ super() }}
+
+
+
+
+
+
-
+
{% endblock scripts %}
{% block styles %}
- {{ super() }}
-
-
-
-
-
+{{ super() }}
+
+
+
+
+
{% endblock styles %}
@@ -80,7 +80,11 @@
{% include "assiduites/widgets/toast.j2" %}
{{ minitimeline|safe }}
-
+
-{% endblock app_content %}
+{% endblock app_content %}
\ No newline at end of file
diff --git a/app/templates/assiduites/widgets/tableau.j2 b/app/templates/assiduites/widgets/tableau.j2
index 39bbb2f45..1ab881c66 100644
--- a/app/templates/assiduites/widgets/tableau.j2
+++ b/app/templates/assiduites/widgets/tableau.j2
@@ -174,7 +174,7 @@
}
window.addEventListener('load', ()=>{
- const table_columns = [...document.querySelectorAll('.external-sort')];
+ const table_columns = [...document.querySelectorAll('th.external-sort')];
table_columns.forEach((e)=>e.addEventListener('click', ()=>{
// récupération de l'ordre "ascending" / "descending"
diff --git a/app/templates/assiduites/widgets/tableau_base.j2 b/app/templates/assiduites/widgets/tableau_base.j2
deleted file mode 100644
index 71580a14e..000000000
--- a/app/templates/assiduites/widgets/tableau_base.j2
+++ /dev/null
@@ -1,624 +0,0 @@
-
-
-{% include "assiduites/widgets/alert.j2" %}
-{% include "assiduites/widgets/prompt.j2" %}
-
-
-
-
\ No newline at end of file
diff --git a/app/templates/assiduites/widgets/tableau_justi.j2 b/app/templates/assiduites/widgets/tableau_justi.j2
deleted file mode 100644
index 06e5c6e51..000000000
--- a/app/templates/assiduites/widgets/tableau_justi.j2
+++ /dev/null
@@ -1,679 +0,0 @@
-
-
-
-
-
- |
-
-
- |
-
-
- |
-
-
- |
-
-
- |
-
-
-
-
-
-
-
-
-
diff --git a/app/templates/sidebar.j2 b/app/templates/sidebar.j2
index f07e68084..00c612301 100755
--- a/app/templates/sidebar.j2
+++ b/app/templates/sidebar.j2
@@ -56,8 +56,8 @@
Absences
{% if sco.etud_cur_sem %}
-
({{sco.prefs["assi_metrique"]}})
+ ({{sco.prefs["assi_metrique"]}})
{{'%1.0f'|format(sco.nbabsjust)}} J., {{'%1.0f'|format(sco.nbabsnj)}} N.J.
{% endif %}
diff --git a/app/views/__init__.py b/app/views/__init__.py
index 890fb63eb..b28a4e57c 100644
--- a/app/views/__init__.py
+++ b/app/views/__init__.py
@@ -74,8 +74,9 @@ class ScoData:
if ins:
self.etud_cur_sem = ins.formsemestre
(
- self.nbabs,
+ self.nbabsnj,
self.nbabsjust,
+ self.nbabs,
) = sco_assiduites.get_assiduites_count_in_interval(
etud.id,
self.etud_cur_sem.date_debut.isoformat(),
@@ -84,7 +85,6 @@ class ScoData:
sco_preferences.get_preference("assi_metrique")
),
)
- self.nbabsnj = self.nbabs - self.nbabsjust
else:
self.etud_cur_sem = None
else:
diff --git a/app/views/assiduites.py b/app/views/assiduites.py
index f892edc6d..6b2e931a2 100644
--- a/app/views/assiduites.py
+++ b/app/views/assiduites.py
@@ -64,7 +64,7 @@ from app.models import (
)
from app.scodoc.codes_cursus import UE_STANDARD
from app.auth.models import User
-from app.models.assiduites import get_assiduites_justif, compute_assiduites_justified
+from app.models.assiduites import get_assiduites_justif
from app.tables.list_etuds import RowEtud, TableEtud
import app.tables.liste_assiduites as liste_assi
@@ -468,7 +468,7 @@ def _record_assiduite_etud(
)
# On met à jour les assiduités en fonction du nouveau justificatif
- compute_assiduites_justified(etud.id, [justi])
+ justi.justifier_assiduites()
# Invalider cache
scass.simple_invalidate_cache(ass.to_dict(), etud.id)
@@ -778,6 +778,7 @@ def _record_justificatif_etud(
form.date_debut.data = dt_debut_tz_server
form.date_fin.data = dt_fin_tz_server
form.entry_date.data = dt_entry_date_tz_server
+ justif.dejustifier_assiduites()
if justif.edit_from_form(form):
message = "Justificatif modifié"
@@ -792,7 +793,6 @@ def _record_justificatif_etud(
)
else:
message = "Pas de modification"
-
else:
justif = Justificatif.create_justificatif(
etud,
@@ -816,7 +816,7 @@ def _record_justificatif_etud(
# pour utiliser le "reset" (remise en "non_just") des assiduités
# (à terme, il faudrait ne recalculer que les assiduités impactées)
# VOIR TODO dans compute_assiduites_justified
- compute_assiduites_justified(etud.id, reset=True)
+ justif.justifier_assiduites()
scass.simple_invalidate_cache(justif.to_dict(), etud.id)
flash(message)
return True
@@ -1595,7 +1595,7 @@ def tableau_assiduite_actions():
user_id=current_user.id,
)
- compute_assiduites_justified(objet.etudiant.id, [justificatif_correspondant])
+ justificatif_correspondant.justifier_assiduites()
scass.simple_invalidate_cache(
justificatif_correspondant.to_dict(), objet.etudiant.id
)
@@ -1707,9 +1707,10 @@ def _action_modifier_justificatif(justi: Justificatif):
justi.fichier = archive_name
+ justi.dejustifier_assiduites()
db.session.add(justi)
db.session.commit()
- scass.compute_assiduites_justified(justi.etudid, reset=True)
+ justi.justifier_assiduites()
scass.simple_invalidate_cache(justi.to_dict(True), justi.etudid)
@@ -2181,12 +2182,8 @@ def _module_selector(formsemestre: FormSemestre, moduleimpl_id: int = None) -> s
"""
# récupération des ues du semestre
ntc: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
- ues = ntc.get_ues_stat_dict()
- modimpls_list: list[dict] = []
- for ue in ues:
- # Ajout des moduleimpl de chaque ue dans la liste des moduleimpls
- modimpls_list += ntc.get_modimpls_dict(ue_id=ue["ue_id"])
+ modimpls_list: list[dict] = ntc.get_modimpls_dict()
# prévoie la sélection par défaut d'un moduleimpl s'il a été passé en paramètre
selected = "" if moduleimpl_id is not None else "selected"
diff --git a/app/views/notes.py b/app/views/notes.py
index 717131db3..570b64f52 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -1187,14 +1187,18 @@ def view_module_abs(moduleimpl_id, fmt="html"):
rows = []
for etud in inscrits:
- nb_abs, nb_abs_just = sco_assiduites.formsemestre_get_assiduites_count(
+ (
+ nb_abs_nj,
+ nb_abs_just,
+ nb_abs,
+ ) = sco_assiduites.formsemestre_get_assiduites_count(
etud.id, modimpl.formsemestre, moduleimpl_id=modimpl.id
)
rows.append(
{
"nomprenom": etud.nomprenom,
"just": nb_abs_just,
- "nojust": nb_abs - nb_abs_just,
+ "nojust": nb_abs_nj,
"total": nb_abs,
"_nomprenom_target": url_for(
"scolar.fiche_etud", scodoc_dept=g.scodoc_dept, etudid=etud.id
diff --git a/tests/api/test_api_justificatifs.py b/tests/api/test_api_justificatifs.py
index 5e73d2c71..5ae86528b 100644
--- a/tests/api/test_api_justificatifs.py
+++ b/tests/api/test_api_justificatifs.py
@@ -38,6 +38,8 @@ JUSTIFICATIFS_FIELDS = {
"external_data": dict,
}
+DEPT_JUSTIFICATIFS_FIELDS = JUSTIFICATIFS_FIELDS | {"formsemestre": dict | None}
+
CREATE_FIELD = {"justif_id": int, "couverture": list}
BATCH_FIELD = {"errors": list, "success": list}
@@ -169,6 +171,32 @@ def test_route_justificatifs(api_headers):
check_failure_get(f"/justificatifs/{FAUX}/query?", api_headers)
+def test_route_justificatifs_formsemestre(api_headers):
+ """test de la route /justificatifs/formsemestre/"""
+ # Bon fonctionnement
+
+ data = GET(path="/justificatifs/formsemestre/1", headers=api_headers)
+ assert isinstance(data, list)
+ for just in data:
+ check_fields(just, JUSTIFICATIFS_FIELDS)
+
+ # Mauvais fonctionnement
+ check_failure_get(path="/justificatifs/formsemestre/42069", headers=api_headers)
+
+
+def test_justificatifs_dept(api_headers):
+ """test de la route /justificatifs/dept/"""
+ # Bon fonctionnement
+
+ data = GET(path="/justificatifs/dept/1", headers=api_headers)
+ assert isinstance(data, list)
+ for just in data:
+ check_fields(just, DEPT_JUSTIFICATIFS_FIELDS)
+
+ # Mauvais fonctionnement
+ check_failure_get(path="/justificatifs/dept/42069", headers=api_headers)
+
+
def test_route_create(api_admin_headers):
"""test de la route /justificatif//create"""
# -== Unique ==-
diff --git a/tests/unit/test_assiduites.py b/tests/unit/test_assiduites.py
index 0cc7ce594..3063c9730 100644
--- a/tests/unit/test_assiduites.py
+++ b/tests/unit/test_assiduites.py
@@ -20,7 +20,6 @@ from app.models import (
ModuleImpl,
Absence,
)
-from app.models.assiduites import compute_assiduites_justified
from app.scodoc.sco_exceptions import ScoValueError
from tests.unit import sco_fake_gen
@@ -73,8 +72,6 @@ def test_general(test_client):
verifier_comptage_et_filtrage_assiduites(etuds, moduleimpls[:4], formsemestres)
verifier_filtrage_justificatifs(etuds[0], justificatifs)
- essais_cache(etuds[0].etudid, formsemestres[:2], moduleimpls)
-
editer_supprimer_assiduites(etuds, moduleimpls)
editer_supprimer_justificatif(etuds[0])
@@ -403,54 +400,6 @@ def _get_justi(
).first()
-def essais_cache(etudid, sems: tuple[FormSemestre], moduleimpls: list[ModuleImpl]):
- """Vérification des fonctionnalités du cache"""
- # TODO faire un test séparé du test_general
- # voir test_calcul_assiduites pour faire
-
- date_deb: str = "2022-09-01T07:00"
- date_fin: str = "2023-01-31T19:00"
-
- assiduites_count_no_cache = scass.get_assiduites_count_in_interval(
- etudid, date_deb, date_fin
- )
- assiduites_count_cache = scass.get_assiduites_count_in_interval(
- etudid, date_deb, date_fin
- )
-
- assert (
- assiduites_count_cache == assiduites_count_no_cache == (2, 1)
- ), "Erreur cache classique"
-
- assert scass.formsemestre_get_assiduites_count(etudid, sems[0]) == (
- 2,
- 1,
- ), "Erreur formsemestre_get_assiduites_count (sans module) A"
- assert scass.formsemestre_get_assiduites_count(etudid, sems[1]) == (
- 0,
- 0,
- ), "Erreur formsemestre_get_assiduites_count (sans module) B"
-
- assert scass.formsemestre_get_assiduites_count(
- etudid, sems[0], moduleimpl_id=moduleimpls[0].id
- ) == (
- 1,
- 1,
- ), "Erreur formsemestre_get_assiduites_count (avec module) A"
- assert scass.formsemestre_get_assiduites_count(
- etudid, sems[0], moduleimpl_id=moduleimpls[1].id
- ) == (
- 1,
- 0,
- ), "Erreur formsemestre_get_assiduites_count (avec module) A"
- assert scass.formsemestre_get_assiduites_count(
- etudid, sems[0], moduleimpl_id=moduleimpls[2].id
- ) == (
- 0,
- 0,
- ), "Erreur formsemestre_get_assiduites_count (avec module) A"
-
-
def ajouter_justificatifs(etud):
"""test de l'ajout des justificatifs"""
@@ -498,10 +447,9 @@ def ajouter_justificatifs(etud):
)
db.session.add(just_obj)
db.session.commit()
+ just_obj.justifier_assiduites()
justificatifs.append(just_obj)
- compute_assiduites_justified(etud.etudid, justificatifs)
-
# Vérification de la création des justificatifs
assert [
justi for justi in justificatifs if not isinstance(justi, Justificatif)
@@ -1416,6 +1364,7 @@ def test_cas_justificatifs(test_client):
Tests de certains cas particuliers des justificatifs
- Création du justificatif avant ou après assiduité
- Assiduité complétement couverte ou non
+ - Modification de la couverture (edition du justificatif)
"""
data = _setup_fake_db(
@@ -1462,7 +1411,7 @@ def test_cas_justificatifs(test_client):
etat=scu.EtatJustificatif.VALIDE,
)
- compute_assiduites_justified(etud_1.etudid, [justif_2])
+ justif_2.justifier_assiduites()
assert len(scass.justifies(justif_2)) == 1, "Justification non prise en compte (b1)"
@@ -1496,7 +1445,8 @@ def test_cas_justificatifs(test_client):
)
# Mise à jour de l'assiduité
- compute_assiduites_justified(etud_1.etudid, [justif_3, justif_4])
+ justif_3.justifier_assiduites()
+ justif_4.justifier_assiduites()
assert (
len(scass.justifies(justif_3)) == 1
@@ -1504,3 +1454,279 @@ def test_cas_justificatifs(test_client):
assert (
len(scass.justifies(justif_4)) == 0
), "Justification complète non prise en compte (c2)"
+
+ # <- Vérification modification de la couverture ->
+
+ # Deux assiduités, 8/01/2024 de 8h à 10h et 14h à 16h
+
+ assi_2: Assiduite = Assiduite.create_assiduite(
+ etud=etud_1,
+ date_debut=scu.is_iso_formated("2024-01-08T08:00", True),
+ date_fin=scu.is_iso_formated("2024-01-08T10:00", True),
+ etat=scu.EtatAssiduite.ABSENT,
+ )
+ assi_3: Assiduite = Assiduite.create_assiduite(
+ etud=etud_1,
+ date_debut=scu.is_iso_formated("2024-01-08T14:00", True),
+ date_fin=scu.is_iso_formated("2024-01-08T16:00", True),
+ etat=scu.EtatAssiduite.ABSENT,
+ )
+
+ # <=>Justification complète<=>
+ # les deux assiduités sont couvertes
+
+ justif_5: Justificatif = Justificatif.create_justificatif(
+ etudiant=etud_1,
+ date_debut=scu.is_iso_formated("2024-01-08T00:00:00", True),
+ date_fin=scu.is_iso_formated("2024-01-08T23:59:59", True),
+ etat=scu.EtatJustificatif.VALIDE,
+ )
+
+ # Justification des assiduités
+ assi_ids: list[int] = justif_5.justifier_assiduites()
+ assert len(assi_ids) == 2, "Vérification Modification couverture (d1)"
+ assert assi_2.assiduite_id in assi_ids, "Vérification Modification couverture (d2)"
+ assert assi_3.assiduite_id in assi_ids, "Vérification Modification couverture (d3)"
+ assert assi_2.est_just is True, "Vérification Modification couverture (d4)"
+ assert assi_3.est_just is True, "Vérification Modification couverture (d5)"
+
+ # Déjustification des assiduités
+ justif_5.dejustifier_assiduites()
+ assi_ids: list[int] = justif_5.dejustifier_assiduites()
+ assert len(assi_ids) == 2, "Vérification Modification couverture (d6)"
+ assert assi_2.assiduite_id in assi_ids, "Vérification Modification couverture (d7)"
+ assert assi_3.assiduite_id in assi_ids, "Vérification Modification couverture (d8)"
+ assert assi_2.est_just is False, "Vérification Modification couverture (d9)"
+ assert assi_3.est_just is False, "Vérification Modification couverture (d10)"
+
+ # <=>Justification Partielle<=>
+ # Seule la première assiduité est couverte
+
+ justif_5.date_fin = scu.is_iso_formated("2024-01-08T11:00", True)
+ db.session.add(justif_5)
+ db.session.commit()
+
+ assi_ids: list[int] = justif_5.justifier_assiduites()
+ assert len(assi_ids) == 1, "Vérification Modification couverture (e1)"
+ assert assi_2.assiduite_id in assi_ids, "Vérification Modification couverture (e2)"
+ assert (
+ assi_3.assiduite_id not in assi_ids
+ ), "Vérification Modification couverture (e3)"
+ assert assi_2.est_just is True, "Vérification Modification couverture (e4)"
+ assert assi_3.est_just is False, "Vérification Modification couverture (e5)"
+
+ assi_ids: list[int] = justif_5.dejustifier_assiduites()
+ assert len(assi_ids) == 1, "Vérification Modification couverture (e6)"
+ assert assi_2.assiduite_id in assi_ids, "Vérification Modification couverture (e7)"
+ assert (
+ assi_3.assiduite_id not in assi_ids
+ ), "Vérification Modification couverture (e3)"
+ assert assi_2.est_just is False, "Vérification Modification couverture (e8)"
+ assert assi_3.est_just is False, "Vérification Modification couverture (e9)"
+
+ # <=>Justification Multiple<=>
+ # Deux justificatifs couvrent une même assiduité
+
+ # on justifie la première assiduité avec le premier justificatif
+ justif_5.justifier_assiduites()
+
+ # deuxième justificatif
+ justif_6: Justificatif = Justificatif.create_justificatif(
+ etudiant=etud_1,
+ date_debut=scu.is_iso_formated("2024-01-08T08:00", True),
+ date_fin=scu.is_iso_formated("2024-01-08T10:00", True),
+ etat=scu.EtatJustificatif.VALIDE,
+ )
+
+ assi_ids: list[int] = justif_6.justifier_assiduites()
+ assert len(assi_ids) == 1, "Vérification Modification couverture (f1)"
+ assert assi_2.assiduite_id in assi_ids, "Vérification Modification couverture (f2)"
+ assert (
+ assi_3.assiduite_id not in assi_ids
+ ), "Vérification Modification couverture (f3)"
+ assert assi_2.est_just is True, "Vérification Modification couverture (f4)"
+ assert assi_3.est_just is False, "Vérification Modification couverture (f5)"
+
+ # on déjustifie le justificatif 5
+ justif_5.etat = scu.EtatJustificatif.NON_VALIDE
+ db.session.add(justif_5)
+ db.session.commit()
+
+ assi_ids: list[int] = justif_5.dejustifier_assiduites()
+ assert len(assi_ids) == 0, "Vérification Modification couverture (f6)"
+ assert (
+ assi_2.assiduite_id not in assi_ids
+ ), "Vérification Modification couverture (f7)"
+ assert assi_2.est_just is True, "Vérification Modification couverture (f8)"
+
+ # on déjustifie le justificatif 6
+ justif_6.etat = scu.EtatJustificatif.NON_VALIDE
+ db.session.add(justif_6)
+ db.session.commit()
+ assi_ids: list[int] = justif_6.dejustifier_assiduites()
+ assert len(assi_ids) == 1, "Vérification Modification couverture (f9)"
+ assert assi_2.assiduite_id in assi_ids, "Vérification Modification couverture (f10)"
+ assert assi_2.est_just is False, "Vérification Modification couverture (f11)"
+
+ # <=>Justification Chevauchée<=>
+ # 1 justificatif chevauche une assiduité (8h -> 10h) (9h -> 11h)
+
+ justif_7: Justificatif = Justificatif.create_justificatif(
+ etudiant=etud_1,
+ date_debut=scu.is_iso_formated("2024-01-08T09:00", True),
+ date_fin=scu.is_iso_formated("2024-01-08T11:00", True),
+ etat=scu.EtatJustificatif.VALIDE,
+ )
+
+ assi_ids: list[int] = justif_7.justifier_assiduites()
+ assert len(assi_ids) == 0, "Vérification Modification couverture (g1)"
+ assert (
+ assi_2.assiduite_id not in assi_ids
+ ), "Vérification Modification couverture (g2)"
+ assert assi_2.est_just is False, "Vérification Modification couverture (g3)"
+
+ # Modification pour correspondre à l'assiduité
+ justif_7.date_debut = scu.is_iso_formated("2024-01-08T08:00", True)
+ db.session.add(justif_7)
+ db.session.commit()
+
+ assi_ids: list[int] = justif_7.justifier_assiduites()
+ assert len(assi_ids) == 1, "Vérification Modification couverture (g4)"
+ assert assi_2.assiduite_id in assi_ids, "Vérification Modification couverture (g5)"
+ assert assi_2.est_just is True, "Vérification Modification couverture (g6)"
+
+
+def test_cache_assiduites(test_client):
+ """Vérification du bon fonctionnement du cache des assiduités"""
+
+ data = _setup_fake_db(
+ [("2024-01-01", "2024-06-30"), ("2024-07-01", "2024-12-31")],
+ 1,
+ 1,
+ )
+
+ formsemestre1: FormSemestre = data["formsemestres"][0]
+ formsemestre2: FormSemestre = data["formsemestres"][1]
+
+ moduleimpl: ModuleImpl = data["moduleimpls"][0]
+ etud: Identite = data["etuds"][0]
+
+ # Création des assiduités
+ assiduites: list[dict] = [
+ # Semestre 1
+ {
+ "date_debut": "2024-01-08T08:00",
+ "date_fin": "2024-01-08T10:00",
+ "moduleimpl": moduleimpl,
+ },
+ {
+ "date_debut": "2024-01-08T14:00",
+ "date_fin": "2024-01-08T16:00",
+ "moduleimpl": moduleimpl,
+ },
+ {
+ "date_debut": "2024-01-09T08:00",
+ "date_fin": "2024-01-09T10:00",
+ "moduleimpl": None,
+ },
+ {
+ "date_debut": "2024-01-09T14:00",
+ "date_fin": "2024-01-09T16:00",
+ "moduleimpl": None,
+ },
+ {
+ "date_debut": "2024-01-10T08:00",
+ "date_fin": "2024-01-10T10:00",
+ "moduleimpl": None,
+ },
+ {
+ "date_debut": "2024-01-10T14:00",
+ "date_fin": "2024-01-10T16:00",
+ "moduleimpl": moduleimpl,
+ },
+ # Semestre 2
+ {
+ "date_debut": "2024-07-09T14:00",
+ "date_fin": "2024-07-09T16:00",
+ "moduleimpl": None,
+ },
+ {
+ "date_debut": "2024-07-10T08:00",
+ "date_fin": "2024-07-10T10:00",
+ "moduleimpl": None,
+ },
+ {
+ "date_debut": "2024-07-10T14:00",
+ "date_fin": "2024-07-10T16:00",
+ "moduleimpl": None,
+ },
+ ]
+
+ justificatifs: list[dict] = [
+ {
+ "date_debut": "2024-01-10T00:00",
+ "date_fin": "2024-01-10T23:59",
+ },
+ {
+ "date_debut": "2024-07-09T00:00",
+ "date_fin": "2024-07-09T23:59",
+ },
+ ]
+
+ # On ajoute les assiduités et les justificatifs
+
+ for assi in assiduites:
+ Assiduite.create_assiduite(
+ etud=etud,
+ date_debut=scu.is_iso_formated(assi["date_debut"], True),
+ date_fin=scu.is_iso_formated(assi["date_fin"], True),
+ moduleimpl=assi["moduleimpl"],
+ etat=scu.EtatAssiduite.ABSENT,
+ )
+
+ for justi in justificatifs:
+ Justificatif.create_justificatif(
+ etudiant=etud,
+ date_debut=scu.is_iso_formated(justi["date_debut"], True),
+ date_fin=scu.is_iso_formated(justi["date_fin"], True),
+ etat=scu.EtatJustificatif.VALIDE,
+ ).justifier_assiduites()
+
+ # Premier semestre 4nj / 2j / 6t
+ assert scass.get_assiduites_count(etud.id, formsemestre1.to_dict()) == (4, 2, 6)
+ assert scass.formsemestre_get_assiduites_count(etud.id, formsemestre1) == (4, 2, 6)
+
+ # ModuleImpl 2nj / 1j / 3t
+ assert scass.formsemestre_get_assiduites_count(
+ etud.id, formsemestre1, moduleimpl.id
+ ) == (2, 1, 3)
+ # Deuxième semestre 2nj / 1j / 3t
+ assert scass.get_assiduites_count(etud.id, formsemestre2.to_dict()) == (2, 1, 3)
+
+ # On supprime la première assiduité (sans invalider le cache)
+ assi: Assiduite = Assiduite.query.filter_by(etudid=etud.id).first()
+ db.session.delete(assi)
+ db.session.commit()
+
+ # Premier semestre 4nj / 2j / 6t (Identique car cache)
+ assert scass.get_assiduites_count(etud.id, formsemestre1.to_dict()) == (4, 2, 6)
+ assert scass.formsemestre_get_assiduites_count(etud.id, formsemestre1) == (4, 2, 6)
+ # ModuleImpl 1nj / 1j / 2t (Change car non cache)
+ assert scass.formsemestre_get_assiduites_count(
+ etud.id, formsemestre1, moduleimpl.id
+ ) == (1, 1, 2)
+ # Deuxième semestre 2nj / 1j / 3t (Identique car cache et non modifié)
+ assert scass.get_assiduites_count(etud.id, formsemestre2.to_dict()) == (2, 1, 3)
+
+ # On invalide maintenant le cache
+ scass.invalidate_assiduites_count(etud.id, formsemestre1.to_dict())
+
+ # Premier semestre 3nj / 2j / 5t (Change car cache invalidé)
+ assert scass.get_assiduites_count(etud.id, formsemestre1.to_dict()) == (3, 2, 5)
+ assert scass.formsemestre_get_assiduites_count(etud.id, formsemestre1) == (3, 2, 5)
+ # ModuleImpl 1nj / 1j / 2t (Ne change pas car pas de changement)
+ assert scass.formsemestre_get_assiduites_count(
+ etud.id, formsemestre1, moduleimpl.id
+ ) == (1, 1, 2)
+ # Deuxième semestre 2nj / 1j / 3t (Identique car cache et non modifié)
+ assert scass.get_assiduites_count(etud.id, formsemestre2.to_dict()) == (2, 1, 3)
diff --git a/tests/unit/test_sco_basic.py b/tests/unit/test_sco_basic.py
index d4cb7a729..b3bba2e20 100644
--- a/tests/unit/test_sco_basic.py
+++ b/tests/unit/test_sco_basic.py
@@ -33,7 +33,6 @@ from app.scodoc import sco_formsemestre_validation
from app.scodoc import sco_cursus_dut
from app.scodoc import sco_saisie_notes
from app.scodoc.sco_utils import EtatAssiduite, EtatJustificatif, localize_datetime
-from app.models.assiduites import compute_assiduites_justified
DEPT = TestConfig.DEPT_TEST
@@ -192,7 +191,7 @@ def run_sco_basic(verbose=False, dept=None) -> FormSemestre:
etudid = etuds[0]["etudid"]
_signal_absences_justificatifs(etudid)
- nbabs, nbabsjust = scass.get_assiduites_count(etudid, sem)
+ _, nbabsjust, nbabs = scass.get_assiduites_count(etudid, sem)
assert nbabs == 6, f"incorrect nbabs ({nbabs})"
assert nbabsjust == 2, f"incorrect nbabsjust ({nbabsjust})"
@@ -267,8 +266,5 @@ def _signal_absences_justificatifs(etudid: int):
etat=EtatJustificatif.VALIDE,
)
db.session.add(justif)
- compute_assiduites_justified(
- etud.etudid,
- [justif],
- )
db.session.commit()
+ justif.justifier_assiduites()
diff --git a/tools/fakedatabase/create_test_api_database.py b/tools/fakedatabase/create_test_api_database.py
index 5b3e96a2c..cd5182bee 100644
--- a/tools/fakedatabase/create_test_api_database.py
+++ b/tools/fakedatabase/create_test_api_database.py
@@ -396,7 +396,7 @@ def ajouter_assiduites_justificatifs(formsemestre: FormSemestre):
for etud in formsemestre.etuds:
base_date = datetime.datetime(
- 2022, 9, [5, 12, 19, 26][random.randint(0, 3)], 8, 0, 0
+ 2021, 9, [6, 13, 20, 27][random.randint(0, 3)], 8, 0, 0
)
base_date = localize_datetime(base_date)