Couvre les RG produit (M6) en tests fonctionnels API et capture le contrat de
serialisation reel (DoD spec-back § 4.0.bis).
Tests (tests/Module/Catalog/Api/) :
- AbstractProductApiTestCase : base commune (productType find-or-create PRODUIT,
productCategory, seedStorageType par sites, validProductPayload, dump DoD).
- ProductSerializationContractTest : POST reel + GET liste/detail ; category en
objet embarque, sites/storageTypes en tableaux d'objets, states en tableau,
manufactured/containsMolasses booleens presents. Dump regenerable via
PRODUCT_DOD_DUMP=1.
- ProductCodeUniquenessTest (RG-6.01) : 409 doublon actif, collision sur forme
normalisee, reutilisation d'un code soft-deleted (index partiel).
- ProductStatesValidationTest (RG-6.02) : >=1 etat requis, valeur hors enum 422.
- ProductConditionalFieldsTest (RG-6.03) : manufactured/containsMolasses forces
false sans SALE (POST et PATCH), conserves avec SALE.
- ProductCategoryTypeTest (RG-6.05) : 422 si categorie non-PRODUIT.
- ProductStorageTypeBySiteTest (RG-6.06) : 422 si storageType hors sites choisis.
- ProductRBACMatrixTest : Admin 200/201 ; Bureau/Compta/Commerciale/Usine 403
(view + manage) ; view lit mais ne gere pas.
Fix contrat de serialisation : le getter containsMolasses() ne respectait pas la
convention d'accesseur (get/is/has) -> le serialiseur n'exposait PAS le champ
dans le JSON, alors que le DoD l'exige. Renomme en isContainsMolasses() (+ unique
appelant dans ProductExportController). Defaut capte par le test de contrat.
Spec : JSON reel colle dans spec-back § 4.0.bis (remplace l'esquisse). Le contrat
reel est plus riche : la liste porte deja sites/storageTypes embarques, category
embarque categoryTypes + audit, createdBy/updatedBy en IRI, sites avec adresse.
make test vert (897 tests) ; php-cs-fixer conforme.