Pendant du telephone secondaire (max 2). Bump @malio/layer-ui 1.7.8 (prop
addable du MalioInputEmail).
- back : colonne billing_email_secondary (migration + COMMENT + catalogue),
propriete ClientAddress (Email + Length), Callback etendu (2e email interdit
hors facturation, optionnel sinon), normalisation lowercase au Processor.
- front : draft + flag UI hasSecondaryBillingEmail, mappers, payloads, champ
MalioInputEmail :addable -> revele un 2e champ ; layout : 2e email qui coule
dans la grille et Adresse complementaire sur une colonne.
- tests back (2 emails / 2e email hors facturation) et front (payload).
Ajoute deux types d'adresse autonomes (exclusifs, comme la Prospection) :
- back : colonnes is_broker / is_distributor sur client_address (migration
modulaire, append + 2 CHECK miroir d'exclusivite + COMMENT ON COLUMN),
proprietes ClientAddress (getters Groups + SerializedName), Callback
validateExclusiveAddressTypes, validateAddressTypeRequired etendue,
catalogue des commentaires SQL mis a jour.
- front : type AddressType (+broker/distributor), drapeaux, mappers, option
du select Type d'adresse, labels i18n, payloads create/edit et lecture.
- tests back (acceptation + exclusivite + contrat de serialisation) et front.
- Boutons « Valider » toujours actifs (retrait du gating de validite) : le back renvoie les 422 mappees en rouge par champ.
- Champs requis a colonne non-nullable : la cle est omise du payload si vide (companyName, RIB, adresse) -> 422 NotBlank au lieu d'un 400 de type a la deserialisation.
- Onglet Contact : au moins un contact requis -> l'amorce vide est soumise pour declencher la 422 RG-1.05 quand aucun contact n'est nomme.
- Adresse : affichage inline des erreurs type / sites / categories, et nouvelle RG back « au moins un type d'adresse obligatoire » (Callback sur isProspect).
## ERP-66 — Utilitaires adresse/téléphone + autocomplétion BAN
### feat
- **httpExternal** : client dédié aux API publiques externes (URL absolue, sans cookie de session, timeout). Seul point d'entrée autorisé pour un `$fetch` externe (règle frontend n°4).
- **useAddressAutocomplete** : implémentation BAN (api-adresse.data.gouv.fr) — recherche ville (`type=municipality`) et adresse, mapping GeoJSON, throw en cas d'erreur/timeout (mode dégradé côté composant). La recherche d'adresse n'impose **pas** `type=housenumber` (sinon 0 résultat tant qu'aucun numéro n'est saisi) — spec-front mise à jour.
- Tests Vitest : httpExternal, useAddressAutocomplete, cas limites `formatPhoneFR`.
### fix
- **ClientAddressBlock** : la rue courante est toujours réinjectée dans les options de `MalioInputAutocomplete` (computed, miroir de `cityOptions`). Corrige le champ Adresse qui se vidait après validation / à l'édition d'une adresse existante (valeur pourtant persistée). Test de montage ajouté.
- **useClientReferentials** : libellé des sites = numéro de département (2 premiers chiffres du code postal, déjà exposé par `/sites`) au lieu du nom.
### Vérifs
- ESLint ✅ · Vitest 196/196 ✅
- Changements 100% frontend (+ doc spec).
Reviewed-on: #52
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
Stack de 2 tickets sur une branche (squash sur `develop`).
## ERP-76 (#500) — Validations d'adresse Client → 422
Les règles d'intégrité de l'onglet Adresse étaient soit non implémentées (RG-1.29), soit rejetées en 500 par les CHECK Postgres (RG-1.06/07/08/11). Elles sont désormais portées par des `Assert\Callback` applicatifs sur `ClientAddress`, qui remontent une **422 Hydra avant la base** ; les CHECK BDD restent en filet de sécurité.
- `validateProspectExclusivity` — `isProspect` exclusif de `isDelivery`/`isBilling` (RG-1.06/07/08).
- `validateBillingEmailPresence` — `billingEmail` obligatoire ssi `isBilling` (RG-1.11).
- `validateCategoryTypes` — refuse une catégorie de type DISTRIBUTEUR/COURTIER sur une adresse (RG-1.29, violation `categories`), via `CategoryInterface` (règle n°1 respectée).
Tests `ClientAddressTest` durcis (≥400 → **422 explicite**) + 4 cas RG-1.29. Cahier de test M1 mis à jour.
## ERP-68 (#486) — Fixtures démo Catalog + Commercial (dev only)
- `CategoryFixtures` (Catalog) : 12 catégories sur les 4 types.
- `ClientFixtures` (Commercial) : 14 clients couvrant les cas RG (dépendant distributeur/courtier RG-1.03, LCR + 2 RIB RG-1.13, Chèque sans RIB, multi-adresses Prospect/Livraison/Facturation RG-1.06/07/08/11, prospect seul, 3 contacts + tél. secondaire RG-1.05/1.02, archivé RG-1.22, onglet Information complet, multi-catégories M2M).
Résolution inter-modules via les seuls contrats Shared (`CategoryInterface`, `SiteProviderInterface`). Valeurs brutes normalisées par `ClientFieldNormalizer`. Données conformes aux CHECK BDD **et** aux validators ERP-76. Idempotentes (lookup `companyName`/`name`). **Garde-fou** : les deux fixtures sont no-op en environnement `test` (la base de test reste un socle minimal ; pas de pollution des comptages ni des cleanups FK).
## Bonus — idempotence fixtures
`AppFixtures` (admin/alice/bob) rendu idempotent via lookup par username : `doctrine:fixtures:load --append` est désormais rejouable sans erreur sur tout le jeu de fixtures.
## Vérifications
- `make test` : **436/436 vert** (0 échec/erreur).
- `make php-cs-fixer-allow-risky` OK.
- `make db-reset` charge sans erreur ; 2 runs `--append` consécutifs = idempotent (0 doublon ; 7 users / 14 clients / 12 catégories stables).
- `admin/admin` intact.
---------
Co-authored-by: Matthieu <contact@malio.fr>
Reviewed-on: #41
Co-authored-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>
Co-committed-by: THOLOT DECHENE Matthieu <matthieu@yuno.malio.fr>