Assiduités : Amélioration Migration et Tests Unitaires

This commit is contained in:
iziram 2023-07-21 19:21:29 +02:00
parent 5ea9944be2
commit 76ccb8ea66
2 changed files with 334 additions and 61 deletions

View File

@ -8,18 +8,14 @@ ses fonctions liées
Ecrit par HARTMANN Matthias (en s'inspirant de tests.unit.test_abs_count.py par Fares Amer ) Ecrit par HARTMANN Matthias (en s'inspirant de tests.unit.test_abs_count.py par Fares Amer )
""" """
from tests.unit import sco_fake_gen
from app import db
from app.scodoc import sco_formsemestre
import app.scodoc.sco_assiduites as scass import app.scodoc.sco_assiduites as scass
from app.models import Assiduite, Justificatif, Identite, FormSemestre, ModuleImpl
from app.scodoc.sco_exceptions import ScoValueError
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.sco_abs import get_abs_count_in_interval from app import db
from app.scodoc import sco_abs_views from app.models import Assiduite, FormSemestre, Identite, Justificatif, ModuleImpl
from tools import migrate_abs_to_assiduites, downgrade_module from app.scodoc import sco_abs_views, sco_formsemestre
from app.scodoc.sco_exceptions import ScoValueError
from tests.unit import sco_fake_gen
from tools import downgrade_module, migrate_abs_to_assiduites
class BiInt(int, scu.BiDirectionalEnum): class BiInt(int, scu.BiDirectionalEnum):
@ -153,43 +149,179 @@ def verif_migration_abs_assiduites():
etudid: int = 1 etudid: int = 1
for debut, fin, demijournee in [ for debut, fin, demijournee, justifiee in [
( (
"02/01/2023", "02/01/2023",
"10/01/2023", "02/01/2023",
1,
False,
), # 1 assi 02/01/2023 8h > 13h (1dj)
(
"03/01/2023",
"03/01/2023",
0,
False,
), # 1 assi 03/01/2023 13h > 18h (1dj)
(
"05/01/2023",
"05/01/2023",
2, 2,
), # 2 assiduités 02/01: 08h -> 06/01: 18h & assiduités 09/01: 08h -> 10/01: 18h | 14dj False,
("16/01/2023", "16/01/2023", 1), # 1 assiduité 16/01: 08h -> 16/01: 12h | 1dj ), # 1 assi 05/01/2023 8h > 18h (2dj)
("19/01/2023", "19/01/2023", 0), # 1 assiduité 19/01: 12h -> 19/01: 18h | 1dj (
("18/01/2023", "18/01/2023", 2), # 1 assiduité 18/01: 08h -> 18/01: 18h | 2dj "09/01/2023",
("23/01/2023", "23/01/2023", 0), # 1 assiduité 23/01: 12h -> 24/01: 18h | 3dj "09/01/2023",
("24/01/2023", "24/01/2023", 2), 1,
False,
),
(
"09/01/2023",
"09/01/2023",
0,
False,
), # 1 assi 09/01/2023 8h > 18h (2dj)
(
"10/01/2023",
"10/01/2023",
0,
False,
),
(
"11/01/2023",
"11/01/2023",
1,
False,
), # 1 assi 10/01/2023 - 11/01/2023 13h > 13h (2dj)
(
"12/01/2023",
"12/01/2023",
1,
False,
), # 1 assi 12/01/2023 8h > 13h (1dj)
(
"13/01/2023",
"13/01/2023",
1,
False,
), # 1 assi 13/01/2023 8h > 13h (1dj)
(
"16/01/2023",
"16/01/2023",
1,
False,
),
(
"16/01/2023",
"16/01/2023",
1,
False,
), # 1 assi 16/01/2023 8h > 13h (1dj)
(
"19/01/2023",
"24/01/2023",
2,
False,
), # 2 assi 19/01/2023 - 20/01/2023 8h > 18h (4dj) + 23/01/23 - 24/01/2023 8h>18h (4dj)
(
"01/02/2023",
"01/02/2023",
1,
True,
), # 1 assi 01/02/2023 8h > 13h (1dj) JUSTI
(
"02/02/2023",
"02/02/2023",
0,
True,
), # 1 assi 02/02/2023 13h > 18h (1dj) JUSTI
(
"06/02/2023",
"06/02/2023",
2,
True,
), # 1 assi 06/02/2023 8h > 18h (2dj) JUSTI
(
"07/02/2023",
"07/02/2023",
0,
True,
),
(
"07/02/2023",
"07/02/2023",
0,
False,
), # 1 assi 07/02/2023 13h > 18h (1dj) JUSTI
(
"08/02/2023",
"08/02/2023",
0,
False,
),
(
"08/02/2023",
"08/02/2023",
0,
True,
), # 1 assi 08/02/2023 13h > 18h (1dj) JUSTI
(
"10/02/2023",
"10/02/2023",
1,
True,
),
(
"10/02/2023",
"10/02/2023",
0,
False,
), # 1 assi 10/02/2023 08h > 18h (2dj) JUSTI
(
"13/02/2023",
"13/02/2023",
1,
False,
),
(
"13/02/2023",
"13/02/2023",
0,
True,
), # 1 assi 13/02/2023 08h > 18h (2dj) JUSTI
(
"15/02/2023",
"15/02/2023",
2,
False,
), # 1 assi 13/02/2023 08h > 18h (2dj) JUSTI(ext)
(
"22/02/2023",
"24/02/2023",
1,
False,
), # 3 assi 22-23-24/02/2023 08h > 13h (3dj) JUSTI(ext)
]: ]:
sco_abs_views.doSignaleAbsence( sco_abs_views.doSignaleAbsence(
datedebut=debut, datedebut=debut,
datefin=fin, datefin=fin,
demijournee=demijournee, demijournee=demijournee,
etudid=etudid, etudid=etudid,
estjust=justifiee,
) )
# --- Justification de certaines absences # --- Justification de certaines absences
for debut, fin, demijournee in [ for debut, fin, demijournee in [
( (
"02/01/2023", "15/02/2023",
"10/01/2023", "15/02/2023",
2, 2,
), # 2 justificatif 02/01: 08h -> 06/01: 18h & justificatif 09/01: 08h -> 10/01: 18h | 14dj ),
( (
"19/01/2023", "21/02/2023",
"19/01/2023", "24/02/2023",
0,
), # 1 justificatif 19/01: 12h -> 19/01: 18h | 1dj
(
"18/01/2023",
"18/01/2023",
2, 2,
), # 1 justificatif 18/01: 08h -> 18/01: 18h | 2dj ),
]: ]:
sco_abs_views.doJustifAbsence( sco_abs_views.doJustifAbsence(
datedebut=debut, datedebut=debut,
@ -200,22 +332,147 @@ def verif_migration_abs_assiduites():
migrate_abs_to_assiduites() migrate_abs_to_assiduites()
assert Assiduite.query.count() == 6, "Erreur migration assiduites" assert Assiduite.query.count() == 21, "Migration : Nb Assiduités FAUX"
assert Justificatif.query.count() == 4, "Erreur migration justificatifs" assert Justificatif.query.count() == 9, "Migration : Nb Justificatif FAUX"
# Cas classiques sans justification
assert (
_get_assi("2023-01-02T08:00", "2023-01-02T13:00") is not None
), "Migration : Abs n°1 mal migrée"
assert (
_get_assi("2023-01-03T13:00", "2023-01-03T18:00") is not None
), "Migration : Abs n°2 mal migrée"
assert (
_get_assi("2023-01-05T08:00", "2023-01-05T18:00") is not None
), "Migration : Abs n°3 mal migrée"
assert (
_get_assi("2023-01-09T08:00", "2023-01-09T18:00") is not None
), "Migration : Abs n°4&5 mal migrée"
assert (
_get_assi("2023-01-10T13:00", "2023-01-11T13:00") is not None
), "Migration : Abs n°6&7 mal migrée"
assert (
_get_assi("2023-01-12T08:00", "2023-01-12T13:00") is not None
), "Migration : Abs n°8 mal migrée"
assert (
_get_assi("2023-01-13T08:00", "2023-01-13T13:00") is not None
), "Migration : Abs n°9 mal migrée"
assert (
_get_assi("2023-01-16T08:00", "2023-01-16T13:00") is not None
), "Migration : Abs n°10&11 mal migrée"
assert (
_get_assi("2023-01-19T08:00", "2023-01-20T18:00") is not None
), "Migration : Abs n°12 mal migrée"
assert (
_get_assi("2023-01-23T08:00", "2023-01-24T18:00") is not None
), "Migration : Abs n°12 mal migrée"
# Cas d'absences justifiées
assert (
_get_assi("2023-02-01T08:00", "2023-02-01T13:00", True) is not None
), "Migration : Abs n°13 mal migrée"
assert (
_get_assi("2023-02-02T13:00", "2023-02-02T18:00", True) is not None
), "Migration : Abs n°14 mal migrée"
assert (
_get_assi("2023-02-06T08:00", "2023-02-06T18:00", True) is not None
), "Migration : Abs n°15 mal migrée"
assert (
_get_assi("2023-02-07T13:00", "2023-02-07T18:00", True) is not None
), "Migration : Abs n°16&17 mal migrée"
assert (
_get_assi("2023-02-08T13:00", "2023-02-08T18:00", True) is not None
), "Migration : Abs n°18&19 mal migrée"
assert (
_get_assi("2023-02-10T08:00", "2023-02-10T18:00", True) is not None
), "Migration : Abs n°20&21 mal migrée"
assert (
_get_assi("2023-02-13T08:00", "2023-02-13T18:00", True) is not None
), "Migration : Abs n°22&23 mal migrée"
# Cas Justificatifs
assert (
_get_justi("2023-02-01T08:00", "2023-02-01T13:00") is not None
), "Migration : Abs n°13 mal migrée"
assert (
_get_justi("2023-02-02T13:00", "2023-02-02T18:00") is not None
), "Migration : Abs n°14 mal migrée"
assert (
_get_justi("2023-02-06T08:00", "2023-02-06T18:00") is not None
), "Migration : Abs n°15 mal migrée"
assert (
_get_justi("2023-02-07T13:00", "2023-02-07T18:00") is not None
), "Migration : Abs n°16&17 mal migrée"
assert (
_get_justi("2023-02-08T13:00", "2023-02-08T18:00") is not None
), "Migration : Abs n°18&19 mal migrée"
assert (
_get_justi("2023-02-10T08:00", "2023-02-10T18:00") is not None
), "Migration : Abs n°20&21 mal migrée"
assert (
_get_justi("2023-02-13T08:00", "2023-02-13T18:00") is not None
), "Migration : Abs n°22&23 mal migrée"
assert (
_get_justi("2023-02-15T08:00", "2023-02-15T18:00") is not None
), "Migration : Justi n°1 mal migré"
assert (
_get_assi("2023-02-15T08:00", "2023-02-15T18:00", True) is not None
), "Migration : Abs n°24 mal migrée"
assert (
_get_justi("2023-02-21T08:00", "2023-02-24T18:00") is not None
), "Migration : Justi n°2 mal migré"
assert (
_get_assi("2023-02-22T08:00", "2023-02-22T13:00", True) is not None
), "Migration : Abs n°25 mal migrée"
assert (
_get_assi("2023-02-23T08:00", "2023-02-23T13:00", True) is not None
), "Migration : Abs n°26 mal migrée"
assert (
_get_assi("2023-02-24T08:00", "2023-02-24T13:00", True) is not None
), "Migration : Abs n°27 mal migrée"
essais_cache(etudid) essais_cache(etudid)
downgrade_module(assiduites=True, justificatifs=True) downgrade_module(assiduites=True, justificatifs=True)
def _get_assi(
deb: str,
fin: str,
est_just: bool = False,
):
deb = scu.localize_datetime(scu.is_iso_formated(deb, True))
fin = scu.localize_datetime(scu.is_iso_formated(fin, True))
return Assiduite.query.filter(
Assiduite.date_debut >= deb,
Assiduite.date_fin <= fin,
Assiduite.est_just == est_just,
).first()
def _get_justi(
deb: str,
fin: str,
):
deb = scu.localize_datetime(scu.is_iso_formated(deb, True))
fin = scu.localize_datetime(scu.is_iso_formated(fin, True))
return Justificatif.query.filter(
Justificatif.date_debut >= deb,
Justificatif.date_fin <= fin,
).first()
def essais_cache(etudid): def essais_cache(etudid):
"""Vérification des fonctionnalités du cache TODO:WIP""" """Vérification des fonctionnalités du cache TODO:WIP"""
date_deb: str = "2023-01-01T07:00" date_deb: str = "2023-01-01T07:00"
date_fin: str = "2023-03-31T19:00" date_fin: str = "2023-03-31T19:00"
abs_count_no_cache: int = get_abs_count_in_interval(etudid, date_deb, date_fin)
abs_count_cache = get_abs_count_in_interval(etudid, date_deb, date_fin)
assiduites_count_no_cache = scass.get_assiduites_count_in_interval( assiduites_count_no_cache = scass.get_assiduites_count_in_interval(
etudid, date_deb, date_fin etudid, date_deb, date_fin
) )
@ -224,11 +481,7 @@ def essais_cache(etudid):
) )
assert ( assert (
abs_count_cache assiduites_count_cache == assiduites_count_no_cache == (34, 15)
== abs_count_no_cache
== assiduites_count_cache
== assiduites_count_no_cache
== (21, 17)
), "Erreur cache" ), "Erreur cache"

View File

@ -46,6 +46,8 @@ class _glob:
MERGER_ASSI: "_Merger" = None MERGER_ASSI: "_Merger" = None
MERGER_JUST: "_Merger" = None MERGER_JUST: "_Merger" = None
JUSTIFS: dict[int, list[tuple[datetime, datetime]]] = {}
MORNING: time = None MORNING: time = None
NOON: time = None NOON: time = None
EVENING: time = None EVENING: time = None
@ -60,6 +62,7 @@ class _Merger:
self.est_abs = est_abs self.est_abs = est_abs
self.raison = abs_.description self.raison = abs_.description
self.entry_date = abs_.entry_date self.entry_date = abs_.entry_date
self.est_just = abs_.estjust
def merge(self, abs_: Absence) -> bool: def merge(self, abs_: Absence) -> bool:
"""Fusionne les absences. """Fusionne les absences.
@ -78,10 +81,13 @@ class _Merger:
return False return False
else: else:
day_after: date = abs_.jour - timedelta(days=1) == self.fin[0] day_after: date = abs_.jour - timedelta(days=1) == self.fin[0]
if not (day_after and abs_.matin): if not (day_after and abs_.matin and self.est_just == abs_.estjust):
return False return False
self.est_just = self.est_just or abs_.estjust
self.fin = (abs_.jour, abs_.matin) self.fin = (abs_.jour, abs_.matin)
return True return True
@staticmethod @staticmethod
@ -99,6 +105,8 @@ class _Merger:
date_deb = _Merger._tuple_to_date(self.deb) date_deb = _Merger._tuple_to_date(self.deb)
date_fin = _Merger._tuple_to_date(self.fin, end=True) date_fin = _Merger._tuple_to_date(self.fin, end=True)
_glob.JUSTIFS[self.etudid].append((date_deb, date_fin))
_glob.cursor.execute( _glob.cursor.execute(
"""INSERT INTO justificatifs """INSERT INTO justificatifs
(etudid,date_debut,date_fin,etat,raison,entry_date) (etudid,date_debut,date_fin,etat,raison,entry_date)
@ -127,10 +135,19 @@ class _Merger:
date_deb = _Merger._tuple_to_date(self.deb) date_deb = _Merger._tuple_to_date(self.deb)
date_fin = _Merger._tuple_to_date(self.fin, end=True) date_fin = _Merger._tuple_to_date(self.fin, end=True)
self.est_just = (
_assi_in_justifs(date_deb, date_fin, self.etudid) or self.est_just
)
if _glob.MERGER_JUST is not None and not self.est_just:
justi_date_deb = _Merger._tuple_to_date(_glob.MERGER_JUST.deb)
justi_date_fin = _Merger._tuple_to_date(_glob.MERGER_JUST.fin, end=True)
justifiee = date_deb >= justi_date_deb and date_fin <= justi_date_fin
self.est_just = justifiee
_glob.cursor.execute( _glob.cursor.execute(
"""INSERT INTO assiduites """INSERT INTO assiduites
(etudid,date_debut,date_fin,etat,moduleimpl_id,"description",entry_date) (etudid,date_debut,date_fin,etat,moduleimpl_id,description,entry_date,est_just)
VALUES (%(etudid)s,%(date_debut)s,%(date_fin)s,%(etat)s,%(moduleimpl_id)s,%(description)s,%(entry_date)s) VALUES (%(etudid)s,%(date_debut)s,%(date_fin)s,%(etat)s,%(moduleimpl_id)s,%(description)s,%(entry_date)s, %(est_just)s)
""", """,
{ {
"etudid": self.etudid, "etudid": self.etudid,
@ -140,6 +157,7 @@ class _Merger:
"moduleimpl_id": self.moduleimpl, "moduleimpl_id": self.moduleimpl,
"description": self.raison, "description": self.raison,
"entry_date": self.entry_date, "entry_date": self.entry_date,
"est_just": self.est_just,
}, },
) )
@ -165,6 +183,10 @@ class _Merger:
self._to_justif() self._to_justif()
def _assi_in_justifs(deb, fin, etudid):
return any(deb >= j[0] and fin <= j[1] for j in _glob.JUSTIFS[etudid])
class _Statistics: class _Statistics:
def __init__(self) -> None: def __init__(self) -> None:
self.object: dict[str, dict or int] = {"total": 0} self.object: dict[str, dict or int] = {"total": 0}
@ -307,6 +329,8 @@ def migrate_dept(dept_name: str, stats: _Statistics, time_elapsed: Profiler):
raise ValueError(f"Département inexistant: {dept_name}") raise ValueError(f"Département inexistant: {dept_name}")
etuds_id: list[int] = [etud.id for etud in dept.etudiants] etuds_id: list[int] = [etud.id for etud in dept.etudiants]
for etudid in etuds_id:
_glob.JUSTIFS[etudid] = []
absences_query = absences_query.filter(Absence.etudid.in_(etuds_id)) absences_query = absences_query.filter(Absence.etudid.in_(etuds_id))
absences: Absence = absences_query.order_by( absences: Absence = absences_query.order_by(
Absence.etudid, Absence.jour, not_(Absence.matin) Absence.etudid, Absence.jour, not_(Absence.matin)
@ -380,14 +404,14 @@ def migrate_dept(dept_name: str, stats: _Statistics, time_elapsed: Profiler):
autosize=True, autosize=True,
) )
print( # print(
TerminalColor.RED # TerminalColor.RED
+ f"Justification des absences du département {dept_name}, veuillez patienter, ceci peut prendre un certain temps." # + f"Justification des absences du département {dept_name}, veuillez patienter, ceci peut prendre un certain temps."
+ TerminalColor.RESET # + TerminalColor.RESET
) # )
justifs: Justificatif = Justificatif.query.join(Identite).filter_by(dept_id=dept.id) # justifs: Justificatif = Justificatif.query.join(Identite).filter_by(dept_id=dept.id)
compute_assiduites_justified(justifs, reset=True) # compute_assiduites_justified(justifs, reset=True)
time_elapsed.stop() time_elapsed.stop()
@ -432,20 +456,16 @@ def _from_abs_to_assiduite_justificatif(_abs: Absence, etud_modimpl_ids: set[int
if _glob.MERGER_ASSI is None: if _glob.MERGER_ASSI is None:
_glob.MERGER_ASSI = _Merger(_abs, True) _glob.MERGER_ASSI = _Merger(_abs, True)
return True
elif _glob.MERGER_ASSI.merge(_abs): elif _glob.MERGER_ASSI.merge(_abs):
return True pass
else: else:
_glob.MERGER_ASSI.export() _glob.MERGER_ASSI.export()
_glob.MERGER_ASSI = _Merger(_abs, True) _glob.MERGER_ASSI = _Merger(_abs, True)
return False if _abs.estjust:
if _glob.MERGER_JUST is None:
if _glob.MERGER_JUST is None: _glob.MERGER_JUST = _Merger(_abs, False)
_glob.MERGER_JUST = _Merger(_abs, False) elif _glob.MERGER_JUST.merge(_abs):
return True pass
elif _glob.MERGER_JUST.merge(_abs): else:
return True _glob.MERGER_JUST.export()
else: _glob.MERGER_JUST = _Merger(_abs, False)
_glob.MERGER_JUST.export()
_glob.MERGER_JUST = _Merger(_abs, False)
return False