3d4ae391fe
Auto Tag Develop / tag (push) Successful in 7s
Empilée sur ERP-142 (#104). ## Périmètre ERP-143 Onglet **Adresse** de l'écran `/providers/new` — saisie multi-adresses (blocs ajoutables) via la sous-ressource addresses. - **`ProviderAddressBlock.vue`** (miroir `SupplierAddressBlock` **simplifié**) : Sélecteur de sites (≥1, RG-3.05) / Catégories (PRESTATAIRE, RG-3.09) / Contact(s) rattaché(s) (depuis l'onglet Contact) / Pays (défaut France) / Code postal / Ville / Adresse (autocomplete BAN) / Complément. **Pas** de type d'adresse, **pas** de bennes, **pas** de triage (différence M2). - **RG-3.06** : `useAddressAutocomplete()` **réutilisé tel quel** — CP → liste des villes (BAN) ; cas dégradé (API down) → ville/adresse en saisie libre + toast unique. - **`useProviderForm`** étendu : `addresses`, `canAddAddress` (RG-3.05/3.09), `add/removeAddress`, `submitAddresses` (POST `/providers/{id}/addresses` + PATCH `/provider_addresses/{id}`, groupe `provider:write:addresses`), erreurs 422 **par ligne**. - **`useProviderReferentials`** : ajout des pays (`/countries`) pour le select Pays. - Helpers purs `utils/forms/providerAddress.ts` (`isProviderAddressValid`, `buildProviderAddressPayload` — relations en IRI, requis vides omis au POST). - « + Nouvelle adresse » / Supprimer (modal) / « Valider ». i18n `technique.providers.form.address` + `confirmDelete.address`. ## Conformité - `useApi()` only ; `Malio*` only ; aucun texte FR en dur ; `useAddressAutocomplete` non réécrit ; pas d'import inter-module (helpers ré-implémentés côté Technique, règle ABSOLUE n°1). ## Vérifications - Vitest : 436/436 (18 nouveaux : helpers adresse, bloc — BAN dégradé/allow-create/mapping erreurs, workflow adresses POST/PATCH/422 par ligne). - ESLint : OK. - `nuxi typecheck` : 0 erreur sur les fichiers source du ticket. - Golden path navigateur : page compile, onglet Contact OK. NB : l'onglet Adresse est gaté derrière la validation principal+contact (multiselect `Malio` non pilotable en a11y) — couvert par tests unitaires (montage + BAN + mapping) + typecheck. Reviewed-on: #105 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
98 lines
3.6 KiB
TypeScript
98 lines
3.6 KiB
TypeScript
import { ref } from 'vue'
|
|
|
|
/**
|
|
* Charge les referentiels (listes courtes) alimentant les selects du formulaire
|
|
* principal de l'ecran « Ajouter un prestataire » (M3 Technique, ERP-141) :
|
|
* categories (type PRESTATAIRE) et sites (86 / 17 / 82).
|
|
*
|
|
* Miroir reduit de `useSupplierReferentials` (M2) : a ce stade (formulaire
|
|
* principal) seuls categories + sites sont necessaires. Les referentiels
|
|
* comptables (modes de TVA, delais/types de reglement, banques) seront charges
|
|
* par l'onglet Comptabilite (ERP-144).
|
|
*
|
|
* Toutes les collections sont recuperees en entier via l'echappatoire prevue
|
|
* `?pagination=false` (referentiels de quelques entrees), avec l'en-tete
|
|
* `Accept: application/ld+json` impose par API Platform 4 pour obtenir l'enveloppe
|
|
* Hydra (`member`). La valeur d'option est l'IRI Hydra (`@id`), renvoyee telle
|
|
* quelle dans le payload POST (relations M2M).
|
|
*
|
|
* Chargement RESILIENT (Promise.allSettled) : chaque referentiel est isole ; un
|
|
* echec (permission manquante, reseau) laisse simplement la liste vide.
|
|
*
|
|
* Etat 100 % local a l'instance (refs) — aucune persistance URL.
|
|
*/
|
|
|
|
/** Option generique au format attendu par MalioSelect / MalioSelectCheckbox. */
|
|
export interface RefOption {
|
|
value: string
|
|
label: string
|
|
}
|
|
|
|
interface HydraMember {
|
|
'@id': string
|
|
}
|
|
|
|
interface CategoryMember extends HydraMember {
|
|
code: string
|
|
name: string
|
|
}
|
|
|
|
interface SiteMember extends HydraMember {
|
|
name: string
|
|
postalCode: string
|
|
}
|
|
|
|
interface CountryMember extends HydraMember {
|
|
code: string
|
|
name: string
|
|
}
|
|
|
|
const LD_JSON_HEADERS = { Accept: 'application/ld+json' }
|
|
|
|
export function useProviderReferentials() {
|
|
const api = useApi()
|
|
|
|
const categories = ref<RefOption[]>([])
|
|
const sites = ref<RefOption[]>([])
|
|
const countries = ref<RefOption[]>([])
|
|
|
|
/** Recupere une collection complete (pagination desactivee) en Hydra. */
|
|
async function fetchAll<T extends HydraMember>(
|
|
url: string,
|
|
query: Record<string, string | string[]> = {},
|
|
): Promise<T[]> {
|
|
const res = await api.get<{ member?: T[] }>(
|
|
url,
|
|
{ pagination: 'false', ...query },
|
|
{ headers: LD_JSON_HEADERS, toast: false },
|
|
)
|
|
return res.member ?? []
|
|
}
|
|
|
|
/** Charge en parallele les referentiels du formulaire principal (categories + sites). */
|
|
async function loadMain(): Promise<void> {
|
|
await Promise.allSettled([
|
|
// RG-3.09 : un prestataire ne porte que des categories de type
|
|
// PRESTATAIRE -> filtre cote API. Libelle affiche = `name`.
|
|
fetchAll<CategoryMember>('/categories', { typeCode: 'PRESTATAIRE' })
|
|
.then((cats) => { categories.value = cats.map(c => ({ value: c['@id'], label: c.name })) }),
|
|
// Sites (RG-3.03) : libelle = numero de departement (2 premiers chiffres
|
|
// du code postal du site), ex: 86100 -> « 86 », 17400 -> « 17 ».
|
|
fetchAll<SiteMember>('/sites')
|
|
.then((sitesList) => { sites.value = sitesList.map(s => ({ value: s['@id'], label: (s.postalCode ?? '').slice(0, 2) })) }),
|
|
// Pays (ERP-116) : la valeur d'option est le NOM du pays (l'adresse stocke
|
|
// `country` en chaine libre, « France »...). value === label. Aligne sur
|
|
// les ecrans client/fournisseur. Sert le select Pays de l'onglet Adresse.
|
|
fetchAll<CountryMember>('/countries')
|
|
.then((list) => { countries.value = list.map(c => ({ value: c.name, label: c.name })) }),
|
|
])
|
|
}
|
|
|
|
return {
|
|
categories,
|
|
sites,
|
|
countries,
|
|
loadMain,
|
|
}
|
|
}
|