Propose systématiquement les horaires du matin et de l'après-midi
La colonne Cible affichait un horaire seulement pour les demi-journées
avec du rattrapage à faire ; les demi-journées au rythme normal
n'affichaient rien. Désormais chaque demi-journée restante (matin et
après-midi) propose sa plage entrée → sortie, qu'il y ait du retard ou
non, pour donner un planning complet à l'utilisateur.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
@ -202,8 +202,6 @@ def compute_week(pointages: list[dict], conges: list[dict], heures_jour_min: int
|
||||
left -= give
|
||||
|
||||
for i, s in enumerate(slots):
|
||||
if adjs[i] <= 0:
|
||||
continue # rythme normal suffit pour cette demi-journée, rien à signaler
|
||||
sortie_min = s["debut"] + s["nominal"] + adjs[i]
|
||||
sortie_min = max(sortie_min, matin_fin_min if s["half"] == "matin" else aprem_fin_min)
|
||||
entree = f"{s['debut'] // 60:02d}:{s['debut'] % 60:02d}"
|
||||
|
||||
@ -128,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):
|
||||
@ -150,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):
|
||||
@ -196,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"
|
||||
|
||||
|
||||
@ -223,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é
|
||||
|
||||
|
||||
@ -245,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"
|
||||
|
||||
|
||||
@ -327,7 +335,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