feat(front) : page Modification fournisseur (/suppliers/{id}/edit) (ERP-96) #85

Merged
tristan merged 13 commits from feature/ERP-96-suppliers-edit into develop 2026-06-11 07:26:33 +00:00
Owner

ERP-96 — Modification fournisseur

Étape 7/7 (front). Dépend de #94 (Ajouter) + #95 (Consultation).

⚠️ MR stackée sur feature/ERP-95-suppliers-show (95 → 94, pas encore mergées dans develop) pour limiter le diff aux 3 fichiers d'ERP-96. À recibler sur develop une fois 94 puis 95 mergées. Squash au merge.

Périmètre

  • Route /suppliers/{id}/edit : champs pré-remplis depuis GET /suppliers/{id}, PATCH partiel indépendant par onglet. Bloc principal conservé (éditable via son propre PATCH supplier:write:main), pas de contact inline (ERP-106).
  • Mode strict (RG-2.16) : chaque onglet n'envoie QUE les champs de son groupe de sérialisation (jamais de mélange → sinon 403). Builders de payload scopés (supplierEdit).
  • Éditabilité par rôle (resolveTabEditability) : métier readonly sans manage ; Comptabilité visible/éditable selon accounting.view/accounting.manage ; placeholders non éditables.
  • Collections contacts/adresses/RIB : POST/PATCH par ligne + DELETE différé des retraits ; 422 mappées inline par champ (propertyPathuseSupplierFormErrors/extractApiViolations), jamais un toast fourre-tout (ERP-101).

Tests

  • Vitest : supplierEdit.spec.ts enrichi (mappers d'hydratation mapMainDraft/mapInformationDraft avec volumeForecast/mapAccountingFormDraft + resolveTabEditability matrice § 2.7). make nuxt-test → 375/375 . ESLint .
  • nuxi typecheck non lancé sur l'hôte (casse le conteneur dev-nuxt).

Miroir de l'écran Modification client (M1), adapté M2 (enum addressType, bennes/triageProvider/volumeForecast, pas de relation Distributeur/Courtier).

## ERP-96 — Modification fournisseur Étape 7/7 (front). Dépend de #94 (Ajouter) + #95 (Consultation). > ⚠️ MR **stackée sur `feature/ERP-95-suppliers-show`** (95 → 94, pas encore mergées dans develop) pour limiter le diff aux 3 fichiers d'ERP-96. À recibler sur `develop` une fois 94 puis 95 mergées. Squash au merge. ### Périmètre - Route `/suppliers/{id}/edit` : champs **pré-remplis** depuis GET /suppliers/{id}, **PATCH partiel indépendant par onglet**. Bloc principal conservé (éditable via son propre PATCH `supplier:write:main`), pas de contact inline (ERP-106). - **Mode strict (RG-2.16)** : chaque onglet n'envoie QUE les champs de son groupe de sérialisation (jamais de mélange → sinon 403). Builders de payload scopés (`supplierEdit`). - Éditabilité par rôle (`resolveTabEditability`) : métier readonly sans `manage` ; Comptabilité visible/éditable selon `accounting.view`/`accounting.manage` ; placeholders non éditables. - Collections contacts/adresses/RIB : POST/PATCH par ligne + DELETE différé des retraits ; 422 mappées **inline par champ** (`propertyPath` → `useSupplierFormErrors`/`extractApiViolations`), jamais un toast fourre-tout (ERP-101). ### Tests - Vitest : `supplierEdit.spec.ts` enrichi (mappers d'hydratation `mapMainDraft`/`mapInformationDraft` avec `volumeForecast`/`mapAccountingFormDraft` + `resolveTabEditability` matrice § 2.7). `make nuxt-test` → 375/375 ✅. ESLint ✅. - `nuxi typecheck` non lancé sur l'hôte (casse le conteneur dev-nuxt). Miroir de l'écran Modification client (M1), adapté M2 (enum `addressType`, `bennes`/`triageProvider`/`volumeForecast`, pas de relation Distributeur/Courtier).
tristan changed target branch from feature/ERP-95-suppliers-show to develop 2026-06-11 07:15:32 +00:00
tristan added 12 commits 2026-06-11 07:15:32 +00:00
feat(front) : page Répertoire fournisseurs (/suppliers) + datatable + filtres + export (ERP-93)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m6s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m10s
79d389834b
- useSupplier(id) : GET /api/suppliers/{id} en Hydra (embed contacts/adresses/ribs
  + scalaires compta si accounting.view), archive()/restore() via PATCH isArchived seul
- supplierConsultation : mappers purs de l'embed (addressType, bennes, triageProvider,
  volumeForecast ; gating compta par omission de cle), helpers de permissions
- page [id]/index.vue : lecture seule, bloc principal + onglets (Information/Contacts/
  Adresses/Comptabilite selon permission/4 coquilles A venir), Modifier/Archiver/Restaurer,
  fleche retour repertoire ; miroir de l'ecran Consultation client (M1)
- tests Vitest : supplierConsultation (mappers + permissions) + useSupplier (GET/PATCH)
- page edit.vue : champs pre-remplis depuis GET /suppliers/{id}, PATCH partiel
  INDEPENDANT par onglet (mode strict RG-2.16 : un seul groupe de serialisation
  par appel), pas de formulaire principal masque mais editable via son propre PATCH
- pas de contact inline (ERP-106) ; onglets metier readonly sans manage, Comptabilite
  visible/editable selon accounting.view / accounting.manage (resolveTabEditability)
- collections contacts/adresses/RIB : POST/PATCH par ligne + DELETE differe des
  retraits ; erreurs 422 mappees inline par champ (propertyPath) via useSupplierFormErrors
- supplierEdit : mappers d'hydratation (mapMainDraft/mapInformationDraft/
  mapAccountingFormDraft, + volumeForecast) et resolveTabEditability
- tests Vitest : mappers d'hydratation + gating par role (matrice 2.7)
- miroir de l'ecran Modification client (M1), adapte M2 (addressType/bennes/
  triageProvider/volumeForecast, pas de relation Distributeur/Courtier)
En edition (PATCH merge), omettre la cle d'un champ requis vide laissait la valeur
serveur inchangee -> faux 200 (l'ancien code postal etait conserve). Nouveau helper
blankEmptyRequired + flag forUpdate sur les builders : a la creation (POST) on omet
toujours la cle (NotBlank), en edition d'une ligne existante on envoie '' (chaine
valide, pas de 400 de type) pour declencher NotBlank 422 inline sous le champ.
Applique au bloc principal, aux adresses et aux RIB (selon id !== null).
Port du fix fournisseur (blankEmptyRequired + flag forUpdate) a l'edition client :
en PATCH d'une ligne existante, un champ requis vide (companyName / postalCode /
city / street / label / bic / iban) est envoye en '' au lieu d'etre omis, sinon le
merge-patch garde l'ancienne valeur (faux 200). Creation (POST) inchangee (omit).
La poubelle de suppression d'un bloc RIB n'apparait que s'il y a plusieurs RIB
(visibleRibs.length > 1) ; elle s'affiche alors sur chaque bloc. Avec un RIB unique
(minimum requis pour une LCR), pas de poubelle. Aligne sur les blocs contact/adresse.
Applique aux ecrans creation + modification, fournisseur et client (M1).
Onglet Comptabilite : on ne saute une amorce RIB neuve vide QUE s'il reste un autre
RIB soumettable (garde hasSubmittableRib, miroir de l'onglet Contacts). Sinon — ex.
unique RIB existant supprime puis remplace par un bloc vide en LCR — le bloc vide est
soumis et le back renvoie une 422 NotBlank mappee en rouge sous label/bic/iban, au lieu
de laisser le DELETE echouer en « dernier RIB d'une LCR » (message plat sans propertyPath).
L'ancien RIB est preserve (arret avant le DELETE). Applique creation + edition, fournisseur + client.
tristan added 1 commit 2026-06-11 07:20:22 +00:00
Merge remote-tracking branch 'origin/develop' into feature/ERP-96-suppliers-edit
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m6s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m15s
6c627ee2d5
# Conflicts:
#	frontend/modules/commercial/pages/suppliers/new.vue
#	frontend/modules/commercial/utils/__tests__/supplierEdit.spec.ts
#	frontend/modules/commercial/utils/supplierEdit.ts
#	frontend/modules/commercial/utils/supplierFormRules.ts
tristan merged commit c594a76d47 into develop 2026-06-11 07:26:33 +00:00
tristan deleted branch feature/ERP-96-suppliers-edit 2026-06-11 07:26:33 +00:00
Sign in to join this conversation.