Correctifs écran Client (ERP-115) #76

Merged
tristan merged 13 commits from feature/ERP-115-correctifs-front into develop 2026-06-08 14:40:18 +00:00
4 changed files with 93 additions and 5 deletions
Showing only changes of commit 8d80781e8c - Show all commits
@@ -41,6 +41,7 @@
@update:model-value="(v: (string | number)[]) => main.categoryIris = v.map(String)"
/>
<MalioSelect
v-if="showRelationAndTriage"
:model-value="main.relationType"
:options="relationOptions"
:label="t('commercial.clients.form.main.relation')"
@@ -49,7 +50,7 @@
@update:model-value="onRelationChange"
/>
<MalioSelect
v-if="main.relationType === 'courtier'"
v-if="showRelationAndTriage && main.relationType === 'courtier'"
:model-value="main.brokerIri"
:options="brokerOptions"
:label="t('commercial.clients.form.main.brokerName')"
@@ -59,7 +60,7 @@
@update:model-value="(v: string | number | null) => main.brokerIri = v === null ? null : String(v)"
/>
<MalioSelect
v-if="main.relationType === 'distributeur'"
v-if="showRelationAndTriage && main.relationType === 'distributeur'"
:model-value="main.distributorIri"
:options="distributorOptions"
:label="t('commercial.clients.form.main.distributorName')"
@@ -69,6 +70,7 @@
@update:model-value="(v: string | number | null) => main.distributorIri = v === null ? null : String(v)"
/>
<MalioCheckbox
v-if="showRelationAndTriage"
v-model="main.triageService"
:label="t('commercial.clients.form.main.triageService')"
group-class="self-center"
@@ -381,7 +383,7 @@
</template>
<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue'
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useClient } from '~/modules/commercial/composables/useClient'
import { useClientReferentials, type CategoryOption, type RefOption } from '~/modules/commercial/composables/useClientReferentials'
import { useClientFormErrors } from '~/modules/commercial/composables/useClientFormErrors'
@@ -423,6 +425,7 @@ import {
isRibBlank,
isRibComplete,
isRibRequiredForPaymentType,
showsRelationAndTriageFields,
} from '~/modules/commercial/utils/clientFormRules'
import {
emptyAddress,
@@ -554,6 +557,28 @@ const relationOptions = computed<RefOption[]>(() => [
{ value: 'courtier', label: t('commercial.clients.form.main.relationBroker') },
])
// Codes des categories selectionnees (resolus depuis l'union referentiel + embed).
const selectedCategoryCodes = computed(() =>
main.categoryIris
.map(iri => mainCategoryOptions.value.find(c => c.value === iri)?.code)
.filter((code): code is string => code !== undefined),
)
// « Relation » + « Prestation de triage » masques par defaut, reveles des qu'une
// categorie ordinaire (autre que Distributeur/Courtier) est selectionnee.
const showRelationAndTriage = computed(() => showsRelationAndTriageFields(selectedCategoryCodes.value))
// Masquer ces champs reinitialise leurs valeurs : pas de relation/triage fantome
// soumis pour un client Distributeur/Courtier.
watch(showRelationAndTriage, (visible) => {
if (!visible) {
main.relationType = null
main.distributorIri = null
main.brokerIri = null
main.triageService = false
}
})
// Distributeur / courtier : referentiel charge a la demande UNION valeur courante.
const currentDistributorOption = computed<RefOption[]>(() => {
const d = client.value?.distributor
@@ -35,6 +35,7 @@
@update:model-value="(v: (string | number)[]) => main.categoryIris = v.map(String)"
/>
<MalioSelect
v-if="showRelationAndTriage"
:model-value="main.relationType"
:options="relationOptions"
:label="t('commercial.clients.form.main.relation')"
@@ -43,7 +44,7 @@
@update:model-value="onRelationChange"
/>
<MalioSelect
v-if="main.relationType === 'courtier'"
v-if="showRelationAndTriage && main.relationType === 'courtier'"
:model-value="main.brokerIri"
:options="referentials.brokers.value"
:label="t('commercial.clients.form.main.brokerName')"
@@ -53,7 +54,7 @@
@update:model-value="(v: string | number | null) => main.brokerIri = v === null ? null : String(v)"
/>
<MalioSelect
v-if="main.relationType === 'distributeur'"
v-if="showRelationAndTriage && main.relationType === 'distributeur'"
:model-value="main.distributorIri"
:options="referentials.distributors.value"
:label="t('commercial.clients.form.main.distributorName')"
@@ -63,6 +64,7 @@
@update:model-value="(v: string | number | null) => main.distributorIri = v === null ? null : String(v)"
/>
<MalioCheckbox
v-if="showRelationAndTriage"
v-model="main.triageService"
:label="t('commercial.clients.form.main.triageService')"
group-class="self-center"
@@ -397,6 +399,7 @@ import {
isRibBlank,
isRibComplete,
isRibRequiredForPaymentType,
showsRelationAndTriageFields,
} from '~/modules/commercial/utils/clientFormRules'
import {
emptyAddress,
@@ -489,6 +492,28 @@ const relationOptions = computed<RefOption[]>(() => [
{ value: 'courtier', label: t('commercial.clients.form.main.relationBroker') },
])
// Codes des categories selectionnees (resolus depuis les IRI du brouillon).
const selectedCategoryCodes = computed(() =>
main.categoryIris
.map(iri => referentials.categories.value.find(c => c.value === iri)?.code)
.filter((code): code is string => code !== undefined),
)
// « Relation » + « Prestation de triage » masques par defaut, reveles des qu'une
// categorie ordinaire (autre que Distributeur/Courtier) est selectionnee.
const showRelationAndTriage = computed(() => showsRelationAndTriageFields(selectedCategoryCodes.value))
// Masquer ces champs reinitialise leurs valeurs : pas de relation/triage fantome
// soumis pour un client Distributeur/Courtier.
watch(showRelationAndTriage, (visible) => {
if (!visible) {
main.relationType = null
main.distributorIri = null
main.brokerIri = null
main.triageService = false
}
})
// Validation du formulaire principal (gate le bouton « Valider ») :
// - companyName / >= 1 categorie obligatoires ;
// - relation Distributeur/Courtier optionnelle, mais le nom correspondant
@@ -18,6 +18,7 @@ import {
isRibBlank,
isRibComplete,
isRibRequiredForPaymentType,
showsRelationAndTriageFields,
type AddressValidityDraft,
type ContactDraft,
type ContactFillableDraft,
@@ -276,6 +277,23 @@ describe('hasAllRequiredAccountingFields (RG-1.30)', () => {
})
})
describe('showsRelationAndTriageFields (affichage Relation + Triage selon categorie)', () => {
it('faux par defaut (aucune categorie selectionnee)', () => {
expect(showsRelationAndTriageFields([])).toBe(false)
})
it('faux si seules des categories Distributeur / Courtier sont selectionnees', () => {
expect(showsRelationAndTriageFields(['DISTRIBUTEUR'])).toBe(false)
expect(showsRelationAndTriageFields(['COURTIER'])).toBe(false)
expect(showsRelationAndTriageFields(['DISTRIBUTEUR', 'COURTIER'])).toBe(false)
})
it('vrai des qu\'une categorie ordinaire est selectionnee', () => {
expect(showsRelationAndTriageFields(['CLIENT'])).toBe(true)
expect(showsRelationAndTriageFields(['DISTRIBUTEUR', 'CLIENT'])).toBe(true)
})
})
describe('hasAtLeastOneInformationField (pas de validation a vide a la creation)', () => {
const blank = {
description: null,
@@ -53,6 +53,26 @@ export function buildClientFormTabKeys(
return keys
}
/**
* Codes de categorie « intermediaire » : un client dont la categorie est
* Distributeur ou Courtier n'a ni relation amont (il EST le distributeur /
* courtier) ni prestation de triage. Sert a conditionner l'affichage des champs
* « Relation » et « Prestation de triage » du formulaire principal.
*/
export const DISTRIBUTOR_BROKER_CATEGORY_CODES = ['DISTRIBUTEUR', 'COURTIER'] as const
/**
* Vrai des qu'au moins une categorie « ordinaire » (autre que Distributeur /
* Courtier) est selectionnee. Les champs « Relation » (depend du distributeur /
* courtier) et « Prestation de triage » du formulaire principal sont masques par
* defaut et reveles uniquement dans ce cas.
*/
export function showsRelationAndTriageFields(selectedCategoryCodes: string[]): boolean {
return selectedCategoryCodes.some(
code => !(DISTRIBUTOR_BROKER_CATEGORY_CODES as readonly string[]).includes(code),
)
}
/** Sous-ensemble d'un contact necessaire aux regles de nommage (RG-1.05/1.14). */
export interface ContactDraft {
firstName: string | null