fab497acdcd8a6e264497a38f19f645230308664
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fab497acdc |
Détailler les pauses d'un créneau, et prévenir le salarié
Un créneau portait un total de pause. Deux pauses de vingt minutes et une coupure de deux heures s'écrivaient toutes deux « 120 », et rien ne permettait de les distinguer — ni à l'écran, ni au contrôle. Or elles ne se planifient pas de la même façon : la première satisfait la pause minimale au-delà de six heures, la seconde interroge l'amplitude de la journée. Chaque pause a désormais sa ligne : durée, début facultatif, libellé, et si elle est rémunérée. Le début reste facultatif à dessein — beaucoup de pauses se prennent « quand c'est calme », et imposer une heure inventerait une précision que le planning n'a pas et qu'un contrôle prendrait pour un engagement. Le créneau garde deux totaux dérivés, et la distinction porte de l'argent. `breakMinutes` reste ce qu'il était, la part non rémunérée déduite du temps de travail : la paie, les compteurs et l'export continuent de le lire sans changer d'un caractère. `paidBreakMinutes` s'ajoute à côté, et la règle de pause minimale regarde la somme des deux — sans quoi un créneau dont la pause de vingt minutes est payée passerait pour un créneau sans pause, et l'employeur le plus généreux serait le seul à recevoir une alerte. La migration reprend les créneaux existants : leur total devient une pause unique, non rémunérée. Laisser la table vide aurait fait disparaître de l'écran des pauses qui comptent pourtant toujours dans les heures payées. En modification, les pauses sont remplacées et non fusionnées : le formulaire porte l'état voulu au complet, et rapprocher ligne à ligne ferait survivre une pause qu'on vient de retirer. L'avis d'affectation part enfin, sous sa propre nature d'envoi. Il est différé à la fin de la transaction : un refus sur le dernier jour d'une répétition annule les autres, et personne ne doit être prévenu d'un créneau qui n'existe pas. La case est décochée par défaut, à l'inverse du produit audité — c'est la publication de la semaine qui prévient, et cette case sert au créneau ajouté après coup, le cas où le salarié ne verrait rien sans elle. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
aa7336d749 |
Répéter un créneau sur plusieurs jours
Le panneau créait un créneau, pour un jour. Or un même horaire se répète d'un jour à l'autre bien plus souvent qu'il ne varie : ressaisir cinq fois « 9 h–17 h, pause 30 » était le geste le plus répété de la semaine, et le plus exposé à la faute de frappe. Les sept jours sont désormais cochables. Le jour ouvert est coché et verrouillé — on ne crée pas ailleurs qu'ici depuis la case d'un jour donné — et voyage dans un champ caché, puisqu'une case désactivée n'est pas envoyée. La création est **tout ou rien**. Un jour refusé, pour période close ou chevauchement, annule les autres : une répétition à demi appliquée laisserait un planning que personne n'a voulu, et qu'il faudrait défaire à la main pour le refaire. Le contrôle de période porte donc sur tous les jours demandés avant la première écriture. Trois champs du modèle étaient inatteignables depuis l'écran : le nombre de repas, la note du créneau, et l'étiquette en modification. Cette dernière était un vrai défaut — une étiquette posée de travers se corrigeait en supprimant le créneau pour le refaire, ce qui perdait sa validation et son historique. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
5f656d05af |
Corriger le bandeau de compteurs, et régler impression et productivité
Le bandeau de la grille affichait contrat, planifié, écart, dimanches et jours de repos. PLAN.md §7.4 en demande cinq autres : heures contractuelles, planifié, absences, écart, repos compensateur. La capture du produit audité le confirme. L'écart n'était pas cosmétique. Les dimanches travaillés et les jours de repos se lisent déjà sur la grille, colonne par colonne. Le repos compensateur, lui, ne se lit nulle part ailleurs : c'est une contrepartie due — au dimanche travaillé, au dépassement de contingent — et l'omettre du bandeau masquait la seule valeur qui dit qu'une dette existe. Le compteur RC n'était alimenté par rien : les repos posés n'étaient tout simplement pas chargés avec la semaine. Ils le sont, et seul le repos compensateur y entre — le repos hebdomadaire est un droit déjà pris, les additionner ferait disparaître la dette dans un total qui ne veut rien dire. Deux écrans de réglages complètent le lot. L'impression gouverne le planning affiché en salle : orientation, densité, totaux, dimanche, colonne d'émargement. Cette dernière porte un avertissement — un émargement papier ne vaut pas décompte du temps de travail, et le décompte reste celui de PlanFlow. L'objectif de productivité est nullable et non « zéro par défaut » : zéro est un objectif inatteignable, l'absence de valeur dit qu'aucun objectif n'a été fixé. Vider le champ efface donc l'objectif au lieu de le mettre à zéro. L'écran rappelle aussi ce que l'indicateur n'est pas : il éclaire une décision d'organisation, il ne mesure pas le travail d'une personne. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
0213375a8f |
WP-06 : absences, registre de compteurs, calendrier
Le dernier module de démonstration disparaît : `src/lib/demo/` ne contient plus que l'aperçu. Le décompte, là où l'on se trompe - **`endDate` est le dernier jour d'absence, pas la date de reprise.** C'est la confusion la plus fréquente du domaine : elle décompte un jour de trop ou de trop peu à chaque demande, et le salarié s'en aperçoit au solde, des mois plus tard. Le champ du formulaire s'appelle « Dernier jour d'absence », et un test couvre explicitement la confusion. - **Un jour férié dans un congé ne se décompte pas**, sans que l'utilisateur ait à scinder sa demande. Exiger la scission, c'est lui déplacer la charge d'un calcul que l'outil sait faire. - Le rythme du contrat est respecté : un temps partiel qui ne travaille jamais le mercredi ne consomme pas de congé ce jour-là. - Ouvrables ou ouvrés est un **paramètre**, pas une constante : se tromper fausse tous les soldes de la même façon. Jours fériés calculés, pas listés Une table écrite à la main est juste l'année où on l'écrit et fausse dès la suivante — et un férié manquant se décompte comme un jour de congé, sans que personne ne le voie. Les onze jours légaux sont donc calculés, Pâques comprise (algorithme grégorien anonyme, vérifié sur quatre années de référence). Quand aucun férié n'est enregistré pour l'année demandée, la demande passe mais l'écran le dit : mieux vaut l'annoncer que laisser croire à un décompte complet. Le registre est la source de vérité - Aucun solde n'est stocké : le solde est la **somme** des écritures. Un solde stocké se désynchronise, et la désynchronisation ne se voit qu'au moment où un salarié conteste. - `UPDATE` et `DELETE` sont refusés par un trigger PostgreSQL, pas seulement par l'application : une règle applicative finit par être contournée par un script de reprise. Les tests d'intégration écrivent directement en base pour le prouver. - Annuler une absence acceptée **contre-passe** la prise au lieu de l'effacer, à la date de la correction — antidater masquerait la correction dans les soldes déjà communiqués. `reversesId` est unique : contre-passer deux fois ferait repartir le solde dans l'autre sens. - Un ajustement manuel sans justification est refusé. Confidentialité du motif médical Un manager voit qu'un salarié est absent, pas de quoi il souffre (matrice n° 9). Le motif d'un arrêt n'est **pas chargé** pour qui n'a pas la capacité de le lire — un champ absent de la réponse ne peut fuiter ni par le HTML ni par un journal. Sur la grille de planning, l'absence s'affiche « Absence » : c'est suffisant pour ne pas planifier quelqu'un. Acquisition 2,5 jours ouvrables par mois travaillé ; 2 jours par mois d'arrêt maladie non professionnelle, plafonnés à 24 par an — droit issu de la réforme de 2024, dont l'oubli prive le salarié d'un droit acquis. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv |
||
|
|
023f236881 |
WP-04: planning sur données réelles — grille semaine, vue jour, publication par équipe
Le planning quitte le module de démonstration : la grille lit `WeeklySchedule` et `Shift`, et les quatre derniers fichiers de `src/lib/demo/` qui portaient des salariés fictifs disparaissent. Modèle - `TeamMember` : rattachement d'un salarié à une équipe, distinct de `MembershipScope` (qui dit ce qu'un manager a le droit de voir). Sans lui, un salarié sans créneau n'apparaîtrait pas dans la grille — c'est-à-dire l'état de départ de toute semaine en construction. - RLS sur `WeeklySchedule`, `Shift`, `Rest`, `DailyNote` et `TeamMember`. Temps - `src/domain/planning/week.ts` : repérage par couple année ISO + semaine ISO, jamais par date de début. Le lundi 29 décembre 2025 appartient à la semaine 1 de 2026 ; une clé fondée sur la date ferait apparaître deux semaines 1. - `zonedInstant` / `zonedMidnight` corrigent le décalage mesuré **à l'instant visé**. Le 29 mars 2026, minuit est en UTC+1 et 09 h en UTC+2 : ajouter neuf heures à minuit donnerait 10 h locales. - La semaine du retour à l'heure d'hiver dure 169 h, celle du passage à l'heure d'été 167 — vérifié par test. Écritures - Création, modification, suppression de créneau ; publication et dépublication **par équipe**, avec verrou optimiste sur `version` : deux managers sur la même grille est le cas normal, pas l'exception. - Chevauchement refusé en transaction, pas seulement dans le formulaire. - Modifier une semaine publiée exige `planning.edit_published`, capacité que le rôle manager n'a pas : un salarié a organisé sa semaine sur ce qu'il a lu. - Toute mutation laisse une entrée d'audit ; la suppression écrit sa trace **avant** l'effacement, sinon l'état supprimé serait perdu. Lecture - `planning.view_unpublished` filtre en base : sans cette capacité, les brouillons ne sont pas chargés du tout. Un test vérifie que les horaires n'apparaissent pas dans le HTML servi — un masquage CSS les y laisserait. - Vue jour reconstruite sur les mêmes données, amplitude déduite de la journée réelle plutôt que figée à 06 h–21 h. Vérification - 26 tests unitaires sur le repérage des semaines et la mise en grille. - Parcours e2e : poser un créneau, refus de chevauchement, publier, dépublier ; et ce que voient un salarié et un manager sur la même semaine. - `scripts/dev-db.sh` : la base de développement est éphémère dans cet environnement, la remonter ne doit pas être une redécouverte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv |