fix(commercial) : validation tous-blocs des onglets collection client + fix 500 NonUniqueResult (ERP-110) #61
Reference in New Issue
Block a user
Delete Branch "fix/erp-107-validation-blocs-collection"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Contexte (ERP-110, dérivé de ERP-107)
Sur les onglets à blocs dynamiques d'un client (Contacts / Adresses / RIB), le POST d'une sous-ressource sur un client ayant déjà ≥2 enfants renvoyait une 500
NonUniqueResultException, court-circuitant la validation (aucune 422 par champ).Cause racine
Au stade « read » du POST, le
LinktoPropertyfaisait résoudre la collection enfant viagetOneOrNullResult()(ItemProvider) :SELECT o FROM ClientContact o INNER JOIN o.client c WHERE c.id = :clientId. Dès 2 enfants →NonUniqueResult→ 500 avant la déserialisation/validation. Les 3 sous-ressources partageaient la même config (même bug latent). Cause secondaire front : la boucle de soumission s'arrêtait au 1er bloc en erreur (returndans lecatch).Correctif
Back —
read: falsesur les 3 opérationsPost(ClientContact/ClientAddress/ClientRib) : le parent est déjà rattaché manuellement par le*Processor::linkParent. Les 3linkParentsont durcis (NotFoundHttpExceptionsi parent absent → 404 préservé, sinon régression 500 au persist surclient_id NOT NULL).Front — nouveau helper
useClientFormErrors().submitRows()qui tente tous les blocs et collecte les erreurs 422 par index (hasError), branché sur les 6 sites (new.vue+edit.vue× contacts/adresses/RIB). Feedback inline seul : pas de toast récap, pas de toast succès tant qu'un bloc reste en erreur.Tests
propertyPath=email(validation atteinte). Rouge avant fix (500), vert après.submitRows(Vitest) — tente tous les blocs, mappe les erreurs par index, n'arrête pas au 1er échec, délègue le fallback non-422, saute les blocs filtrés.Vérifications
make test: 474/474 OKmake php-cs-fixer-allow-risky: 0 fichier à corrigermake nuxt-test: 219/219 OKReview ERP-110 — 2 points (faible sévérité)
PR solide. Le correctif back (
read: false+linkParentdurci) est correct et la suiteClientSubResourceApiTestpasse (18 tests). J'ai notamment vérifié queread: falsene court-circuite pas l'expressionsecurity:testRibWriteWithoutAccountingManageReturns403(POST sans permission → 403) passe toujours.Deux points front à considérer :
🟡 1. Erreurs RIB « fantômes » si le PATCH scalaire comptable échoue
new.vue(~886) et[id]/edit.vue(~905) —submitAccountingLe reset
ribErrors.value = []en tête de fonction a été retiré (le reset vit maintenant danssubmitRows, donc à l'étape 2). Si l'étape 1 (PATCH des scalaires comptables) échoue, onreturnavantsubmitRows→ les erreurs RIB d'une soumission précédente restent affichées.Scénario : IBAN invalide → 422 inline sous le RIB. L'utilisateur corrige l'IBAN mais saisit mal un champ scalaire (ex. SIREN) → re-submit → l'étape 1 échoue,
return→ l'ancienne erreur IBAN reste affichée alors qu'elle est corrigée.Fix : remettre
ribErrors.value = []en tête desubmitAccounting(juste aprèsaccountingErrors.clearErrors()).🟡 2. Bloc existant entièrement vidé → ignoré en silence + faux toast de succès
[id]/edit.vue—submitContacts/submitAccounting(mode edit)isContactBlank/isRibBlankskippent tout bloc vide, y compris un blocid !== null(entité existante). Si l'utilisateur vide tous les champs d'un contact/RIB existant et valide → aucun PATCH envoyé,hasErrorrestefalse→ toast de succès affiché alors que rien n'a été persisté (perte silencieuse d'intention).Cas limite (vider sans passer par la suppression), mais le faux « succès » est trompeur.
Option : ne skipper que les blocs vides dont
id === null(amorces neuves), pas les entités existantes.⚪ Note (pas un bug)
Le 404 « client inexistant » est désormais porté par
*Processor::linkParent(au lieu du read stage). Aucun test ne couvrePOST /api/clients/{idInexistant}/contacts → 404— ajout de couverture suggéré.Corrigé dans
b564838(fix) +ad32d81(test) :ribErrors.value = []remis en tête desubmitAccounting(new.vue + edit.vue) : plus d'erreurs RIB obsolètes si l'étape 1 (PATCH scalaires) échoue.shouldSkippasse àrow.id === null && isXBlank(row): un contact/RIB existant vidé part désormais en PATCH → 422 inline (plus de faux toast de succès). Aucun impact en création.testPost{Contact,Address,Rib}OnMissingClientReturns404) couvrant le 404 porté par*Processor::linkParent.Vérifs :
ClientSubResourceApiTest21/21 ✅ ·nuxt-test227/227 ✅ · php-cs-fixer 0 fix.