Commit Graph

2 Commits

Author SHA1 Message Date
Matthieu ff47af07d2 feat(commercial) : entités M2 fournisseurs + repositories (ERP-86)
Entités jumelles du M1 client, mapping ORM aligné sur la migration ERP-85,
sans contact inline (ERP-106) :

- Supplier (#[Auditable] + Timestampable/Blamable) : formulaire principal,
  Information (+ volumeForecast), Comptabilité (FK référentiels M1), archivage,
  soft-delete préparé. Catégories M2M via CategoryInterface (règle n°1).
- SupplierContact / SupplierAddress (enum addressType, bennes, triageProvider)
  / SupplierRib.
- Repositories : interfaces Domain + impls Doctrine. DoctrineSupplierRepository
  porte les fetch-joins anti-N+1 de la liste (categories + addresses.sites en
  2 passes, pattern ERP-100) et les filtres (search companyName + contacts,
  categoryCode, siteId, archivage).

Contrat de sérialisation (RETEX M1, 3 maillons posés sur l'entité) :
read-groups sur les propriétés, getters isArchived/isTriageProvider avec
SerializedName, embed contacts/addresses (supplier:item:read) et ribs
(supplier:read:accounting). L'#[ApiResource] + Provider/Processor sont au
ticket suivant (ERP-87).

Validation FR (ERP-107) : messages FR sur toutes les contraintes, Length(max)
calé sur les colonnes. Garde-fou EntityConstraintsHaveFrenchMessageTest étendu
(Assert\Choice + whitelist addressType/postalCode). Clés i18n audit des 4
entités ajoutées.

make test : 483/483 OK.
2026-06-05 10:55:04 +02:00
matthieu 597101262d feat(commercial) : messages de validation FR sur les contraintes back + garde-fou (ERP-107) (#59)
Auto Tag Develop / tag (push) Successful in 8s
## Contexte

Résout **ERP-107** — pendant back du mapping d'erreur par champ front (ERP-101). Le front (`useFormErrors` / `mapViolationsToRecord`) affiche sous chaque champ le `message` renvoyé par le back. Ce ticket garantit que ces messages existent, sont en FR et rattachés au bon champ.

## Changements

- **Messages FR explicites** sur toutes les contraintes `#[Assert\*]` des entités métier : `Client`, `ClientContact`, `ClientAddress`, `ClientRib`, `Category`, `Role`, `User` (Email, NotBlank, Length, Bic, Iban, PositiveOrZero, Count…).
- **Contraintes `Assert\Length` manquantes ajoutées**, calées sur le `length` de la colonne ORM (téléphones `VARCHAR(20)`, `siren`, `nTva`, `accountNumber`, `username`…). Évite une erreur Postgres 500 non rattachée au champ → 422 propre.
- **Locale FR globale** (`symfony/translation` + `default_locale: fr`) comme filet pour les messages natifs Symfony non surchargés.
- **Garde-fou** `tests/Architecture/EntityConstraintsHaveFrenchMessageTest` : échoue si une contrainte n'a pas de message FR explicite (comparaison au défaut Symfony) ou si `Assert\Length.max` diverge du `length` ORM. Whitelist justifiée pour les formats auto-bornés (Bic/Iban/Regex CP/couleur hex).
- **Test fonctionnel** du JSON 422 réel : message FR + `propertyPath` consommable par le front.
- **Convention documentée** dans `.claude/rules/backend.md`.

## Décisions

- Stratégie retenue : message FR **explicite sur toutes** les contraintes + locale FR en filet (les deux leviers du ticket).
- Garde-fou `Length == ORM length` : **test bloquant** (anti-dérive).
- RG-1.03 (distributor/broker) : pas de `Assert\Callback` ajouté — le `ClientProcessor` gère **déjà** l'exclusivité (422 + `propertyPath`). Pas de doublon.

## Hors périmètre / à suivre

- **Alignement `nullable`(DB) / `NotBlank`(back) / `required`(front)** : les champs obligatoires existants ont été confirmés, mais aucun changement de nullabilité DB n'a été fait sans arbitrage métier. À recroiser avec les astérisques front (ERP-101 / PR #58) si divergence constatée.

## Vérifications

- `make test` : **469 tests verts** (1793 assertions), 0 échec/erreur.
- `php-cs-fixer` : 0 fichier à corriger.

---------

Co-authored-by: admin malio <malio@yuno.malio.fr>
Co-authored-by: Matthieu <contact@malio.fr>
Reviewed-on: #59
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
2026-06-04 09:27:32 +00:00