Modif gestion dates annees scolaire pour mieux gérer l'hémisphère sud.

This commit is contained in:
Emmanuel Viennet 2024-12-18 17:33:18 +01:00
parent b6344c27a8
commit bb99cd8aa6
6 changed files with 104 additions and 43 deletions

View File

@ -526,7 +526,7 @@ class DecisionsProposeesAnnee(DecisionsProposees):
return formsemestre.annee_scolaire()
def annee_scolaire_str(self) -> str:
"L'année scolaire, eg '2021 - 2022'"
"L'année scolaire, eg '2021 - 2022' ou '2021' en hémisphère sud"
formsemestre = self.formsemestre_impair or self.formsemestre_pair
return formsemestre.annee_scolaire_str().replace(" ", "")

View File

@ -355,7 +355,9 @@ class ScoDocSiteConfig(models.ScoDocModel):
@classmethod
def get_month_debut_periode2(cls) -> int:
"""Mois de début de l'année scolaire."""
"""Mois de début de la seconde période (semestre) de l'année.
Par défaut, 12 (décembre). Sera souvent juillet en hémisphère sud.
"""
return cls._get_int_field("month_debut_periode2", scu.MONTH_DEBUT_PERIODE2)
@classmethod

View File

@ -699,18 +699,27 @@ class FormSemestre(models.ScoDocModel):
"""
if self.semestre_id <= 0:
return False # formations sans semestres
# août (8) en métropole, janvier (1) en hémisphère sud:
month_debut = ScoDocSiteConfig.get_month_debut_annee_scolaire()
if month_debut < 4:
# Hémisphère sud: utilise date début deuxième période
# typiquement juillet
pivot = ScoDocSiteConfig.get_month_debut_periode2()
return (
# impair commençaant en fin d'année civile
(self.semestre_id % 2 and self.date_debut.month >= pivot)
or
# pair commençant en début d'année civile
((not self.semestre_id % 2) and self.date_debut.month < pivot)
)
# Hémisphère nord
return (
# impair
(
self.semestre_id % 2
and self.date_debut.month < scu.MONTH_DEBUT_ANNEE_SCOLAIRE
)
(self.semestre_id % 2 and self.date_debut.month < month_debut)
or
# pair
(
(not self.semestre_id % 2)
and self.date_debut.month >= scu.MONTH_DEBUT_ANNEE_SCOLAIRE
)
((not self.semestre_id % 2) and self.date_debut.month >= month_debut)
)
@classmethod
@ -719,8 +728,8 @@ class FormSemestre(models.ScoDocModel):
date_debut: datetime.date,
year=False,
periode=None,
mois_pivot_annee=scu.MONTH_DEBUT_ANNEE_SCOLAIRE,
mois_pivot_periode=scu.MONTH_DEBUT_PERIODE2,
mois_pivot_annee: int | None = None,
mois_pivot_periode: int | None = None,
) -> bool:
"""Vrai si la date_debut est dans la période indiquée (1,2,0)
du semestre `periode` de l'année scolaire indiquée
@ -734,6 +743,10 @@ class FormSemestre(models.ScoDocModel):
"""
if not year:
year = scu.annee_scolaire()
if mois_pivot_annee is None:
mois_pivot_annee = ScoDocSiteConfig.get_month_debut_annee_scolaire()
if mois_pivot_periode is None:
mois_pivot_periode = ScoDocSiteConfig.get_month_debut_periode2()
# n'utilise pas le jour pivot
jour_pivot_annee = jour_pivot_periode = 1
# calcule l'année universitaire et la période
@ -758,10 +771,10 @@ class FormSemestre(models.ScoDocModel):
def comp_periode(
cls,
date_debut: datetime,
mois_pivot_annee=scu.MONTH_DEBUT_ANNEE_SCOLAIRE,
mois_pivot_periode=scu.MONTH_DEBUT_PERIODE2,
jour_pivot_annee=1,
jour_pivot_periode=1,
mois_pivot_annee: int | None = None,
mois_pivot_periode: int | None = None,
jour_pivot_annee: int = 1,
jour_pivot_periode: int = 1,
) -> tuple[int, int]:
"""Calcule la session associée à un formsemestre commençant en date_debut
sous la forme (année, période)
@ -782,6 +795,10 @@ class FormSemestre(models.ScoDocModel):
pp < pa -----------------|-------------------|---------------->
(A-1, P:1) pp (A-1, P:2) pa (A, P:1)
"""
if mois_pivot_annee is None:
mois_pivot_annee = ScoDocSiteConfig.get_month_debut_annee_scolaire()
if mois_pivot_periode is None:
mois_pivot_periode = ScoDocSiteConfig.get_month_debut_periode2()
pivot_annee = 100 * mois_pivot_annee + jour_pivot_annee
pivot_periode = 100 * mois_pivot_periode + jour_pivot_periode
pivot_sem = 100 * date_debut.month + date_debut.day
@ -930,7 +947,7 @@ class FormSemestre(models.ScoDocModel):
return scu.annee_scolaire_debut(self.date_debut.year, self.date_debut.month)
def annee_scolaire_str(self):
"2021 - 2022"
"""2021 - 2022 (ou "2021" si hémisphère sud)"""
return scu.annee_scolaire_repr(self.date_debut.year, self.date_debut.month)
def mois_debut(self) -> str:

View File

@ -778,7 +778,7 @@ class CursusMasterLMD(TypeCursus):
TYPE_CURSUS = CodesCursus.MasterLMD
NAME = "Master LMD"
NB_SEM = 4
COMPENSATION_UE = True # variabale inutilisée
COMPENSATION_UE = True # variable inutilisée
UNUSED_CODES = set((ADC, ATT, ATB))

View File

@ -1429,12 +1429,22 @@ def timedate_human_repr():
def annee_scolaire_repr(year, month):
"""representation de l'annee scolaire : '2009 - 2010'
"""Représentation de l'annee scolaire : '2009 - 2010'
à partir d'une date.
Dans l'hémisphère sud, l'année scolaire coincide avec l'année civile.
On considère que si le mois de début de l'année scolaire est au
premier trimestre (jan-fev-mar), alors l'affichage n'indique que l'année
en cours (eg "2024").
"""
if month >= MONTH_DEBUT_ANNEE_SCOLAIRE: # apres le 1er aout
from app.models.config import ScoDocSiteConfig
month_debut = ScoDocSiteConfig.get_month_debut_annee_scolaire()
if month_debut < 4:
# Hémisphère sud:
return str(year) if month >= month_debut else str(year - 1)
# Hémisphère nord
if month >= month_debut: # par ex. apres le 1er aout
return f"{year} - {year + 1}"
else:
return f"{year - 1} - {year}"
@ -1450,9 +1460,11 @@ def annee_scolaire_debut(year, month) -> int:
Par défaut (hémisphère nord), l'année du mois de août
précédent la date indiquée.
"""
if int(month) >= MONTH_DEBUT_ANNEE_SCOLAIRE:
from app.models.config import ScoDocSiteConfig
month_debut = ScoDocSiteConfig.get_month_debut_annee_scolaire()
if int(month) >= month_debut:
return int(year)
else:
return int(year) - 1
@ -1461,11 +1473,15 @@ def date_debut_annee_scolaire(annee_sco: int | None = None) -> datetime.datetime
Si annee_sco n'est pas spécifié, année courante
(par défaut, l'année scolaire en métropole commence le 1er aout)
"""
from app.models.config import ScoDocSiteConfig
if annee_sco is None:
annee_sco = annee_scolaire()
try:
return datetime.datetime(
year=annee_sco, month=MONTH_DEBUT_ANNEE_SCOLAIRE, day=1
year=annee_sco,
month=ScoDocSiteConfig.get_month_debut_annee_scolaire(),
day=1,
)
except ValueError as exc:
raise ScoValueError("année scolaire invalide") from exc
@ -1478,11 +1494,15 @@ def date_fin_annee_scolaire(annee_sco: int | None = None) -> datetime.datetime:
# on prend la date de début de l'année scolaire suivante,
# et on lui retire 1 jour.
# On s'affranchit ainsi des problèmes de durées de mois.
from app.models.config import ScoDocSiteConfig
if annee_sco is None:
annee_sco = annee_scolaire()
try:
return datetime.datetime(
year=annee_sco + 1, month=MONTH_DEBUT_ANNEE_SCOLAIRE, day=1
year=annee_sco + 1,
month=ScoDocSiteConfig.get_month_debut_annee_scolaire(),
day=1,
) - datetime.timedelta(days=1)
except (TypeError, ValueError) as exc:
raise ScoValueError("année scolaire invalide") from exc

View File

@ -3,7 +3,7 @@
"""Test Periodes
Utiliser comme:
pytest tests/unit/test_periode.py
pytest tests/unit/_test_periode.py
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
@ -32,8 +32,30 @@ import datetime
from app.models import FormSemestre
from app.scodoc.sco_formsemestre import sem_in_semestre_scolaire
# Nota: pour accélerer (éviter de recrer l'app),
# on regroupe ces petits tests dans une seule fonction
def test_default():
def test_periode(test_client):
"Joue tous les tests de ce module"
_test_default()
_test_automne_nord()
_test_noel_nord()
_test_ete_nord()
_test_printemps_sud()
_test_automne_sud()
_test_noel_sud()
_test_ete_sud()
_test_nouvel_an_sud()
_test_nouvel_an_special_pp_before_pa()
_test_nouvel_ete_pp_before_pa()
_test_automne_special_pp_before_pa()
_test_sem_in_periode1_default()
_test_sem_in_periode2_default()
_test_sem_in_annee_default()
def _test_default():
# with default
assert (2021, 2) == FormSemestre.comp_periode(datetime.datetime(2022, 1, 1))
assert (2021, 2) == FormSemestre.comp_periode(
@ -41,59 +63,59 @@ def test_default():
)
def test_automne_nord():
def _test_automne_nord():
assert (2022, 1) == FormSemestre.comp_periode(datetime.datetime(2022, 9, 1))
def test_noel_nord():
def _test_noel_nord():
assert (2022, 2) == FormSemestre.comp_periode(datetime.datetime(2022, 12, 15))
def test_ete_nord():
def _test_ete_nord():
assert (2021, 2) == FormSemestre.comp_periode(datetime.datetime(2022, 7, 30))
def test_printemps_sud():
def _test_printemps_sud():
assert (2022, 1) == FormSemestre.comp_periode(
datetime.datetime(2022, 1, 1), 1, 1, 1, 8
)
def test_automne_sud():
def _test_automne_sud():
assert (2022, 2) == FormSemestre.comp_periode(
datetime.datetime(2022, 8, 2), 1, 8, 1, 1
)
def test_noel_sud():
def _test_noel_sud():
assert (2022, 2) == FormSemestre.comp_periode(
datetime.datetime(2022, 12, 30), 1, 8, 1, 1
)
def test_ete_sud():
def _test_ete_sud():
assert (2022, 1) == FormSemestre.comp_periode(
datetime.datetime(2022, 7, 30), 1, 8, 1, 1
)
def test_nouvel_an_sud():
def _test_nouvel_an_sud():
assert (2021, 2) == FormSemestre.comp_periode(
datetime.datetime(2022, 1, 1), 3, 8, 1, 1
)
def test_nouvel_an_special_pp_before_pa():
def _test_nouvel_an_special_pp_before_pa():
assert (2023, 1) == FormSemestre.comp_periode(
datetime.datetime(2024, 1, 10), 8, 2, 1, 1
)
def test_nouvel_ete_pp_before_pa():
def _test_nouvel_ete_pp_before_pa():
assert (2023, 2) == FormSemestre.comp_periode(datetime.datetime(2024, 6, 1), 8, 2)
def test_automne_special_pp_before_pa():
def _test_automne_special_pp_before_pa():
assert (2024, 1) == FormSemestre.comp_periode(datetime.datetime(2024, 9, 20), 8, 2)
@ -105,7 +127,7 @@ sem_next_year = {"date_debut_iso": "2023-08-16"}
sem_prev_year = {"date_debut_iso": "2022-07-31"}
def test_sem_in_periode1_default():
def _test_sem_in_periode1_default():
assert True is sem_in_semestre_scolaire(sem_automne, 2022, 1)
assert False is sem_in_semestre_scolaire(sem_nouvel_an, 2022, 1)
assert False is sem_in_semestre_scolaire(sem_printemps, 2022, 1)
@ -114,7 +136,7 @@ def test_sem_in_periode1_default():
assert False is sem_in_semestre_scolaire(sem_prev_year, 2022, 1)
def test_sem_in_periode2_default():
def _test_sem_in_periode2_default():
assert False is sem_in_semestre_scolaire(sem_automne, 2022, 2)
assert True is sem_in_semestre_scolaire(sem_nouvel_an, 2022, 2)
assert True is sem_in_semestre_scolaire(sem_printemps, 2022, 2)
@ -123,7 +145,7 @@ def test_sem_in_periode2_default():
assert False is sem_in_semestre_scolaire(sem_prev_year, 2022, 1)
def test_sem_in_annee_default():
def _test_sem_in_annee_default():
assert True is sem_in_semestre_scolaire(sem_automne, 2022, 0)
assert True is sem_in_semestre_scolaire(sem_nouvel_an, 2022)
assert True is sem_in_semestre_scolaire(sem_printemps, 2022, 0)