diff --git a/README.md b/README.md index ef5b971..1a19232 100644 --- a/README.md +++ b/README.md @@ -194,9 +194,10 @@ jour, pleine largeur : un menu dépliant fermé par défaut (seuls l'heure de re et le total restent visibles). Déplié, il offre autant de lignes que nécessaire (**+ intervention**) sur trois colonnes : **début**, **fin** et description libre. Une fin antérieure au début (fin < début) désigne une intervention à -cheval sur minuit. Une durée forfaitaire peut être ajoutée au temps travaillé de -chaque jour d'astreinte déclaré (page **Réglages**, « Forfait par jour -d'astreinte »). +cheval sur minuit. Une durée forfaitaire peut être attribuée à chaque jour +d'astreinte déclaré (page **Réglages**, « Forfait par jour d'astreinte ») : +elle ne compte jamais dans les heures travaillées, elle est suivie à part dans +le récapitulatif d'astreinte. La semaine affiche aussi **samedi et dimanche** (heures dues nulles, lignes grisées) : on peut y déclarer des astreintes, y saisir les interventions et les diff --git a/app/calcul.py b/app/calcul.py index ec8bff8..879b313 100644 --- a/app/calcul.py +++ b/app/calcul.py @@ -458,7 +458,9 @@ def compute_week(pointages: list[dict], conges: list[dict], heures_jour_min: int if jour_astreinte_qualifie(p["date"], astreintes) and events else None) matin_ex, aprem_ex = exclusion_retour(conges_date, retour_min, plages, jour_ferie) forfait = forfait_as_min if p["date"] in astreintes else 0 - travaille = heures_travaillees(p, retour_min) + forfait + # Le forfait d'astreinte ne compte jamais dans les heures travaillées : + # il est suivi à part dans le récapitulatif d'astreinte. + travaille = heures_travaillees(p, retour_min) du = heures_dues(p["date"], conges, heures_jour_min, plages, retour_min, jour_ferie) du_full = du + matin_ex + aprem_ex matin_nom, aprem_nom = nominaux_du_jour(conges_date, du_full, matin_ex, aprem_ex, jour_ferie) diff --git a/app/main.py b/app/main.py index 8b97b03..cfd229f 100644 --- a/app/main.py +++ b/app/main.py @@ -335,7 +335,7 @@ def _build_jour_ctx(date, conges, h_jour, user_id): matin_ex, aprem_ex = exclusion_retour(conges_date, retour_min, plages, jour_ferie) forfait = (hhmm_to_minutes(plages["astreinte_forfait"]) if plages.get("astreinte_forfait") else 0) \ if date in astreintes else 0 - trav = heures_travaillees(p, retour_min) + forfait + trav = heures_travaillees(p, retour_min) # forfait d'astreinte : hors heures travaillées du = heures_dues(date, conges, h_jour, plages, retour_min, jour_ferie) du_full = du + matin_ex + aprem_ex matin_nom, aprem_nom = nominaux_du_jour(conges_date, du_full, matin_ex, aprem_ex, jour_ferie) @@ -492,8 +492,8 @@ def _as_block_html(date, jour): hint = (f'' f'retour ≥ {_e(jour["retour"])}') if jour.get("forfait_min"): - hint += (f'' - f'forfait + {_e(jour["forfait_h"])}') + hint += (f'' + f'forfait {_e(jour["forfait_h"])}') total = "" if jour.get("astreinte_min"): total = (f'' @@ -1125,8 +1125,9 @@ def settings_plages_save( @app.post("/settings/astreinte-forfait", response_class=HTMLResponse) def settings_astreinte_forfait(request: Request, astreinte_forfait: str = Form("")): - """Durée forfaitaire ajoutée au temps travaillé de chaque jour d'astreinte - déclaré (réglage par utilisateur, stocké avec ses plages).""" + """Durée forfaitaire attribuée à chaque jour d'astreinte déclaré (réglage par + utilisateur, stocké avec ses plages) : suivie dans le récapitulatif + d'astreinte, jamais comptée dans les heures travaillées.""" user_id = _get_user(request) if not user_id: return RedirectResponse("/login", status_code=302) diff --git a/app/templates/_ligne.html b/app/templates/_ligne.html index 0dbc0ec..1a6943f 100644 --- a/app/templates/_ligne.html +++ b/app/templates/_ligne.html @@ -131,7 +131,7 @@ ▸ {{ nb_as }} intervention{{ 's' if nb_as != 1 else '' }} {% if j.retour_min is not none %}retour ≥ {{ j.retour }}{% endif %} - {% if j.forfait_min %}forfait + {{ j.forfait_h }}{% endif %} + {% if j.forfait_min %}forfait {{ j.forfait_h }}{% endif %} {% if j.astreinte_min %}astreinte : {{ j.astreinte_h }}{% endif %}
diff --git a/app/templates/_soldes.html b/app/templates/_soldes.html index 30221b0..e088053 100644 --- a/app/templates/_soldes.html +++ b/app/templates/_soldes.html @@ -56,7 +56,7 @@
{{ j.jour }} {{ j.date[8:] }}/{{ j.date[5:7] }} - {% if j.forfait_min %}forfait + {{ j.forfait_h }}{% endif %} + {% if j.forfait_min %}forfait {{ j.forfait_h }}{% endif %} {% if j.total_min %}astreinte {{ j.total_h }} → {{ j.total_pondere_h }} pondérées{% endif %}
{% for ev in j.events %} @@ -76,7 +76,7 @@ {% endfor %}
{% for c in result.astreinte.categories %}{{ c.nom }} : {{ c.min_h }} ×{{ c.facteur_txt }} = {{ c.pondere_h }}{% endfor %} - {% if result.astreinte.total_forfait_min %}forfaits + {{ result.astreinte.total_forfait_h }} (dans le travaillé){% endif %} + {% if result.astreinte.total_forfait_min %}forfaits {{ result.astreinte.total_forfait_h }} (hors heures travaillées){% endif %} total {{ result.astreinte.total_h }} → {{ result.astreinte.total_pondere_h }} pondérées
diff --git a/app/templates/settings.html b/app/templates/settings.html index b8ee8f3..5300360 100644 --- a/app/templates/settings.html +++ b/app/templates/settings.html @@ -125,9 +125,10 @@ function asDelRatio(btn) { btn.closest('.as-ratio-edit').remove(); }
Forfait par jour d'astreinte

- Durée ajoutée automatiquement au temps travaillé de chaque jour d'astreinte - déclaré (bouton AS), en plus des interventions saisies. Elle compte dans - le bilan de la semaine ; le lendemain de l'astreinte n'est pas concerné. + Durée forfaitaire attribuée à chaque jour d'astreinte déclaré (bouton AS), + en plus des interventions saisies. Elle ne compte jamais dans les heures + travaillées : elle est suivie à part dans le récapitulatif d'astreinte de la + semaine ; le lendemain de l'astreinte n'est pas concerné. Vide = pas de forfait.

diff --git a/app/tests/test_astreinte.py b/app/tests/test_astreinte.py index 097a6f6..10aaa3a 100644 --- a/app/tests/test_astreinte.py +++ b/app/tests/test_astreinte.py @@ -555,9 +555,10 @@ def test_compute_week_astreinte_samedi_dimanche(freeze_today): # ── Forfait par jour d'astreinte déclaré ─────────────────────────────────────── -def test_compute_week_forfait_ajoute_au_travaille_du_jour_declare(freeze_today): - """Forfait 1h00 réglé : ajouté au travaillé du jour AS déclaré uniquement - (pas du lendemain), sans toucher aux heures dues.""" +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.""" plages = {**PLAGES, "astreinte_forfait": "01:00"} pointages = [ _pointage("2026-07-13", "09:00", "12:24", "13:30", "17:54"), @@ -567,10 +568,10 @@ def test_compute_week_forfait_ajoute_au_travaille_du_jour_declare(freeze_today): result = compute_week(pointages, [], HEURES_JOUR_MIN, plages, ["2026-07-14"]) mardi = result["jours"][1] assert mardi["forfait_min"] == 60 - assert mardi["travaille_min"] == HEURES_JOUR_MIN + 60 + assert mardi["travaille_min"] == HEURES_JOUR_MIN # pointé seul, forfait exclu assert result["jours"][2]["forfait_min"] == 0 # lendemain : rien assert result["jours"][0]["forfait_min"] == 0 # jour sans astreinte - assert result["total_travaille"] == "16h36" # 2 × 7h48 + 1h + 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 ast = result["astreinte"]