This commit is contained in:
PTA
2026-08-20 17:00:06 +02:00
parent 5d8c0993a6
commit 94e7f09eb4
58 changed files with 5605 additions and 615 deletions

90
docs/README_V7_15.md Normal file
View File

@@ -0,0 +1,90 @@
# PTA V7.15 — Les affectations sont bornées par le contrat de l’agent
## Le problème traité
La fiche agent portait `date_debut_contrat` et `date_fin_contrat` depuis l’origine — saisies,
contrôlées l’une par rapport à l’autre, affichées dans les écrans et les PDF. Mais **aucun contrôle
de planification ne les lisait** : rien n’empêchait de planifier un agent trois mois avant son
arrivée, ou un contrat temporaire l’année suivant son départ.
Les conséquences n’étaient pas cosmétiques : ces heures entraient dans les cumuls annuels, dans le
quota, dans les contrôles de couverture — un lieu pouvait passer pour couvert par un agent qui
n’était pas encore embauché.
## Ce qui change
### 1. Toute écriture de créneau est bornée
La règle est posée sur **tous** les chemins qui créent ou déplacent une affectation :
| Chemin | Ce qui est contrôlé |
| --- | --- |
| Enregistrement d’un brouillon | Chaque date saisie |
| Modification d’un créneau (fiche agent) | La nouvelle date |
| Déplacement / duplication d’un créneau | La date cible |
| Copie d’une semaine entière | Les cinq jours ouvrés de la semaine cible |
| Application d’une semaine type | Les cinq jours ouvrés de la semaine visée |
| Duplication sur une période | Les deux bornes de la période |
Le refus est un **422** portant `code: HORS_CONTRAT`, la liste des dates refusées, et une phrase qui
nomme la période réellement couverte :
> Marc Louis n’est pas sous contrat à cette période : son contrat court à partir du 04/05/2026.
> Date(s) refusée(s) : 02/03/2026.
La règle vaut pour **tous les motifs**, congés et absences compris : hors contrat, il n’y a rien à
décompter.
Une borne absente **ouvre**, elle ne ferme jamais : pas de date de fin signifie contrat à durée
indéterminée ; pas de date de début (fiche ancienne) signifie qu’aucune borne basse n’est opposée,
plutôt que d’inventer une date.
### 2. La validation révèle les affectations déjà hors contrat
Les gardes ci-dessus empêchent d’en créer de nouvelles ; elles ne disent rien de celles qui
existaient avant. Un contrôle bloquant `HORS_CONTRAT` rejoint donc les quatre contrôles de
validation existants, à la validation d’une semaine comme à celle d’une année entière :
> L’affectation #824 du 2026-05-11 est en dehors des dates de contrat de l’agent.
La comparaison est faite en SQL sur la fiche agent jointe : c’est l’état du contrat **au moment du
contrôle** qui fait foi.
### 3. Le contrat ne peut plus glisser sous des affectations existantes
Contrôle miroir, sans lequel le premier ne servirait à rien : modifier les dates de contrat d’un
agent est refusé si cela laisserait des affectations au-dehors. Le message dit combien et sur quelle
période, pour qu’on sache quoi retirer :
> Ces dates de contrat laisseraient 6 affectation(s) en dehors du contrat, entre le 11/05/2026 et le
> 14/08/2026. Supprimez-les d’abord, ou élargissez les dates.
## Vérifications effectuées
Onze cas exécutés sur la pile, tous conformes : saisie avant le début de contrat (refusée), dans le
contrat (acceptée), sur la semaine à cheval contenant le premier jour (acceptée), copie de semaine
hors contrat, saisie après la date de fin, déplacement et modification de créneau vers une date hors
contrat, raccourcissement de contrat sous des affectations existantes, contrôle de validation sur une
donnée devenue illégitime, application d’une semaine type sur une semaine puis sur une période hors
contrat.
## Fichiers
| Fichier | Rôle |
| --- | --- |
| `app/Models/AgentModel.php` | `contractRange()`, `contractCoversDate()`, `datesOutsideContract()`, `contractViolationMessage()`, `entriesOutsideContract()` |
| `app/Controllers/PlanningController.php` | Garde sur les quatre chemins d’écriture, contrôle de validation |
| `app/Controllers/WeekTemplateController.php` | Garde sur l’application à une semaine et sur une période |
| `app/Controllers/AnnualOverviewController.php` | Même contrôle à la validation annuelle |
| `app/Controllers/AgentController.php` | Refus d’un contrat qui orphelinerait des affectations |
| `app/Models/PlanningModel.php` | `entriesOutsideContract()` pour le contrôle de validation |
Aucune migration : les colonnes existent depuis le socle, seule leur exploitation change.
## Point d’attention
La garde est **dupliquée** dans `PlanningController` et `WeekTemplateController`, faute de base
commune entre contrôleurs — comme l’est déjà `parseWeek()`. Ce qui n’est pas dupliqué, c’est le
message : il est construit par `AgentModel::contractViolationMessage()`, pour que l’utilisateur lise
la même phrase quel que soit l’écran. **Toute nouvelle voie d’écriture de créneaux doit poser la même
garde** — le contrôle de validation n’est qu’un filet, pas un substitut.