Retour décalé après astreinte : la présence obligatoire couverte compte comme effectuée
Quand le repos de 11h décale le retour au bureau (ex. 11:00), les heures de
présence obligatoire couvertes (ex. 09:00→11:00) sont créditées à la colonne
Travaillé au lieu d'être retirées des heures dues, qui restent complètes.
Le solde est inchangé, mais le calcul est explicite : badge « +2h00 repos »
sous le total (plages couvertes au survol) et rappel dans le bloc astreinte.
Rien n'est crédité sans heures dues (week-end, férié, congé), et le crédit
ne dépasse pas le nominal du jour.
Corrige aussi la perte des interventions postées sans description (le zip
s'arrêtait sur la liste vide des descriptions).
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
This commit is contained in:
27
app/main.py
27
app/main.py
@ -33,7 +33,7 @@ from models import (
|
||||
)
|
||||
from calcul import (
|
||||
compute_week, minutes_to_hhmm, minutes_to_time, hhmm_to_minutes, heures_dues,
|
||||
heures_travaillees, jour_astreinte_qualifie, exclusion_retour,
|
||||
heures_travaillees, jour_astreinte_qualifie, exclusion_retour, couvert_detail,
|
||||
nominaux_du_jour, retour_apres_repos, decompte_astreinte, fenetre_astreinte_jour,
|
||||
)
|
||||
from stats import compute_all_stats
|
||||
@ -351,9 +351,14 @@ 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 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
|
||||
# Les heures de présence obligatoire couvertes par le repos de 11h sont
|
||||
# comptées comme effectuées : créditées au travaillé, dues complètes (le
|
||||
# forfait d'astreinte, lui, reste hors heures travaillées). Sans heures
|
||||
# dues (week-end, férié, congé), rien à créditer.
|
||||
du_full = heures_dues(date, conges, h_jour, plages, None, jour_ferie)
|
||||
couvert = min(matin_ex + aprem_ex, du_full)
|
||||
trav = heures_travaillees(p, retour_min) + couvert
|
||||
du = du_full
|
||||
matin_nom, aprem_nom = nominaux_du_jour(conges_date, du_full, matin_ex, aprem_ex, jour_ferie)
|
||||
delta = trav - du
|
||||
# Décompte astreinte du jour (compteur séparé, hors heures de semaine) :
|
||||
@ -373,6 +378,9 @@ def _build_jour_ctx(date, conges, h_jour, user_id):
|
||||
"forfait_h": minutes_to_hhmm(forfait) if forfait else "",
|
||||
"du_full_min": du_full,
|
||||
"matin_excl_min": matin_ex, "aprem_excl_min": aprem_ex,
|
||||
"couvert_min": couvert,
|
||||
"couvert_h": minutes_to_hhmm(couvert) if couvert else "",
|
||||
"couvert_detail": couvert_detail(plages, retour_min, matin_ex, aprem_ex) if couvert else "",
|
||||
"matin_nominal_min": matin_nom, "aprem_nominal_min": aprem_nom,
|
||||
"astreinte": date in astreintes,
|
||||
"astreinte_qualifiee": jour_astreinte_qualifie(date, astreintes),
|
||||
@ -385,6 +393,9 @@ def _build_jour_ctx(date, conges, h_jour, user_id):
|
||||
|
||||
def _oob_calc(date, jour):
|
||||
trav_inner = f'<span class="calc-num">{"—" if not jour["travaille_min"] else _e(jour["travaille"])}</span>'
|
||||
if jour.get("couvert_min"):
|
||||
trav_inner += (f'<span class="calc-couvert" title="Présence obligatoire couverte par le repos de 11h '
|
||||
f'({_e(jour["couvert_detail"])}) : comptée comme effectuée">+{_e(jour["couvert_h"])} repos</span>')
|
||||
if jour["travaille_min"]:
|
||||
cls = "delta-pos" if jour["delta_min"] > 0 else ("delta-neg" if jour["delta_min"] < 0 else "delta-zero")
|
||||
sign = "+" if jour["delta_min"] > 0 else ""
|
||||
@ -539,6 +550,9 @@ def _as_block_html(date, jour):
|
||||
if jour.get("retour_min") is not None:
|
||||
hint = (f'<span class="as-hint" title="11h de repos consécutif après la dernière activité (durée arrondie au quart d\'heure supérieur), retour arrondi au quart d\'horloge supérieur : :00, :15, :30 ou :45">'
|
||||
f'retour ≥ {_e(jour["retour"])}</span>')
|
||||
if jour.get("couvert_min"):
|
||||
hint += (f'<span class="as-hint" title="Présence obligatoire couverte par le repos ({_e(jour["couvert_detail"])}) : comptée comme effectuées dans la colonne Travaillé">'
|
||||
f'+{_e(jour["couvert_h"])} de présence comptées</span>')
|
||||
if jour.get("forfait_min"):
|
||||
hint += (f'<span class="as-hint" title="Forfait du jour AS déclaré (réglé dans Réglages) : suivi dans le récapitulatif d'astreinte, hors heures travaillées">'
|
||||
f'forfait {_e(jour["forfait_h"])}</span>')
|
||||
@ -843,9 +857,12 @@ def save_pointage(
|
||||
# au lieu de les écraser à vide. Les paires début/fin invalides sont ignorées.
|
||||
if jour_astreinte_qualifie(date, set(load_astreintes_effectives(user_id))):
|
||||
events = []
|
||||
for deb, fin, desc in zip(astreinte_debut, astreinte_fin, astreinte_desc):
|
||||
# Les descriptions sont optionnelles : sans elles (POST programmatique),
|
||||
# zip s'arrêterait à la liste la plus courte et perdrait les événements.
|
||||
for i, (deb, fin) in enumerate(zip(astreinte_debut, astreinte_fin)):
|
||||
deb, fin = clean(deb), clean(fin)
|
||||
if deb and fin:
|
||||
desc = astreinte_desc[i] if i < len(astreinte_desc) else ""
|
||||
events.append({"debut": deb, "fin": fin,
|
||||
"desc": (desc or "").strip()[:200] or None})
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user