Merge remote-tracking branch 'origin/main'
# Conflicts: # app/calcul.py
This commit is contained in:
@ -113,6 +113,8 @@ def test_compute_week_cible_repartie_sur_seule_demi_journee_restante(freeze_toda
|
||||
|
||||
assert vendredi["cible_matin"] is None # matin déjà pointé (entrée+sortie), plus rien à y faire
|
||||
assert vendredi["cible_aprem"] == "18:18"
|
||||
# La préconisation aprem inclut aussi l'heure d'arrivée (reprise par défaut 13:30)
|
||||
assert vendredi["cible_aprem_entree"] == "13:30"
|
||||
|
||||
|
||||
def test_compute_week_semaine_totalement_vide_compte_les_10_demi_journees(freeze_today):
|
||||
@ -126,10 +128,11 @@ def test_compute_week_semaine_totalement_vide_compte_les_10_demi_journees(freeze
|
||||
result = compute_week(pointages, [], HEURES_JOUR_MIN)
|
||||
assert result["slots_restants"] == 10
|
||||
assert result["reste_min"] == HEURES_JOUR_MIN * 5
|
||||
# Rien n'est encore en retard puisque rien n'a encore été renseigné : le rythme
|
||||
# normal (à répartir librement sur les 10 demi-journées) suffit, pas de cible imposée.
|
||||
# Pas de retard (rien n'a encore été renseigné) : le rythme normal suffit, extra = 0.
|
||||
# Mais chaque demi-journée reste propose son horaire visé (matin 09:00→12:00,
|
||||
# aprem 13:30→18:18 avec le surplus nominal basculé depuis le matin saturé).
|
||||
assert result["extra_min"] == 0
|
||||
assert all(j["cible_matin"] is None and j["cible_aprem"] is None for j in result["jours"])
|
||||
assert all(j["cible_matin"] == "12:00" and j["cible_aprem"] == "18:18" for j in result["jours"])
|
||||
|
||||
|
||||
def test_compute_week_jour_futur_non_entame_recoit_une_cible_repartie(freeze_today):
|
||||
@ -148,30 +151,34 @@ def test_compute_week_jour_futur_non_entame_recoit_une_cible_repartie(freeze_tod
|
||||
assert lundi_suivant["cible_matin"] is not None or lundi_suivant["cible_aprem"] is not None
|
||||
|
||||
|
||||
def test_compute_week_jour_futur_a_egalite_pas_de_cible(freeze_today):
|
||||
"""Quand le rythme normal des demi-journées restantes suffit déjà, aucune cible n'est affichée."""
|
||||
def test_compute_week_jour_futur_a_egalite_propose_le_rythme_normal(freeze_today):
|
||||
"""Quand le rythme normal des demi-journées restantes suffit (pas de rattrapage),
|
||||
les horaires visés du matin et de l'après-midi sont quand même proposés."""
|
||||
dates_completes = ["2026-07-13", "2026-07-14", "2026-07-15", "2026-07-16", "2026-07-17"]
|
||||
pointages = _semaine_complete(dates_completes)
|
||||
pointages.append(_pointage("2026-07-20")) # lundi suivant, rien pointé — mais la semaine est déjà à l'équilibre
|
||||
|
||||
result = compute_week(pointages, [], HEURES_JOUR_MIN)
|
||||
lundi_suivant = result["jours"][5]
|
||||
assert lundi_suivant["cible_matin"] is None
|
||||
assert lundi_suivant["cible_aprem"] is None
|
||||
assert result["extra_min"] == 0
|
||||
assert lundi_suivant["cible_matin"] == "12:00"
|
||||
assert lundi_suivant["cible_aprem"] == "18:18"
|
||||
|
||||
|
||||
def test_compute_week_jour_courant_non_entame_rythme_normal_suffit(freeze_today):
|
||||
def test_compute_week_jour_courant_non_entame_propose_le_rythme_normal(freeze_today):
|
||||
""""Aujourd'hui" sans rien pointé n'est pas traité comme un jour futur figé : ses deux
|
||||
demi-journées entrent dans la répartition. Ici le manque (468 min) correspond exactement
|
||||
au nominal des deux demi-journées restantes : le rythme normal suffit, pas de cible."""
|
||||
au nominal des deux demi-journées restantes : le rythme normal suffit, mais les horaires
|
||||
visés matin et aprem restent proposés."""
|
||||
dates_completes = ["2026-07-13", "2026-07-14", "2026-07-15", "2026-07-16"]
|
||||
pointages = _semaine_complete(dates_completes)
|
||||
pointages.append(_pointage("2026-07-17"))
|
||||
|
||||
result = compute_week(pointages, [], HEURES_JOUR_MIN)
|
||||
vendredi = result["jours"][4]
|
||||
assert vendredi["cible_matin"] is None
|
||||
assert vendredi["cible_aprem"] is None
|
||||
assert result["extra_min"] == 0
|
||||
assert vendredi["cible_matin"] == "12:00"
|
||||
assert vendredi["cible_aprem"] == "18:18"
|
||||
|
||||
|
||||
def test_compute_week_demi_journee_en_cours_pas_de_double_comptage(freeze_today):
|
||||
@ -194,8 +201,9 @@ def test_compute_week_demi_journee_en_cours_pas_de_double_comptage(freeze_today)
|
||||
result = compute_week(pointages, [], HEURES_JOUR_MIN)
|
||||
vendredi = result["jours"][4]
|
||||
assert result["extra_min"] == 60
|
||||
# matin saturé au nominal (09:00→12:00), pas de cible ; aprem : 13:30 + 288 + 60 = 19:18
|
||||
assert vendredi["cible_matin"] is None
|
||||
# matin en cours : sa cible correspond au planning nominal (09:00→12:00), pas de rattrapage
|
||||
# possible (saturé au plafond pause) ; aprem : 13:30 + 288 + 60 = 19:18
|
||||
assert vendredi["cible_matin"] == "12:00"
|
||||
assert vendredi["cible_aprem"] == "19:18"
|
||||
|
||||
|
||||
@ -221,7 +229,9 @@ def test_compute_week_cible_matin_ne_mange_jamais_la_pause_de_midi(freeze_today)
|
||||
# 120 min de retard + 54 min de nominal matin qui ne tiennent pas avant la pause
|
||||
# (et ne peuvent pas basculer sur l'après-midi, en congé)
|
||||
assert result["extra_min"] == 174
|
||||
assert vendredi["cible_matin"] is None
|
||||
# Le matin (seul créneau dispo, aprem en congé) est saturé à son plafond 09:00→12:00 :
|
||||
# cible proposée au rythme normal, mais le rattrapage (174 min) ne tient pas.
|
||||
assert vendredi["cible_matin"] == "12:00"
|
||||
assert vendredi["cible_aprem"] is None # congé
|
||||
|
||||
|
||||
@ -243,8 +253,8 @@ def test_compute_week_surplus_creneau_sature_reporte_sur_les_autres(freeze_today
|
||||
result = compute_week(pointages, [], HEURES_JOUR_MIN)
|
||||
vendredi = result["jours"][4]
|
||||
assert result["extra_min"] == 80
|
||||
# matin saturé au nominal, pas de cible ; aprem : 13:30 + 288 + 80 = 19:38
|
||||
assert vendredi["cible_matin"] is None
|
||||
# matin saturé au nominal (cible au rythme normal 09:00→12:00) ; aprem : 13:30 + 288 + 80 = 19:38
|
||||
assert vendredi["cible_matin"] == "12:00"
|
||||
assert vendredi["cible_aprem"] == "19:38"
|
||||
|
||||
|
||||
@ -273,7 +283,7 @@ def test_compute_week_avance_reduit_les_departs_du_soir_restants(freeze_today):
|
||||
result = compute_week(pointages, [], heures_jour, plages)
|
||||
assert result["extra_min"] == 0 # extra_min ne compte que le retard, pas l'avance
|
||||
for jour in result["jours"][1:]:
|
||||
assert jour["cible_matin"] is None
|
||||
assert jour["cible_matin"] == "13:00" # rythme normal, jamais ajusté par l'avance
|
||||
assert jour["cible_aprem"] == "17:55"
|
||||
|
||||
|
||||
@ -301,6 +311,7 @@ def test_compute_week_avance_ne_descend_jamais_sous_aprem_fin(freeze_today):
|
||||
def test_compute_week_cible_matin_jamais_ajustee_meme_avec_de_la_marge(freeze_today):
|
||||
"""Le rattrapage hebdomadaire ne porte jamais sur le matin, même quand la
|
||||
matinée obligatoire est plus longue que le nominal et aurait de la marge.
|
||||
Le matin garde son horaire nominal (rythme normal), non ajusté.
|
||||
|
||||
Matin 08:00→13:00 (capacité 300 > nominal 270). Vendredi en congé après-midi,
|
||||
120 min de retard : le seul créneau ouvert (le matin) n'est pas ajustable, le
|
||||
@ -323,14 +334,14 @@ def test_compute_week_cible_matin_jamais_ajustee_meme_avec_de_la_marge(freeze_to
|
||||
result = compute_week(pointages, conges, heures_jour, plages)
|
||||
vendredi = result["jours"][4]
|
||||
assert result["extra_min"] == 120
|
||||
assert vendredi["cible_matin"] is None
|
||||
assert vendredi["cible_matin"] == "12:30" # rythme normal (08:00 + 270 nominal), pas de rattrapage
|
||||
assert vendredi["cible_aprem"] is None # congé
|
||||
|
||||
|
||||
def test_compute_week_arrivee_visee_n_etend_pas_le_rattrapage_au_matin(freeze_today):
|
||||
"""L'arrivée visée sert de début projeté du matin (pour le calcul du surplus
|
||||
basculant vers l'après-midi), mais n'ouvre jamais le matin au rattrapage
|
||||
hebdomadaire — celui-ci reste réservé aux départs du soir.
|
||||
"""L'arrivée visée sert de début projeté du matin (pour le rythme normal affiché
|
||||
et le calcul du surplus basculant vers l'après-midi), mais n'ouvre jamais le
|
||||
matin au rattrapage hebdomadaire — celui-ci reste réservé aux départs du soir.
|
||||
"""
|
||||
plages = {"arrivee_visee": "08:00"}
|
||||
conges = [{"date": "2026-07-17", "type": "aprem"}]
|
||||
@ -344,7 +355,7 @@ def test_compute_week_arrivee_visee_n_etend_pas_le_rattrapage_au_matin(freeze_to
|
||||
result = compute_week(pointages, conges, HEURES_JOUR_MIN, plages)
|
||||
vendredi = result["jours"][4]
|
||||
assert result["extra_min"] == 120
|
||||
assert vendredi["cible_matin"] is None
|
||||
assert vendredi["cible_matin"] == "11:54" # rythme normal (08:00 + 234 nominal), pas de rattrapage
|
||||
|
||||
|
||||
def test_compute_week_depart_vise_plafond_souple(freeze_today):
|
||||
@ -372,7 +383,7 @@ def test_compute_week_depart_vise_plafond_souple(freeze_today):
|
||||
# vendredi aprem : 13:30 + 234 + (36 + 9) = 18:09 ; lundi aprem : 13:30 + 288 + 9 = 18:27
|
||||
# (sans départ visé, lundi finirait à 18:45)
|
||||
assert vendredi["cible_aprem"] == "18:09"
|
||||
assert lundi["cible_matin"] is None
|
||||
assert lundi["cible_matin"] == "12:00" # matin au rythme normal (pas de rattrapage pour ce créneau)
|
||||
assert lundi["cible_aprem"] == "18:27"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user