f4313d1f3d
- ClientAddressBlock : la rue courante est toujours reinjectee dans les options de MalioInputAutocomplete (computed, miroir de cityOptions). Sinon, des que la liste de suggestions BAN est vide (remontage apres validation, edition d'une adresse existante), le composant ne resolvait plus la valeur liee et affichait un champ vide alors que la donnee etait bien persistee. Test de montage ajoute. - useClientReferentials : le libelle des sites = numero de departement (2 premiers chiffres du code postal, deja expose par /sites) au lieu du nom.
152 lines
5.8 KiB
TypeScript
152 lines
5.8 KiB
TypeScript
import { ref } from 'vue'
|
|
|
|
/**
|
|
* Charge les referentiels (listes courtes) alimentant les selects de l'ecran
|
|
* « Ajouter un client » : categories, sites, modes de TVA, delais et types de
|
|
* reglement, banques, et les listes distributeurs / courtiers.
|
|
*
|
|
* Toutes les collections sont recuperees en entier via l'echappatoire prevue
|
|
* `?pagination=false` (referentiels de quelques dizaines d'entrees max), avec
|
|
* l'en-tete `Accept: application/ld+json` impose par API Platform 4 pour obtenir
|
|
* l'enveloppe Hydra (`member`). Les valeurs d'option sont les IRI Hydra (`@id`)
|
|
* pour pouvoir etre renvoyees telles quelles dans les payloads POST/PATCH
|
|
* (relations ManyToOne / ManyToMany).
|
|
*
|
|
* Etat 100 % local a l'instance (refs) — aucune persistance URL.
|
|
*/
|
|
|
|
/** Option generique au format attendu par MalioSelect / MalioSelectCheckbox ({ label, value }). */
|
|
export interface RefOption {
|
|
value: string
|
|
label: string
|
|
}
|
|
|
|
/** Option de type de reglement enrichie de son code stable (RG-1.12 / RG-1.13). */
|
|
export interface PaymentTypeOption extends RefOption {
|
|
code: string
|
|
}
|
|
|
|
/** Option de categorie enrichie de son code stable (filtrage RG-1.29 cote adresse). */
|
|
export interface CategoryOption extends RefOption {
|
|
code: string
|
|
}
|
|
|
|
/** Option de client (distributeur / courtier) — value = IRI du client lie. */
|
|
export type ClientOption = RefOption
|
|
|
|
interface HydraMember {
|
|
'@id': string
|
|
}
|
|
|
|
interface CategoryMember extends HydraMember {
|
|
code: string
|
|
name: string
|
|
}
|
|
|
|
interface SiteMember extends HydraMember {
|
|
name: string
|
|
postalCode: string
|
|
}
|
|
|
|
interface ReferentialMember extends HydraMember {
|
|
code: string
|
|
label: string
|
|
}
|
|
|
|
interface ClientMember extends HydraMember {
|
|
companyName: string
|
|
}
|
|
|
|
const LD_JSON_HEADERS = { Accept: 'application/ld+json' }
|
|
|
|
export function useClientReferentials() {
|
|
const api = useApi()
|
|
|
|
const categories = ref<CategoryOption[]>([])
|
|
const sites = ref<RefOption[]>([])
|
|
const tvaModes = ref<RefOption[]>([])
|
|
const paymentDelays = ref<RefOption[]>([])
|
|
const paymentTypes = ref<PaymentTypeOption[]>([])
|
|
const banks = ref<RefOption[]>([])
|
|
const distributors = ref<ClientOption[]>([])
|
|
const brokers = ref<ClientOption[]>([])
|
|
|
|
/** 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 communs (hors distributeurs/courtiers,
|
|
* charges a la demande selon la relation choisie).
|
|
*
|
|
* Chargement RESILIENT (Promise.allSettled) : chaque referentiel est isole.
|
|
* Necessaire pour les roles metier qui n'ont pas toutes les permissions de
|
|
* lecture — ex. Compta a `commercial.clients.view` (donc /tva_modes, /banks...
|
|
* accessibles) mais PAS `catalog.categories.view` ni `sites.view` : sans
|
|
* isolation, le 403 sur /categories ferait echouer tout le bloc et viderait
|
|
* les selects comptables dont Compta a besoin sur l'ecran de modification.
|
|
* Un referentiel en echec reste simplement vide (l'ecran d'edition complete
|
|
* l'affichage des valeurs courantes depuis l'embed du detail client).
|
|
*/
|
|
async function loadCommon(): Promise<void> {
|
|
await Promise.allSettled([
|
|
fetchAll<CategoryMember>('/categories')
|
|
.then((cats) => { categories.value = cats.map(c => ({ value: c['@id'], label: c.name, code: c.code })) }),
|
|
fetchAll<SiteMember>('/sites')
|
|
// Libelle = numero de departement (2 premiers chiffres du code
|
|
// postal du site), ex: 86100 -> « 86 ». Le code postal est deja
|
|
// expose par /sites (groupe site:read) — aucune colonne a ajouter.
|
|
.then((sitesList) => { sites.value = sitesList.map(s => ({ value: s['@id'], label: (s.postalCode ?? '').slice(0, 2) })) }),
|
|
fetchAll<ReferentialMember>('/tva_modes')
|
|
.then((tva) => { tvaModes.value = tva.map(t => ({ value: t['@id'], label: t.label })) }),
|
|
fetchAll<ReferentialMember>('/payment_delays')
|
|
.then((delays) => { paymentDelays.value = delays.map(d => ({ value: d['@id'], label: d.label })) }),
|
|
fetchAll<ReferentialMember>('/payment_types')
|
|
.then((types) => { paymentTypes.value = types.map(t => ({ value: t['@id'], label: t.label, code: t.code })) }),
|
|
fetchAll<ReferentialMember>('/banks')
|
|
.then((banksList) => { banks.value = banksList.map(b => ({ value: b['@id'], label: b.label })) }),
|
|
])
|
|
}
|
|
|
|
/** Liste des clients pouvant etre choisis comme distributeur (code DISTRIBUTEUR). */
|
|
async function loadDistributors(): Promise<void> {
|
|
if (distributors.value.length > 0) {
|
|
return
|
|
}
|
|
const clients = await fetchAll<ClientMember>('/clients', { categoryCode: 'DISTRIBUTEUR' })
|
|
distributors.value = clients.map(c => ({ value: c['@id'], label: c.companyName }))
|
|
}
|
|
|
|
/** Liste des clients pouvant etre choisis comme courtier (code COURTIER). */
|
|
async function loadBrokers(): Promise<void> {
|
|
if (brokers.value.length > 0) {
|
|
return
|
|
}
|
|
const clients = await fetchAll<ClientMember>('/clients', { categoryCode: 'COURTIER' })
|
|
brokers.value = clients.map(c => ({ value: c['@id'], label: c.companyName }))
|
|
}
|
|
|
|
return {
|
|
categories,
|
|
sites,
|
|
tvaModes,
|
|
paymentDelays,
|
|
paymentTypes,
|
|
banks,
|
|
distributors,
|
|
brokers,
|
|
loadCommon,
|
|
loadDistributors,
|
|
loadBrokers,
|
|
}
|
|
}
|