fix(heures) : n'enregistrer que les lignes modifiées (anti-écrasement concurrent) (#31)
Auto Tag Develop / tag (push) Successful in 10s
Auto Tag Develop / tag (push) Successful in 10s
## Problème Sur l'écran **Heures** / **Heures Conducteurs**, l'enregistrement envoyait au bulk-upsert une entrée pour **tous** les employés visibles non verrouillés, à partir de l'état en mémoire de la grille. Le backend (`WorkHourBulkUpsertProcessor`) traitant une **entrée vide comme une suppression**, un admin avec une grille **périmée** pouvait supprimer une ligne saisie entre-temps par un autre utilisateur. ### Scénario reproduit 1. Un admin ouvre l'écran ; la ligne d'un salarié `ROLE_SELF` est vide. 2. Ce salarié saisit ses heures dans sa propre session → ligne créée, **non validée** (donc non verrouillée). 3. L'admin, sur sa grille périmée, enregistre d'autres employés. 4. Le payload contient une entrée **vide** pour le salarié → le backend supprime sa ligne. **Perte de données.** ## Correctif (suivi des lignes modifiées) `hydrateRows` capture un instantané `loadedRows` de l'état chargé depuis le serveur. `handleSave` ne transmet plus que les lignes **dont l'état courant diffère de l'instantané**. - Ligne **intouchée** → jamais envoyée → jamais supprimée ✅ - Ligne **vidée volontairement** → envoyée vide → supprimée (métier conservé) - Ligne **remplie/modifiée** → envoyée → créée/mise à jour Symétrique dans `useHoursPage.ts` et `useDriverHoursPage.ts`. ## Limite connue Pas de verrou optimiste backend : l'édition **explicite** d'une ligne sur données périmées peut toujours écraser une saisie concurrente sur cette même ligne (hors périmètre). ## Doc - `doc/hours-save-dirty-tracking.md` (nouveau) - Note `CLAUDE.md` (section *Validation Rules*) ## Vérification - Pre-commit hook : **236 tests PHPUnit OK**. - Pas de harnais de tests frontend (revue de code uniquement). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #31 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #31.
This commit is contained in:
@@ -64,6 +64,7 @@
|
||||
- `isSiteValid` (site manager): locks for non-admin, admin can still edit
|
||||
- Any real modification resets both `isSiteValid=false` and `isValid=false`
|
||||
- No-op saves preserve existing validations
|
||||
- **Enregistrement = seules les lignes modifiées sont envoyées (anti-écrasement concurrent)** : l'écran Heures / Heures Conducteurs affiche toute la journée, et le bulk-upsert (`WorkHourBulkUpsertProcessor`) traite une **entrée vide comme une suppression**. Pour éviter qu'un admin avec une grille **périmée** ne supprime une ligne saisie entre-temps par un autre utilisateur (ex. `ROLE_SELF` non encore validé → non verrouillé), `handleSave` ne transmet **que les lignes dont l'état courant diffère de l'instantané chargé** (`loadedRows`, capturé dans `hydrateRows` ; comparaison `JSON.stringify(buildEntry(current)) !== buildEntry(original)`). Une ligne intouchée n'est jamais envoyée → jamais supprimée. Vidée volontairement → envoyée vide → supprimée (métier conservé). Symétrique dans `useHoursPage.ts` et `useDriverHoursPage.ts`. **Limite** : pas de verrou optimiste backend — l'édition explicite d'une ligne sur données périmées peut toujours écraser une saisie concurrente sur cette même ligne. Doc : `doc/hours-save-dirty-tracking.md`.
|
||||
|
||||
## Overtime Rules
|
||||
- Contracts <= 35h: +25% from 35h to 43h, +50% beyond
|
||||
|
||||
Reference in New Issue
Block a user