Fait étendre SupplierExportControllerTest à AbstractSupplierApiTestCase au
lieu d'AbstractCommercialApiTestCase. Supprime le seedSupplier() privé (qui
seedait des catégories de type CLIENT via createCategory(), violant RG-2.10)
et le tearDown() redondant, désormais portés par la base sur des catégories
FOURNISSEUR.
Le contact principal utilise le helper addContact() de la base ; le téléphone
secondaire, non porté par ce helper, est posé via le setter sur le contact
retourné. L'assertion de la colonne Catégories dérive le libellé attendu de
supplierCategory('NEGOCIANT') au lieu de hardcoder le préfixe de nom de test.
- config/packages/test/doctrine.yaml : force dbal profiling en test pour que
doctrine.debug_data_holder existe sous APP_DEBUG=0 (CI). Le test anti-N+1
SupplierListTest passait en local (debug=1) mais cassait en CI.
- RBACMatrix/SupplierApi : les 422 RG-2.03 et RG-2.14 assertent desormais le
propertyPath / message (plus seulement le code) — un 422 orthogonal ne peut
plus faire passer le test.
- RBACMatrix : gating bureau/commerciale verifie l'ensemble des champs
comptables (accountNumber/nTva/tvaMode/paymentType), plus seulement siren/ribs.
- violationsByPath() mutualise dans AbstractSupplierApiTestCase (dedup).
Suite fonctionnelle M2 assertant sur le CORPS JSON (jamais les annotations),
jumelle de la suite clients M1 :
- contrat de sérialisation : 4 régressions M1 re-testées (RIB gaté absent pour
Commerciale, booléens triageProvider/isArchived présents, embed
categories[].code/name, embed sites[].name/postalCode objet) + enveloppe AP4
(member/totalItems/view, archivés exclus) + suppression du contact inline ;
- matrice RBAC réelle (app:seed-rbac) bureau/compta/commerciale/usine 200/403,
gating accounting par omission de clé, mode strict PATCH (RG-2.16) ;
- RG-2.03/2.04/2.05/2.06/2.07/2.08/2.09/2.10/2.11/2.12/2.14/2.15/2.17 ;
- sous-ressources contacts/adresses/ribs (CRUD, sécurité, normalisation) ;
- anti N+1 liste (compte de requêtes constant), audit Supplier + RIB iban/bic.
Fix de contrat découvert et corrigé (sinon DoD figée sur un contrat faux) :
les référentiels comptables (TvaMode/PaymentType/PaymentDelay/Bank) ne portaient
que le groupe client:read:accounting (M1) → sur un fournisseur ils sortaient en
IRI nu. Ajout de supplier:read:accounting → objet {id, code, label} embarqué.
makefile : test-db-setup recrée l'index partiel uq_supplier_company_name_active
(droppé par schema:update comme pour le client) — oubli M2.
DoD § 4.0.bis : réponses JSON RÉELLES (liste + détail admin/commerciale) collées,
capturées via SupplierSerializationContractTest.
Export XLSX du répertoire fournisseurs (spec § 4.6), jumeau de l'export client M1.
- SupplierExportController avec #[Route(priority: 1)] (anti-conflit API Platform {id}),
is_granted('commercial.suppliers.view'). Mêmes filtres que la liste
(includeArchived/archivedOnly/search/categoryCode/siteId) via createListQueryBuilder()
partagé avec le SupplierProvider ; non archivés par défaut.
- Colonnes : Nom, Contact principal (SupplierContact de plus petit position — ERP-106),
Tél principal/secondaire, Email, Catégories (CSV), Sites (CSV), SIREN (omis sans
accounting.view), Date de création.
- hydrateContacts() ajouté au repository (chargement batché des contacts en une requête
IN, anti-N+1) — méthode dédiée à l'export, la liste paginée n'embarque pas les contacts.
- Tables supplier* ajoutées à ColumnCommentsCatalog : leurs COMMENT (posés par la
migration ERP-85) étaient dropés par le schema:update --force du test-db-setup et non
restaurés, cassant ColumnsHaveSqlCommentTest dès un re-setup de la base de test.
- Test fonctionnel SupplierExportControllerTest (9 cas).
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).
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).
Branche les operations API du repertoire fournisseurs (M2), jumelles du M1 :
- SupplierProvider : liste paginee (Paginator ORM), exclusion archives +
soft-deletes par defaut, filtres includeArchived/categoryCode/siteId/search,
echappatoire ?pagination=false, item 404 si soft-delete (RG-2.17).
- SupplierProcessor : normalisation companyName, archivage isArchived/archivedAt
(RG-2.14/2.15), gating fin accounting/manage en mode strict (403 sur tout le
payload hors-permission, RG-2.16), 409 doublon companyName + conflit de
restauration (RG-2.11).
- SupplierReadGroupContextBuilder : ajoute supplier:read:accounting au contexte
de lecture si accounting.view (gating compta + RIB par omission de cle). Un
Provider ne peut pas influencer les groupes de serialisation : c'est le point
d'extension idiomatique, miroir de ClientReadGroupContextBuilder.
- SupplierFieldNormalizer : normalisation serveur (RG-2.12).
- Supplier : ajout #[ApiResource] (GetCollection/Get/Post/Patch) wirant
Provider/Processor.
Validators metier (RG-2.03/2.07/2.08/2.10) = ticket suivant.
make test vert (483/483), php-cs-fixer applique.
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.
Recree le CategoryType FOURNISSEUR (unifie sur CLIENT par ERP-78) et implemente
un vrai filtre ?typeCode= sur GET /api/categories (inexistant en prod).
- CategoryProvider lit ?typeCode= depuis les filtres (meme pattern que
includeDeleted) et le passe au repository ; naltere pas ?pagination=false.
- DoctrineCategoryRepository::createListQueryBuilder joint le CategoryType et
filtre sur son code (compatible Paginator ORM fetchJoinCollection).
- Migration racine Version20260605120000 : seed du type FOURNISSEUR en
ON CONFLICT + 5 categories de demo (Negociant, Cooperative, Producteur,
Grossiste, Importateur) en NOT EXISTS. Aucune colonne creee.
- CategoryTypeFixtures / CategoryFixtures etendus a FOURNISSEUR (idempotent,
survit a make db-reset).
- Test CategoryTypeCodeFilterTest : filtre exclusif, compat pagination Hydra,
code inexistant -> liste vide.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.