feat(front) : util httpExternal + autocomplete adresse BAN (ERP-66) (#52)
Auto Tag Develop / tag (push) Successful in 7s

## 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>
This commit was merged in pull request #52.
This commit is contained in:
2026-06-03 14:02:14 +00:00
committed by Autin
parent f406a598eb
commit 912280d24e
19 changed files with 590 additions and 87 deletions
@@ -177,12 +177,14 @@ class ClientAddress implements TimestampableInterface, BlamableInterface
#[Groups(['client_address:read', 'client_address:write'])]
private Collection $contacts;
// Au moins une categorie est obligatoire sur une adresse (spec-front § Adresse).
// RG-1.29 : categories de code DISTRIBUTEUR/COURTIER interdites (validateCategoryCodes).
/** @var Collection<int, CategoryInterface> */
#[ORM\ManyToMany(targetEntity: CategoryInterface::class)]
#[ORM\JoinTable(name: 'client_address_category')]
#[ORM\JoinColumn(name: 'client_address_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
#[ORM\InverseJoinColumn(name: 'category_id', referencedColumnName: 'id', onDelete: 'RESTRICT')]
#[Assert\Count(min: 1, minMessage: 'Au moins une catégorie est obligatoire.')]
#[Groups(['client_address:read', 'client_address:write'])]
private Collection $categories;