feat(commercial) : validators M2 fournisseurs (RG-2.03/2.07/2.08/2.10) (ERP-89) #68

Merged
malio merged 3 commits from feature/ERP-89-validators-m2 into develop 2026-06-08 07:33:38 +00:00
Owner

Étape 4/7 du M2 fournisseurs — stackée sur #67 (ERP-88).

Périmètre (RG-2.03 / 2.07 / 2.08 / 2.10)

Décision figée ERP-89 : les RG inter-champs passent par Assert\Callback + ->atPath() sur l'entité Supplier (et non dans le Processor), pour que chaque 422 porte un propertyPath consommable par extractApiViolations (mapping inline, pas un toast — ERP-101).

  • RG-2.10Supplier::validateCategoryType()atPath('categories') : catégories de type FOURNISSEUR uniquement sur supplier.categories (miroir d'ERP-88 côté adresse).
  • RG-2.07Supplier::validatePaymentTypeConsistency()atPath('bank') : VIREMENT impose une banque.
  • RG-2.08 — même Callback → atPath('ribs') : LCR impose ≥ 1 RIB (le 409 sur DELETE du dernier RIB en LCR reste porté par ERP-88).
  • RG-2.03SupplierInformationCompletenessValidator (8 champs Information dont volumeForecast), invoqué par le SupplierProcessor après détection back du rôle Commerciale via BusinessRoleAwareInterface. Le Processor ne porte que rôle / mode strict / gating.

Tests (16, verts)

  • SupplierValidationTest — Callbacks RG-2.07/2.08/2.10, assertion par propertyPath.
  • SupplierInformationCompletenessValidatorTest — complétude / champs manquants / zéros valides.
  • SupplierProcessorTest — détection rôle RG-2.03 (POST + PATCH main-only + non-Commerciale).

make test : 499 tests OK. php-cs-fixer : clean.

Étape 4/7 du M2 fournisseurs — stackée sur #67 (ERP-88). ## Périmètre (RG-2.03 / 2.07 / 2.08 / 2.10) Décision figée ERP-89 : les RG inter-champs passent par `Assert\Callback` + `->atPath()` sur l'entité Supplier (et non dans le Processor), pour que chaque 422 porte un `propertyPath` consommable par `extractApiViolations` (mapping inline, pas un toast — ERP-101). - **RG-2.10** — `Supplier::validateCategoryType()` → `atPath('categories')` : catégories de type FOURNISSEUR uniquement sur `supplier.categories` (miroir d'ERP-88 côté adresse). - **RG-2.07** — `Supplier::validatePaymentTypeConsistency()` → `atPath('bank')` : VIREMENT impose une banque. - **RG-2.08** — même Callback → `atPath('ribs')` : LCR impose ≥ 1 RIB (le 409 sur DELETE du dernier RIB en LCR reste porté par ERP-88). - **RG-2.03** — `SupplierInformationCompletenessValidator` (8 champs Information dont `volumeForecast`), invoqué par le `SupplierProcessor` après détection back du rôle Commerciale via `BusinessRoleAwareInterface`. Le Processor ne porte que rôle / mode strict / gating. ## Tests (16, verts) - `SupplierValidationTest` — Callbacks RG-2.07/2.08/2.10, assertion par propertyPath. - `SupplierInformationCompletenessValidatorTest` — complétude / champs manquants / zéros valides. - `SupplierProcessorTest` — détection rôle RG-2.03 (POST + PATCH main-only + non-Commerciale). `make test` : 499 tests OK. `php-cs-fixer` : clean.
matthieu added the backM2-Fournisseurtype/feat labels 2026-06-05 11:59:47 +00:00
Author
Owner

Retours review — points assumés (non bloquants)

Le review (👍 mergeable, aucun défaut bloquant) relève deux points de comportement. Tous deux sont voulus et conformes à la spec + au jumeau M1 déjà en prod — aucun changement de code, on les documente ici :

  1. Archivage d'un fournisseur incomplet par une Commerciale → 422. Lecture littérale de RG-2.03 (« POST et tout PATCH ») et miroir de RG-1.04 (M1). Acté par le test testCommercialeIncompleteInformationOnMainOnlyPatchIsUnprocessable. Comportement assumé.

  2. Friction lifecycle : si un Admin crée un fournisseur sans remplir l'onglet Information (201, non gaté), une Commerciale ne peut plus modifier aucun champ tant que les 8 champs Information ne sont pas complétés. Conforme RG-2.03 + miroir M1. Comportement assumé.

Exempter le PATCH d'archivage de la complétude (pour autoriser l'archivage d'un fournisseur incomplet) serait une décision produit à arbitrer séparément, et devrait alors être répliquée sur le Client M1 pour éviter le drift. Hors périmètre ERP-89.

### Retours review — points assumés (non bloquants) Le review (👍 mergeable, aucun défaut bloquant) relève deux points de comportement. Tous deux sont **voulus** et conformes à la spec + au jumeau M1 déjà en prod — aucun changement de code, on les documente ici : 1. **Archivage d'un fournisseur incomplet par une Commerciale → 422.** Lecture littérale de RG-2.03 (« POST **et tout PATCH** ») et miroir de RG-1.04 (M1). Acté par le test `testCommercialeIncompleteInformationOnMainOnlyPatchIsUnprocessable`. Comportement assumé. 2. **Friction lifecycle** : si un Admin crée un fournisseur sans remplir l'onglet Information (201, non gaté), une Commerciale ne peut plus modifier aucun champ tant que les 8 champs Information ne sont pas complétés. Conforme RG-2.03 + miroir M1. Comportement assumé. > Exempter le PATCH d'archivage de la complétude (pour autoriser l'archivage d'un fournisseur incomplet) serait une **décision produit** à arbitrer séparément, et devrait alors être répliquée sur le Client M1 pour éviter le drift. Hors périmètre ERP-89.
malio changed target branch from feature/ERP-88-sous-ressources-m2 to develop 2026-06-08 07:31:49 +00:00
matthieu added 2 commits 2026-06-08 07:33:18 +00:00
Ajoute les opérations API Platform et les Processors d'écriture des
sous-collections du fournisseur (POST/PATCH/DELETE + GET unitaire) :

- SupplierContactProcessor : rattachement parent, normalisation serveur
  (RG-2.12), validation RG-2.04 (prénom OU nom). DELETE libre (RG-2.13).
- SupplierAddressProcessor : rattachement parent. RG-2.05/2.06/2.09 portées
  par les contraintes d'entité ; RG-2.10 (catégorie type FOURNISSEUR) via
  Assert\Callback validateCategoryType.
- SupplierRibProcessor : rattachement parent, RG-2.08 (refus DELETE du
  dernier RIB sous LCR -> 409).

Security différenciée : contacts/adresses -> commercial.suppliers.manage ;
ribs -> commercial.suppliers.accounting.manage (+ .view pour le GET).
POST en read:false (parent rattaché manuellement, 404 si absent) — parade
NonUniqueResult du M1. Messages FR (ERP-107) + propertyPath aligné (ERP-101).
feat(commercial) : validators M2 fournisseurs (RG-2.03/2.07/2.08/2.10) (ERP-89)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
544da49404
RG inter-champs via Assert\Callback->atPath() sur l'entite Supplier (decision
figee ERP-89), pour un 422 a propertyPath consommable par extractApiViolations :
- RG-2.10 : categories de type FOURNISSEUR (supplier.categories) -> atPath('categories')
- RG-2.07 : VIREMENT impose une banque -> atPath('bank')
- RG-2.08 : LCR impose au moins un RIB -> atPath('ribs')

RG-2.03 (completude Information pour le role Commerciale, detection back via
BusinessRoleAwareInterface) portee par SupplierInformationCompletenessValidator,
invoque par le SupplierProcessor.

Tests : SupplierValidationTest (Callbacks 2.07/2.08/2.10),
SupplierInformationCompletenessValidatorTest, SupplierProcessorTest (RG-2.03).
matthieu force-pushed feature/ERP-89-validators-m2 from b580bb6576 to 544da49404 2026-06-08 07:33:18 +00:00 Compare
malio added 1 commit 2026-06-08 07:33:33 +00:00
Merge branch 'develop' into feature/ERP-89-validators-m2
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Failing after 53s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m7s
0a8f0ba242
malio merged commit e265a008bc into develop 2026-06-08 07:33:38 +00:00
malio deleted branch feature/ERP-89-validators-m2 2026-06-08 07:33:38 +00:00
Sign in to join this conversation.