feat(commercial) : referentiel pays (country) en base + branchement front (ERP-116)
Cree la table country (referentiel statique : code ISO alpha-2, name, position) seedee avec 6 pays (France, Allemagne, Belgique, Espagne, Italie, Royaume-Uni), exposee en lecture seule via /api/countries (GetCollection + Get, gating aligne sur Bank). Perimetre minimal volontaire : aucune longueur bancaire/fiscale a ce stade (iteration ulterieure du ticket). Front : la liste des pays jusqu'ici codee en dur dans les 3 ecrans clients est remplacee par le referentiel charge via useClientReferentials (value = nom du pays, l'adresse continuant de stocker country en chaine libre : pas de FK ni de migration de donnees). Consultation : options derivees de l'embed. Garde-fous : country ajoute a ColumnCommentsCatalog + whitelist EntitiesAreTimestampableBlamableTest ; tests API dedies (200/seed/405/403/401).
This commit is contained in:
@@ -30,6 +30,10 @@ describe('useClientReferentials.loadCommon (resilience ERP-102)', () => {
|
||||
if (url === '/sites') {
|
||||
return Promise.resolve({ member: [{ '@id': '/api/sites/1', name: 'Chatellerault', postalCode: '86100' }] })
|
||||
}
|
||||
if (url === '/countries') {
|
||||
// Pays : value === label === name (l'adresse stocke le nom).
|
||||
return Promise.resolve({ member: [{ '@id': '/api/countries/1', code: 'FR', name: 'France' }] })
|
||||
}
|
||||
return Promise.resolve({
|
||||
member: [{ '@id': '/api/x/1', code: 'X', label: 'Libelle X' }],
|
||||
})
|
||||
@@ -44,6 +48,8 @@ describe('useClientReferentials.loadCommon (resilience ERP-102)', () => {
|
||||
expect(refs.sites.value).toEqual([{ value: '/api/sites/1', label: '86' }])
|
||||
expect(refs.tvaModes.value).toEqual([{ value: '/api/x/1', label: 'Libelle X' }])
|
||||
expect(refs.banks.value).toEqual([{ value: '/api/x/1', label: 'Libelle X' }])
|
||||
// Pays : value = nom du pays (et non l'IRI).
|
||||
expect(refs.countries.value).toEqual([{ value: 'France', label: 'France' }])
|
||||
|
||||
// Seul le select en echec reste vide.
|
||||
expect(refs.categories.value).toEqual([])
|
||||
|
||||
@@ -3,7 +3,7 @@ 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.
|
||||
* reglement, banques, pays, 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
|
||||
@@ -57,6 +57,11 @@ interface ClientMember extends HydraMember {
|
||||
companyName: string
|
||||
}
|
||||
|
||||
interface CountryMember extends HydraMember {
|
||||
code: string
|
||||
name: string
|
||||
}
|
||||
|
||||
const LD_JSON_HEADERS = { Accept: 'application/ld+json' }
|
||||
|
||||
export function useClientReferentials() {
|
||||
@@ -68,6 +73,7 @@ export function useClientReferentials() {
|
||||
const paymentDelays = ref<RefOption[]>([])
|
||||
const paymentTypes = ref<PaymentTypeOption[]>([])
|
||||
const banks = ref<RefOption[]>([])
|
||||
const countries = ref<RefOption[]>([])
|
||||
const distributors = ref<ClientOption[]>([])
|
||||
const brokers = ref<ClientOption[]>([])
|
||||
|
||||
@@ -116,6 +122,12 @@ export function useClientReferentials() {
|
||||
.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 })) }),
|
||||
// Pays (ERP-116) : la valeur d'option est le NOM du pays (et non l'IRI),
|
||||
// car l'adresse stocke `country` en chaine libre (« France »...). On
|
||||
// conserve ainsi la compatibilite avec les adresses existantes sans FK
|
||||
// ni migration de donnees a ce stade. value === label.
|
||||
fetchAll<CountryMember>('/countries')
|
||||
.then((list) => { countries.value = list.map(c => ({ value: c.name, label: c.name })) }),
|
||||
])
|
||||
}
|
||||
|
||||
@@ -144,6 +156,7 @@ export function useClientReferentials() {
|
||||
paymentDelays,
|
||||
paymentTypes,
|
||||
banks,
|
||||
countries,
|
||||
distributors,
|
||||
brokers,
|
||||
loadCommon,
|
||||
|
||||
@@ -554,10 +554,10 @@ const contactOptions = computed<RefOption[]>(() =>
|
||||
})),
|
||||
)
|
||||
|
||||
const countryOptions: RefOption[] = [
|
||||
{ value: 'France', label: 'France' },
|
||||
{ value: 'Espagne', label: 'Espagne' },
|
||||
]
|
||||
// Pays : referentiel `country` charge via l'API (ERP-116), en remplacement de
|
||||
// l'ancienne liste codee en dur. Valeur = nom du pays (l'adresse stocke
|
||||
// `country` en chaine libre, donc value === label).
|
||||
const countryOptions = computed<RefOption[]>(() => referentials.countries.value)
|
||||
|
||||
const relationOptions = computed<RefOption[]>(() => [
|
||||
{ value: 'distributeur', label: t('commercial.clients.form.main.relationDistributor') },
|
||||
|
||||
@@ -384,10 +384,18 @@ const relationOptions = computed<SelectOption[]>(() => [
|
||||
{ value: 'courtier', label: t('commercial.clients.form.main.relationBroker') },
|
||||
])
|
||||
|
||||
const countryOptions: SelectOption[] = [
|
||||
{ value: 'France', label: 'France' },
|
||||
{ value: 'Espagne', label: 'Espagne' },
|
||||
]
|
||||
// Pays (ERP-116) : options construites depuis l'EMBED des adresses (jamais via
|
||||
// GET /countries, sur le meme principe que les autres selects de consultation
|
||||
// — en 403 pour les roles metier non-admin). Valeur = nom du pays stocke tel
|
||||
// quel dans l'adresse, donc value === label ; suffit a afficher le libelle en
|
||||
// lecture seule.
|
||||
const countryOptions = computed<SelectOption[]>(() =>
|
||||
[...new Set(
|
||||
(client.value?.addresses ?? [])
|
||||
.map(a => a.country)
|
||||
.filter((c): c is string => !!c),
|
||||
)].map(c => ({ value: c, label: c })),
|
||||
)
|
||||
|
||||
// Selects comptables : libelle issu de l'embed (option unique ou vide).
|
||||
const tvaModeOptions = computed(() => referentialOptionOf(client.value?.tvaMode))
|
||||
|
||||
@@ -783,11 +783,10 @@ const contactOptions = computed<RefOption[]>(() =>
|
||||
})),
|
||||
)
|
||||
|
||||
// Pays disponibles (France preselectionnee par defaut sur chaque adresse).
|
||||
const countryOptions: RefOption[] = [
|
||||
{ value: 'France', label: 'France' },
|
||||
{ value: 'Espagne', label: 'Espagne' },
|
||||
]
|
||||
// Pays disponibles : referentiel `country` charge via l'API (ERP-116), en
|
||||
// remplacement de l'ancienne liste codee en dur. France reste preselectionnee
|
||||
// par defaut sur chaque adresse (cf. valeur initiale du draft d'adresse).
|
||||
const countryOptions = computed<RefOption[]>(() => referentials.countries.value)
|
||||
|
||||
// Type d'adresse (Select) obligatoire + RG-1.10 (>= 1 site) + RG-1.11 (email
|
||||
// facturation si Facturation) sur chaque adresse.
|
||||
|
||||
Reference in New Issue
Block a user