Merge pull request 'dates antipodiques: ajout get_periode, tests et intégration' (#527) from jmplace/ScoDoc-Lille:improve_periode_management into master

Reviewed-on: https://scodoc.org/git/ScoDoc/ScoDoc/pulls/527
This commit is contained in:
Emmanuel Viennet 2022-11-11 09:40:02 +01:00
commit 51d7dff649
4 changed files with 211 additions and 54 deletions

View File

@ -586,7 +586,16 @@ class ApoEtud(dict):
(sem["semestre_id"] == apo_data.cur_semestre_id)
and (apo_data.etape in sem["etapes"])
and (
sco_formsemestre.sem_in_annee_scolaire(sem, apo_data.annee_scolaire)
# sco_formsemestre.sem_in_annee_scolaire(sem, apo_data.annee_scolaire) # TODO à remplacer par ?
sco_formsemestre.sem_in_semestre_scolaire(
sem,
apo_data.annee_scolaire,
0,
# jour_pivot_annee,
# mois_pivot_annee,
# jour_pivot_periode,
# mois_pivot_periode
)
)
)
]

View File

@ -422,67 +422,97 @@ def sem_set_responsable_name(sem):
)
def debut_in_semestre_scolaire(
date_debut: datetime.date, year: int = False, saison: int = 0
) -> bool:
"""Vrai si date_debut est dans l'année scolaire ou le semestre
indiquée par year et periode
(par défaut, l'année scolaire en cours).
periode:
1 = sept,
0 = janvier
None = année complète
def get_periode(
debut: datetime,
jour_pivot_annee=1,
mois_pivot_annee=8,
jour_pivot_periode=1,
mois_pivot_periode=12,
):
"""Calcule la session associée à un formsemestre sous la forme (année, période)
année: première année de l'année scolaire
période = 1 (première période de l'année scolaire anciennement automne)
ou 2 (deuxième période de l'année scolaire - anciennement printemps)
les quatre derniers paramètres forment les dates pivots pour l'année (1er août par défaut)
et pour la période (1er décembre par défaut).
Tous les calculs se font à partir de la date de début du formsemestre.
Exemples dans tests/unit/test_periode
"""
if not year:
year = scu.AnneeScolaire()
# XXX WIP à voir selon ce que fait réellement sem_in_semestre_scolaire
"""Implementation
Cas à considérer pour le calcul de la période
def sem_in_semestre_scolaire(sem, year=False, saison=0):
"""n'utilise que la date de debut, pivot au 1er aout
si annee non specifiée, année scolaire courante
Patch Jmp: ajout du parametre optionnel saison
1 = sept, 0 = janvier, None = année complète
si saison non spécifiée: année complète
pivot de saison au 1er décembre
XXX TODO: la période (ici appelée "saison" devrait être éditable
manuellement dans le formsemestre_edit afin de couvrir les cas particulier
comme un semestre S2 qui commencerait en décembre... voire novembre.
)
pa < pp -----------------|-------------------|---------------->
(A-1, P:2) pa (A, P:1) pp (A, P:2)
pp < pa -----------------|-------------------|---------------->
(A-1, P:1) pp (A-1, P:2) pa (A, P:1)
"""
if not year:
year = scu.AnneeScolaire()
# est-on dans la même année universitaire ?
if sem["mois_debut_ord"] > 7: # XXX
if sem["annee_debut"] != str(year):
return False
pa = 100 * mois_pivot_annee + jour_pivot_annee
pp = 100 * mois_pivot_periode + jour_pivot_periode
ps = 100 * debut.month + debut.day
if ps < pa:
annee = debut.year - 1
else:
if sem["annee_debut"] != str(year + 1):
return False
# raffinement éventuel sur le semestre
# saison is None => pas de rafinement => True
if saison == 0:
return True
elif saison == 1: # calcul en fonction de la saison
return sem["mois_debut_ord"] > 7 and sem["mois_debut_ord"] < 12
else: # saison == 0
return sem["mois_debut_ord"] <= 7 or sem["mois_debut_ord"] == 12
annee = debut.year
if pa < pp:
if ps < pa or ps > pp:
periode = 2
else:
periode = 1
else:
if ps < pp or ps > pa:
periode = 1
else:
periode = 2
return annee, periode
def sem_in_annee_scolaire(sem, year=False):
"""Test si sem appartient à l'année scolaire year (int).
N'utilise que la date de début, pivot au 1er août.
Si année non specifiée, année scolaire courante
def sem_in_semestre_scolaire(
sem,
year=False,
periode=None,
jour_pivot_annee=1,
mois_pivot_annee=8,
jour_pivot_periode=1,
mois_pivot_periode=12,
):
"""n'utilise que la date de debut,
si annee non specifiée, année scolaire courante
la période garde les même convention que semset["sem_id"];
* 1 : premère période
* 2 : deuxième période
* 0 ou periode non précisée: annualisé (donc inclut toutes les périodes)
)
"""
if not year:
year = scu.AnneeScolaire()
return (
(sem["annee_debut"] == str(year))
and (sem["mois_debut_ord"] > scu.MONTH_FIN_ANNEE_SCOLAIRE)
) or (
(sem["annee_debut"] == str(year + 1))
and (sem["mois_debut_ord"] <= scu.MONTH_FIN_ANNEE_SCOLAIRE)
# calcule l'année universitaire et la periode
sem_annee, sem_periode = get_periode(
datetime.datetime.fromisoformat(sem["date_debut_iso"]),
jour_pivot_annee,
mois_pivot_annee,
jour_pivot_periode,
mois_pivot_periode,
)
if periode is None or periode == 0:
return sem_annee == year
else:
return sem_annee == year and sem_periode == periode
# def sem_in_annee_scolaire(sem, year=False):
# """Test si sem appartient à l'année scolaire year (int).
# N'utilise que la date de début, pivot au 1er août.
# Si année non specifiée, année scolaire courante
# """
# if not year:
# year = scu.AnneeScolaire()
# return (
# (sem["annee_debut"] == str(year))
# and (sem["mois_debut_ord"] > scu.MONTH_FIN_ANNEE_SCOLAIRE)
# ) or (
# (sem["annee_debut"] == str(year + 1))
# and (sem["mois_debut_ord"] <= scu.MONTH_FIN_ANNEE_SCOLAIRE)
# )
def sem_est_courant(sem): # -> FormSemestre.est_courant

View File

@ -233,7 +233,8 @@ class SemSet(dict):
if sco_formsemestre.sem_in_semestre_scolaire(
sem,
year=self["annee_scolaire"],
saison=self["sem_id"],
# Indiquer ici les valeur des dates pivots année et période
periode=self["sem_id"],
)
]
return sems

117
tests/unit/test_periode.py Normal file
View File

@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
"""Test Periodes
Utiliser comme:
pytest tests/unit/test_periode.py
"""
import datetime
from app.scodoc.sco_formsemestre import get_periode, sem_in_semestre_scolaire
""" Calcule la session associée à un formsemestre sous la forme (année, période)
année: première année de l'année scolaire
période = 1 (première période de l'année scolaire) ou 2 (deuxième période de l'année scolaire)
les quatre derniers paramètres forment les dates pivots pour l'année (1er août par défaut)
et pour la période (1er décembre par défaut).
Tous les calculs se font à partir de la date de début du formsemestre.
Exemples:
Début FormSemestre pivot_année pivot_periode Résultat
01/01/2022 ( 1, 8) ( 1,12) (2021,2) # A: printemps nord
01/09/2022 ( 1, 8) ( 1,12) (2022,1) # B: automne nord
15/12/2022 ( 1, 8) ( 1,12) (2022,2)
30/07/2023 ( 1, 8) ( 1,12) (2022,2)
01/01/2022 ( 1, 1) ( 1, 8) (2022,1) # antipodes
30/07/2022 ( 1, 1) ( 1, 8) (2022,1) # antipodes
02/08/2022 ( 1, 1) ( 1, 8) (2022,2) # antipodes
30/12/2022 ( 1, 1) ( 1, 8) (2022,2) # antipodes
01/01/2022 ( 3, 1) ( 1, 8) (2021,2) # antipodes l'année scolaire démarre le 3 janvier
10/01/2024 ( 1, 8) ( 1, 2) (2023,2) # pivot période < pivot année
01/06/2024 ( 1, 8) ( 1, 2) (2023,2) # pivot période < pivot année
20/09/2024 ( 1, 8) ( 1, 2) (2024,1) # pivot période < pivot année
"""
def test_default():
# with default
assert (2021, 2) == get_periode(datetime.datetime(2022, 1, 1))
assert (2021, 2) == get_periode(datetime.datetime(2022, 1, 1), 1, 8, 1, 12)
def test_automne_nord():
assert (2022, 1) == get_periode(datetime.datetime(2022, 9, 1))
def test_noel_nord():
assert (2022, 2) == get_periode(datetime.datetime(2022, 12, 15))
def test_étét_nord():
assert (2021, 2) == get_periode(datetime.datetime(2022, 7, 30))
def test_printemps_sud():
assert (2022, 1) == get_periode(datetime.datetime(2022, 1, 1), 1, 1, 1, 8)
def test_automne_sud():
assert (2022, 2) == get_periode(datetime.datetime(2022, 8, 2), 1, 1, 1, 8)
def test_noel_sud():
assert (2022, 2) == get_periode(datetime.datetime(2022, 12, 30), 1, 1, 1, 8)
def test_été_sud():
assert (2022, 1) == get_periode(datetime.datetime(2022, 7, 30), 1, 1, 1, 8)
def test_nouvel_an_sud():
assert (2021, 2) == get_periode(datetime.datetime(2022, 1, 1), 3, 1, 1, 8)
def test_nouvel_an_special_pp_before_pa():
assert (2023, 1) == get_periode(datetime.datetime(2024, 1, 10), 1, 8, 1, 2)
def test_nouvel_été_pp_before_pa():
assert (2023, 2) == get_periode(datetime.datetime(2024, 6, 1), 1, 8, 1, 2)
def test_automne_special_pp_before_pa():
assert (2024, 1) == get_periode(datetime.datetime(2024, 9, 20), 1, 8, 1, 2)
sem_automne = {"date_debut_iso": "2022-09-24"}
sem_nouvel_an = {"date_debut_iso": "2023-01-01"}
sem_printemps = {"date_debut_iso": "2023-03-14"}
sem_été = {"date_debut_iso": "2023-07-11"}
sem_next_year = {"date_debut_iso": "2023-08-16"}
sem_prev_year = {"date_debut_iso": "2022-07-31"}
def test_sem_in_periode1_default():
assert True == sem_in_semestre_scolaire(sem_automne, 2022, 1)
assert False == sem_in_semestre_scolaire(sem_nouvel_an, 2022, 1)
assert False == sem_in_semestre_scolaire(sem_printemps, 2022, 1)
assert False == sem_in_semestre_scolaire(sem_été, 2022, 1)
assert False == sem_in_semestre_scolaire(sem_next_year, 2022, 1)
assert False == sem_in_semestre_scolaire(sem_prev_year, 2022, 1)
def test_sem_in_periode2_default():
assert False == sem_in_semestre_scolaire(sem_automne, 2022, 2)
assert True == sem_in_semestre_scolaire(sem_nouvel_an, 2022, 2)
assert True == sem_in_semestre_scolaire(sem_printemps, 2022, 2)
assert True == sem_in_semestre_scolaire(sem_été, 2022, 2)
assert False == sem_in_semestre_scolaire(sem_next_year, 2022, 1)
assert False == sem_in_semestre_scolaire(sem_prev_year, 2022, 1)
def test_sem_in_annee_default():
assert True == sem_in_semestre_scolaire(sem_automne, 2022, 0)
assert True == sem_in_semestre_scolaire(sem_nouvel_an, 2022)
assert True == sem_in_semestre_scolaire(sem_printemps, 2022, 0)
assert True == sem_in_semestre_scolaire(sem_été, 2022, 0)
assert False == sem_in_semestre_scolaire(sem_next_year, 2022)
assert False == sem_in_semestre_scolaire(sem_prev_year, 2022, 0)