Forfait d'astreinte : bonifié comme réalisé en journée du jour AS

Le forfait était suivi brut, sans bonification. Considéré réalisé en
journée du jour où il est attribué, il reçoit désormais le facteur
journée correspondant : ×1 en semaine, ×1,5 le samedi, ×2 le dimanche
ou un jour férié (suit les règles de ratios configurées). Toujours hors
heures travaillées ; affiché pondéré sur la ligne du jour, dans les
totaux du récapitulatif et expliqué dans Réglages.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
This commit is contained in:
Jacquin Antoine
2026-09-10 17:05:05 +02:00
parent f50d1ef7fc
commit d760842121
7 changed files with 125 additions and 16 deletions

View File

@ -2,7 +2,8 @@
from calcul import (
compute_week, decompte_astreinte, heures_dues, heures_travaillees, hhmm_to_minutes,
jour_astreinte_qualifie, exclusion_retour, nominaux_du_jour, fenetre_astreinte_jour,
retour_apres_repos, DEFAULT_PLAGES, PAS_ASTREINTE_MIN, ASTREINTE_DEBUT_MIN,
retour_apres_repos, regle_journee_astreinte, DEFAULT_PLAGES, PAS_ASTREINTE_MIN,
ASTREINTE_DEBUT_MIN,
)
import models
@ -620,7 +621,8 @@ def test_compute_week_astreinte_samedi_dimanche(freeze_today):
def test_compute_week_forfait_hors_heures_travaillees(freeze_today):
"""Forfait 1h00 réglé : attribué au jour AS déclaré uniquement (pas du
lendemain), mais jamais compté dans les heures travaillées — seulement
suivi dans le récapitulatif d'astreinte."""
suivi dans le récapitulatif d'astreinte, pondéré par la bonification
journée du jour (2026-07-14 est férié : ×2)."""
plages = {**PLAGES, "astreinte_forfait": "01:00"}
pointages = [
_pointage("2026-07-13", "09:00", "12:24", "13:30", "17:54"),
@ -635,13 +637,49 @@ def test_compute_week_forfait_hors_heures_travaillees(freeze_today):
assert result["jours"][0]["forfait_min"] == 0 # jour sans astreinte
assert result["total_travaille"] == "15h36" # 2 × 7h48, forfait exclu
# récapitulatif d'astreinte : le jour AS apparaît avec son forfait même sans
# intervention ; le forfait est rappelé mais hors compteurs pondérés
# intervention ; le forfait est bonifié « journée » du jour (férié → ×2)
ast = result["astreinte"]
assert ast["actif"] is True
assert ast["total_min"] == 0
assert ast["total_forfait_min"] == 60
assert ast["total_forfait_h"] == "1h00"
assert [(j["date"], j["forfait_min"], j["events"]) for j in ast["jours"]] == [("2026-07-14", 60, [])]
assert ast["total_forfait_pondere_min"] == 120
assert ast["total_forfait_pondere_h"] == "2h00"
[(jour_as)] = ast["jours"]
assert (jour_as["date"], jour_as["forfait_min"], jour_as["events"]) == ("2026-07-14", 60, [])
assert (jour_as["forfait_pondere_min"], jour_as["forfait_regle"], jour_as["forfait_facteur_txt"]) == (120, "Dimanche / férié", "2")
def test_forfait_bonifie_selon_la_journee_du_jour(freeze_today):
"""Le forfait est considéré réalisé en journée : il bénéficie de la
bonification « journée » du jour où il est attribué — ×1 en semaine, ×1,5
le samedi, ×2 le dimanche ou un férié (règles par défaut)."""
plages = {**PLAGES, "astreinte_forfait": "01:00"}
pointages = [_pointage(d) for d in
["2026-07-13", "2026-07-14", "2026-07-15", "2026-07-16", "2026-07-17",
"2026-07-18", "2026-07-19"]]
result = compute_week(pointages, [], HEURES_JOUR_MIN, plages,
["2026-07-15", "2026-07-18", "2026-07-19"])
ast = result["astreinte"]
details = {j["date"]: (j["forfait_min"], j["forfait_pondere_min"], j["forfait_regle"])
for j in ast["jours"]}
assert details["2026-07-15"] == (60, 60, "Journée") # mercredi : ×1
assert details["2026-07-18"] == (60, 90, "Samedi") # samedi : ×1,5
assert details["2026-07-19"] == (60, 120, "Dimanche / férié") # dimanche : ×2
assert ast["total_forfait_min"] == 180
assert ast["total_forfait_pondere_min"] == 270
assert ast["total_forfait_pondere_h"] == "4h30"
def test_regle_journee_astreinte_suit_les_regles_configurees():
"""La bonification journée du forfait suit les règles configurées : première
règle couvrant midi pour le type du jour."""
regles = [{"nom": "Journée spéciale", "jours": ["semaine"], "debut": "06:00", "fin": "22:00", "facteur": 1.25}]
r = regle_journee_astreinte("2026-07-15", regles)
assert r is not None
assert (r["nom"], r["facteur"], r["facteur_txt"]) == ("Journée spéciale", 1.25, "1,25")
# Aucune règle ne couvre midi ce jour-là : pas de bonification
assert regle_journee_astreinte("2026-07-15", [{"nom": "Nuit", "jours": ["semaine"], "debut": "22:00", "fin": "06:00", "facteur": 1.5}]) is None
def test_compute_week_sans_forfait_comportement_inchange(freeze_today):