Merge branch 'develop' into feat/erp-107-validation-messages-fr
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 1m38s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m7s

This commit is contained in:
2026-06-04 08:41:38 +00:00
23 changed files with 1097 additions and 265 deletions
+34
View File
@@ -44,6 +44,40 @@ Tout champ de formulaire / filtre doit utiliser les composants `Malio*` plutot q
Toute autre exception requiert validation avant merge.
## Validation des formulaires — useFormErrors obligatoire (erreur par champ)
**Tout formulaire qui soumet a une API DOIT afficher les erreurs de validation 422 sous le champ concerne, via `useFormErrors`** (`frontend/shared/composables/useFormErrors.ts`). C'est le pendant front de « le back renvoie TOUTES les violations d'une 422 d'un coup » : un seul aller-retour, chaque erreur affichee inline sous son champ (prop `:error` des `Malio*`), pas un toast fourre-tout.
Principe cle : **le nom du champ cote front = le `propertyPath` renvoye par le back**. Aucun mapping manuel champ par champ.
Pattern de reference (champs scalaires) :
```ts
const { errors, setError, clearErrors, handleApiError } = useFormErrors()
async function submit() {
clearErrors()
try {
await useApi().post('/clients', payload, { toast: false }) // toast: false obligatoire
} catch (e) {
// 422 → mapping inline par champ (pas de toast) ; autre → toast de fallback.
handleApiError(e, { fallbackMessage: t('foo.error') })
}
}
```
```vue
<MalioInputText v-model="form.companyName" :error="errors.companyName" />
<MalioSelect v-model="form.siren" :error="errors.siren" />
```
Regles :
- **Toujours `{ toast: false }`** sur l'appel API qui veut un mapping inline (sinon le toast natif d'`useApi` masque le fin).
- **Cas metier specifique** (ex: 409 doublon) : `setError('champ', message)` + toast explicite **avant** de deleguer le reste a `handleApiError`. Cf. `useCategoryForm` (doublon RG-1.07).
- **Collections** (listes de sous-entites sauvees par un appel par ligne) : une erreur PAR LIGNE via un tableau `ref<Record<string, string>[]>` aligne sur l'index, peuple par `mapViolationsToRecord(error.response._data)` (util pur de `shared/utils/api.ts`). Le composant de ligne expose une prop `:errors` (`Record<string, string>`) bindee sur le `:error` de chaque champ. Cf. `ClientContactBlock` / `ClientAddressBlock` et les submits de `clients/new.vue` / `clients/[id]/edit.vue`.
**Interdit** : se contenter d'un toast global sur une 422 quand le back identifie les champs fautifs (`propertyPath`). Reimplementer un mapping `if/else` par champ a la main au lieu d'`useFormErrors` / `mapViolationsToRecord`.
## Tableaux de donnees — MalioDataTable obligatoire
Tout affichage LISTE tabulaire (donnees metier paginees, CRUD admin) doit passer par `MalioDataTable` :