Ajoute les astreintes : saisie de la fin de dernière activité, retour au bureau décalé de 11h de repos

Un nouveau bouton AS marque un jour d'astreinte. Ce jour et son lendemain,
une saisie « Fin activité » enregistre l'heure de fin de la dernière
intervention hors horaires (elle peut être le matin si la nuit a dépassé
minuit). L'app en déduit l'heure de retour au bureau (fin + 11h de repos
consécutif) et retire du décompte de la semaine toute la présence avant
cette heure : heures dues réduites, présence pointée avant le retour non
comptée, préconisations Fin cible démarrées à l'heure de retour sans
avertissement de retard, demi-journée entièrement en repos considérée
comme remplie. Les exports .ods gagnent les colonnes Astreinte et Retour,
et les stats n'ont plus les retards liés au repos.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
This commit is contained in:
Jacquin Antoine
2026-09-08 22:05:10 +02:00
parent c31fcd28ec
commit 065d73e15c
9 changed files with 665 additions and 58 deletions

View File

@ -1,11 +1,15 @@
{% set matin_cg = 'matin' in j.conge or 'jour' in j.conge %}
{% set aprem_cg = 'aprem' in j.conge or 'jour' in j.conge %}
{% set matin_warn = not matin_cg and j.du_min > 0 and (
(j.matin_entree and j.matin_entree > plages.matin_debut) or
{% set matin_requis = not matin_cg and j.du_min > 0 and j.matin_nominal_min > 0 %}
{% set aprem_requis = not aprem_cg and j.du_min > 0 and j.aprem_nominal_min > 0 %}
{% set borne_matin = [plages.matin_debut, j.retour or plages.matin_debut] | max %}
{% set borne_aprem = [plages.aprem_debut, j.retour or plages.aprem_debut] | max %}
{% set matin_warn = matin_requis and (
(j.matin_entree and j.matin_entree > borne_matin) or
(j.matin_sortie and j.matin_sortie < plages.matin_fin)
) %}
{% set aprem_warn = not aprem_cg and j.du_min > 0 and (
(j.aprem_entree and j.aprem_entree > plages.aprem_debut) or
{% set aprem_warn = aprem_requis and (
(j.aprem_entree and j.aprem_entree > borne_aprem) or
(j.aprem_sortie and j.aprem_sortie < plages.aprem_fin)
) %}
<tr id="row-{{ j.date }}">
@ -37,6 +41,17 @@
data-date="{{ j.date }}" value="{{ j.aprem_sortie or '' }}">
</div>
</div>
{% if j.astreinte_qualifiee %}
<div id="as-block-{{ j.date }}" class="as-block" data-label="Astreinte">
<span class="as-label">Fin activité</span>
<input class="time-input" type="time" name="astreinte_fin"
data-date="{{ j.date }}" value="{{ j.astreinte_fin or '' }}"
title="Heure de fin de la dernière activité (peut être le matin) — 11h de repos ensuite">
{% if j.retour_min is not none %}<span class="as-hint" title="11h de repos consécutif après la dernière activité">retour ≥ {{ j.retour }}</span>{% endif %}
</div>
{% else %}
<div id="as-block-{{ j.date }}"></div>
{% endif %}
</td>
<td class="col-calc" data-label="Travaillé">
@ -102,6 +117,10 @@
hx-swap="none"
class="btn-cg btn-jour {% if 'jour' in j.conge %}jour-on{% endif %}"
title="Journée entière">J</button>
<button hx-post="/astreinte/{{ j.date }}/toggle"
hx-swap="none"
class="btn-cg btn-as {% if j.astreinte %}as-on{% endif %}"
title="Jour d'astreinte">AS</button>
</div>
</div>
</td>

View File

@ -428,6 +428,33 @@
.btn-cg.on { background: var(--conge-bg); border-color: var(--conge-bd); color: var(--conge-txt); }
.btn-cg.btn-jour { border-radius: 50%; width: 22px; height: 22px; font-size: 9px; }
.btn-cg.jour-on { background: var(--accent-2); border-color: #955505; color: #fff; }
.btn-cg.btn-as { border-radius: 4px; }
.btn-cg.as-on { background: var(--accent); border-color: var(--accent); color: #fff; }
/* Astreinte : opération hors horaires + heure de retour après 11h de repos */
.as-block {
display: flex;
align-items: center;
gap: 5px;
flex-wrap: wrap;
padding: .3rem .65rem .45rem;
border-top: 1px dashed var(--rule);
}
.as-label {
font-family: var(--mono);
font-size: 9px;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--accent-2);
white-space: nowrap;
}
.as-block .time-input { width: 68px; }
.as-hint {
font-family: var(--mono);
font-size: 10px;
color: var(--accent);
white-space: nowrap;
}
/* ── Tableau hebdo en cartes empilées sous 700px (évite le scroll horizontal) ── */
@media (max-width: 700px) {
@ -490,6 +517,8 @@
.pointage-table .btn-valider { width: 40px; height: 40px; font-size: 16px; }
.pointage-table .btn-cg { width: 34px; height: 34px; font-size: 11px; }
.pointage-table .btn-cg.btn-jour { width: 32px; height: 32px; }
.as-block { padding: .4rem .75rem .55rem; }
.as-block .time-input { width: 92px; }
}
/* ── Historique ── */