# Normalisation des dates

## Format canonique

Toutes les valeurs représentant une date sans heure sont stockées au format ISO
`Y-m-d` (par exemple `2026-09-30`). Elles ne doivent pas contenir d’heure, de
minutes ou de secondes. Les colonnes réellement datetime (journaux, `created_at`,
etc.) ne sont pas concernées.

## Dynamic fields

`lncshared/app/Models/DynamicModel.php` applique automatiquement `Y-m-d` aux
champs dont le metadata déclare `field_type = date`, à la lecture comme à
l’écriture du JSON dynamique. Cette règle s’applique lorsque la valeur passe par
le setter de `DynamicModel`.

Depuis la centralisation, `DynamicModel` possède aussi un hook `saving` générique
qui nettoie les dates ISO avec heure (`YYYY-MM-DD HH:MM:SS`) et les dates
européennes exactes (`dd/mm/YYYY`) dans les données JSON avant toute sauvegarde.
Le modèle `Lease` n’a donc plus de `booted()` spécifique pour cette conversion.

## Entrées HTTP et routes

Les formulaires peuvent envoyer `dd/mm/yyyy` et certains liens historiques
peuvent contenir ce format. Avant validation ou requête SQL, utiliser le service
partagé `LncShared\App\Services\DateNormalizer` :

```php
DateNormalizer::normalizeRequest($request, [
    'start_date', 'contract_date', 'add_parent_lease_date',
]);
```

Cette étape est nécessaire car `lncshared` ne peut pas normaliser un paramètre
de route, une valeur utilisée directement dans `whereDate()` ou un champ qui
contourne `DynamicModel`.

## Données historiques

Les anciennes valeurs JSON pouvant contenir `00:00:00` sont progressivement
normalisées lors de la sauvegarde des baux. La migration
`2026_08_26_000004_normalize_lease_json_dates` nettoie les valeurs historiques
dans `leases.data` (y compris les tableaux imbriqués) sans utiliser
`chunkById`, car `leases` possède une clé primaire composite. Elle peut être
appliquée en production avec :

```bash
php artisan migrate --force
```

La migration est volontairement non réversible : elle supprime uniquement les
heures parasites et convertit les dates européennes exactes.

## Règle de maintenance

Ne pas ajouter de fonction locale de conversion de date dans un contrôleur.
Ajouter le champ à la liste passée à `DateNormalizer::normalizeRequest()` et
laisser `DynamicModel` garantir le format des dynamic fields.
Le hook générique de `DynamicModel` constitue la dernière protection pour les
écritures qui ne passent pas par les contrôleurs HTTP.

## Étapes 3 et 4 — contrôle centralisé

Les écritures de bail passent désormais par `DateNormalizer` dans les contrôleurs
API et Web (étape 3). En complément, le hook `saving` de `DynamicModel` applique
la même règle à toute écriture JSON dynamique, quel que soit le point d’entrée
(import, commande ou modèle) (étape 4). Il n’est donc plus nécessaire de
redéfinir `Lease::booted()` pour normaliser les dates.

La règle métier complémentaire est que `endDate_d` doit être strictement
postérieure à `start_date`. Lors de la création d’un avenant à la date `J` :

- le bail précédent (parent ou dernier avenant) est clôturé au `J-1` ;
- `add_parent_lease_date` est la `start_date` du bail d’origine (premier bail
  non-avenant antérieur à `J`) ;
- `add_start_index_date` est la dernière date anniversaire de ce bail parent
  inférieure ou égale à `J`.
