fix(commercial) : corrections formulaire client (ajout de bloc, onglet Information)
- Boutons « ajouter » Adresse/RIB desactives tant que le dernier bloc n'est pas valide (predicats isAddressValid/isRibComplete, reutilises par la validation d'onglet). - Onglet Information : bouton Valider desactive si aucun champ rempli (pas de validation a vide) — creation uniquement, l'edition garde la possibilite de tout vider. - Onglet Contact accessible des la creation du client (onglet Information facultatif).
This commit is contained in:
@@ -205,6 +205,7 @@
|
|||||||
icon-name="mdi:add-bold"
|
icon-name="mdi:add-bold"
|
||||||
icon-position="left"
|
icon-position="left"
|
||||||
:label="t('commercial.clients.form.address.add')"
|
:label="t('commercial.clients.form.address.add')"
|
||||||
|
:disabled="!canAddAddress"
|
||||||
@click="addAddress"
|
@click="addAddress"
|
||||||
/>
|
/>
|
||||||
<MalioButton
|
<MalioButton
|
||||||
@@ -334,6 +335,7 @@
|
|||||||
icon-name="mdi:add-bold"
|
icon-name="mdi:add-bold"
|
||||||
icon-position="left"
|
icon-position="left"
|
||||||
:label="t('commercial.clients.form.accounting.addRib')"
|
:label="t('commercial.clients.form.accounting.addRib')"
|
||||||
|
:disabled="!canAddRib"
|
||||||
@click="addRib"
|
@click="addRib"
|
||||||
/>
|
/>
|
||||||
<MalioButton
|
<MalioButton
|
||||||
@@ -410,15 +412,16 @@ import {
|
|||||||
type MainFormDraft,
|
type MainFormDraft,
|
||||||
} from '~/modules/commercial/utils/clientEdit'
|
} from '~/modules/commercial/utils/clientEdit'
|
||||||
import {
|
import {
|
||||||
addressTypeFromFlags,
|
|
||||||
buildClientFormTabKeys,
|
buildClientFormTabKeys,
|
||||||
hasAllRequiredAccountingFields,
|
hasAllRequiredAccountingFields,
|
||||||
hasAtLeastOneValidContact,
|
hasAtLeastOneValidContact,
|
||||||
|
isAddressValid,
|
||||||
isBankRequiredForPaymentType,
|
isBankRequiredForPaymentType,
|
||||||
isBillingEmailRequired,
|
isBillingEmailRequired,
|
||||||
isContactBlank,
|
isContactBlank,
|
||||||
isContactNamed,
|
isContactNamed,
|
||||||
isRibBlank,
|
isRibBlank,
|
||||||
|
isRibComplete,
|
||||||
isRibRequiredForPaymentType,
|
isRibRequiredForPaymentType,
|
||||||
} from '~/modules/commercial/utils/clientFormRules'
|
} from '~/modules/commercial/utils/clientFormRules'
|
||||||
import {
|
import {
|
||||||
@@ -787,18 +790,17 @@ async function submitContacts(): Promise<void> {
|
|||||||
|
|
||||||
// ── Onglet Adresse ───────────────────────────────────────────────────────────
|
// ── Onglet Adresse ───────────────────────────────────────────────────────────
|
||||||
const canValidateAddresses = computed(() =>
|
const canValidateAddresses = computed(() =>
|
||||||
addresses.value.length > 0
|
addresses.value.length > 0 && addresses.value.every(isAddressValid),
|
||||||
&& addresses.value.every((a) => {
|
|
||||||
const filledBillingEmail = a.billingEmail !== null && a.billingEmail.trim() !== ''
|
|
||||||
return addressTypeFromFlags(a) !== null
|
|
||||||
&& a.siteIris.length >= 1
|
|
||||||
&& a.categoryIris.length >= 1
|
|
||||||
&& (!isBillingEmailRequired(a) || filledBillingEmail)
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// « + Adresse » desactive tant que la derniere adresse n'est pas valide.
|
||||||
|
const canAddAddress = computed(() => {
|
||||||
|
const last = addresses.value[addresses.value.length - 1]
|
||||||
|
return last !== undefined && isAddressValid(last)
|
||||||
|
})
|
||||||
|
|
||||||
function addAddress(): void {
|
function addAddress(): void {
|
||||||
addresses.value.push(emptyAddress())
|
if (canAddAddress.value) addresses.value.push(emptyAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
function askRemoveAddress(index: number): void {
|
function askRemoveAddress(index: number): void {
|
||||||
@@ -875,20 +877,21 @@ function onPaymentTypeChange(value: string | number | null): void {
|
|||||||
if (!isBankRequired.value) accounting.bankIri = null
|
if (!isBankRequired.value) accounting.bankIri = null
|
||||||
}
|
}
|
||||||
|
|
||||||
function ribIsComplete(rib: { label: string | null, bic: string | null, iban: string | null }): boolean {
|
|
||||||
const filled = (v: string | null) => v !== null && v.trim() !== ''
|
|
||||||
return filled(rib.label) && filled(rib.bic) && filled(rib.iban)
|
|
||||||
}
|
|
||||||
|
|
||||||
const canValidateAccounting = computed(() => {
|
const canValidateAccounting = computed(() => {
|
||||||
if (!hasAllRequiredAccountingFields(accounting)) return false
|
if (!hasAllRequiredAccountingFields(accounting)) return false
|
||||||
if (isBankRequired.value && accounting.bankIri === null) return false
|
if (isBankRequired.value && accounting.bankIri === null) return false
|
||||||
if (isRibRequired.value && !ribs.value.some(ribIsComplete)) return false
|
if (isRibRequired.value && !ribs.value.some(isRibComplete)) return false
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// « + RIB » desactive tant que le dernier bloc RIB n'est pas complet.
|
||||||
|
const canAddRib = computed(() => {
|
||||||
|
const last = ribs.value[ribs.value.length - 1]
|
||||||
|
return last !== undefined && isRibComplete(last)
|
||||||
|
})
|
||||||
|
|
||||||
function addRib(): void {
|
function addRib(): void {
|
||||||
ribs.value.push(emptyRib())
|
if (canAddRib.value) ribs.value.push(emptyRib())
|
||||||
}
|
}
|
||||||
|
|
||||||
function askRemoveRib(index: number): void {
|
function askRemoveRib(index: number): void {
|
||||||
|
|||||||
@@ -134,13 +134,15 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isValidated('information')" class="mt-12 flex justify-center">
|
<div v-if="!isValidated('information')" class="mt-12 flex justify-center">
|
||||||
<!-- Desactive tant que le client n'est pas cree : evite un PATCH
|
<!-- Desactive tant que le client n'est pas cree (evite un PATCH
|
||||||
avant le POST si l'utilisateur clique trop tot (le panneau
|
avant le POST si clic trop tot, Information etant l'onglet
|
||||||
Information est l'onglet actif par defaut). -->
|
actif par defaut) OU si aucun champ n'est rempli : onglet
|
||||||
|
facultatif, mais pas de validation a vide (on passe alors
|
||||||
|
directement a Contact). -->
|
||||||
<MalioButton
|
<MalioButton
|
||||||
variant="primary"
|
variant="primary"
|
||||||
:label="t('commercial.clients.form.submit')"
|
:label="t('commercial.clients.form.submit')"
|
||||||
:disabled="tabSubmitting || clientId === null"
|
:disabled="tabSubmitting || clientId === null || !canValidateInformation"
|
||||||
@click="submitInformation"
|
@click="submitInformation"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -204,6 +206,7 @@
|
|||||||
icon-name="mdi:add-bold"
|
icon-name="mdi:add-bold"
|
||||||
icon-position="left"
|
icon-position="left"
|
||||||
:label="t('commercial.clients.form.address.add')"
|
:label="t('commercial.clients.form.address.add')"
|
||||||
|
:disabled="!canAddAddress"
|
||||||
@click="addAddress"
|
@click="addAddress"
|
||||||
/>
|
/>
|
||||||
<MalioButton
|
<MalioButton
|
||||||
@@ -333,6 +336,7 @@
|
|||||||
icon-name="mdi:add-bold"
|
icon-name="mdi:add-bold"
|
||||||
icon-position="left"
|
icon-position="left"
|
||||||
:label="t('commercial.clients.form.accounting.addRib')"
|
:label="t('commercial.clients.form.accounting.addRib')"
|
||||||
|
:disabled="!canAddRib"
|
||||||
@click="addRib"
|
@click="addRib"
|
||||||
/>
|
/>
|
||||||
<MalioButton
|
<MalioButton
|
||||||
@@ -380,16 +384,18 @@ import { computed, onMounted, reactive, ref, watch } from 'vue'
|
|||||||
import { useClientReferentials, type RefOption } from '~/modules/commercial/composables/useClientReferentials'
|
import { useClientReferentials, type RefOption } from '~/modules/commercial/composables/useClientReferentials'
|
||||||
import { useClientFormErrors } from '~/modules/commercial/composables/useClientFormErrors'
|
import { useClientFormErrors } from '~/modules/commercial/composables/useClientFormErrors'
|
||||||
import {
|
import {
|
||||||
addressTypeFromFlags,
|
|
||||||
buildClientFormTabKeys,
|
buildClientFormTabKeys,
|
||||||
CLIENT_FORM_PLACEHOLDER_TABS,
|
CLIENT_FORM_PLACEHOLDER_TABS,
|
||||||
hasAllRequiredAccountingFields,
|
hasAllRequiredAccountingFields,
|
||||||
|
hasAtLeastOneInformationField,
|
||||||
hasAtLeastOneValidContact,
|
hasAtLeastOneValidContact,
|
||||||
|
isAddressValid,
|
||||||
isBankRequiredForPaymentType,
|
isBankRequiredForPaymentType,
|
||||||
isBillingEmailRequired,
|
isBillingEmailRequired,
|
||||||
isContactBlank,
|
isContactBlank,
|
||||||
isContactNamed,
|
isContactNamed,
|
||||||
isRibBlank,
|
isRibBlank,
|
||||||
|
isRibComplete,
|
||||||
isRibRequiredForPaymentType,
|
isRibRequiredForPaymentType,
|
||||||
} from '~/modules/commercial/utils/clientFormRules'
|
} from '~/modules/commercial/utils/clientFormRules'
|
||||||
import {
|
import {
|
||||||
@@ -538,7 +544,9 @@ async function submitMain(): Promise<void> {
|
|||||||
main.companyName = created.companyName ?? main.companyName
|
main.companyName = created.companyName ?? main.companyName
|
||||||
|
|
||||||
mainLocked.value = true
|
mainLocked.value = true
|
||||||
unlockedIndex.value = 0
|
// Information est facultatif : on deverrouille jusqu'a Contact (index 1)
|
||||||
|
// pour que l'utilisateur puisse y aller directement sans valider Information.
|
||||||
|
unlockedIndex.value = tabIndex('contact')
|
||||||
activeTab.value = 'information'
|
activeTab.value = 'information'
|
||||||
toast.success({ title: t('commercial.clients.toast.createSuccess') })
|
toast.success({ title: t('commercial.clients.toast.createSuccess') })
|
||||||
}
|
}
|
||||||
@@ -625,9 +633,12 @@ const information = reactive({
|
|||||||
directorName: null as string | null,
|
directorName: null as string | null,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Onglet facultatif, mais pas de validation « a vide » : au moins un champ rempli.
|
||||||
|
const canValidateInformation = computed(() => hasAtLeastOneInformationField(information))
|
||||||
|
|
||||||
/** PATCH /clients/{id} — mode strict : uniquement les champs du groupe information. */
|
/** PATCH /clients/{id} — mode strict : uniquement les champs du groupe information. */
|
||||||
async function submitInformation(): Promise<void> {
|
async function submitInformation(): Promise<void> {
|
||||||
if (clientId.value === null || tabSubmitting.value) return
|
if (clientId.value === null || tabSubmitting.value || !canValidateInformation.value) return
|
||||||
tabSubmitting.value = true
|
tabSubmitting.value = true
|
||||||
informationErrors.clearErrors()
|
informationErrors.clearErrors()
|
||||||
try {
|
try {
|
||||||
@@ -753,18 +764,17 @@ const countryOptions: RefOption[] = [
|
|||||||
// Type d'adresse (Select) obligatoire + RG-1.10 (>= 1 site) + RG-1.11 (email
|
// Type d'adresse (Select) obligatoire + RG-1.10 (>= 1 site) + RG-1.11 (email
|
||||||
// facturation si Facturation) sur chaque adresse.
|
// facturation si Facturation) sur chaque adresse.
|
||||||
const canValidateAddresses = computed(() =>
|
const canValidateAddresses = computed(() =>
|
||||||
addresses.value.length > 0
|
addresses.value.length > 0 && addresses.value.every(isAddressValid),
|
||||||
&& addresses.value.every((a) => {
|
|
||||||
const filledBillingEmail = a.billingEmail !== null && a.billingEmail.trim() !== ''
|
|
||||||
return addressTypeFromFlags(a) !== null
|
|
||||||
&& a.siteIris.length >= 1
|
|
||||||
&& a.categoryIris.length >= 1
|
|
||||||
&& (!isBillingEmailRequired(a) || filledBillingEmail)
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// « + Adresse » desactive tant que la derniere adresse n'est pas valide.
|
||||||
|
const canAddAddress = computed(() => {
|
||||||
|
const last = addresses.value[addresses.value.length - 1]
|
||||||
|
return last !== undefined && isAddressValid(last)
|
||||||
|
})
|
||||||
|
|
||||||
function addAddress(): void {
|
function addAddress(): void {
|
||||||
addresses.value.push(emptyAddress())
|
if (canAddAddress.value) addresses.value.push(emptyAddress())
|
||||||
}
|
}
|
||||||
|
|
||||||
function askRemoveAddress(index: number): void {
|
function askRemoveAddress(index: number): void {
|
||||||
@@ -859,23 +869,24 @@ function onPaymentTypeChange(value: string | number | null): void {
|
|||||||
if (!isBankRequired.value) accounting.bankIri = null
|
if (!isBankRequired.value) accounting.bankIri = null
|
||||||
}
|
}
|
||||||
|
|
||||||
function ribIsComplete(rib: RibFormDraft): boolean {
|
|
||||||
const filled = (v: string | null) => v !== null && v.trim() !== ''
|
|
||||||
return filled(rib.label) && filled(rib.bic) && filled(rib.iban)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RG-1.30 : les 6 champs scalaires obligatoires (comme les onglets Contact /
|
// RG-1.30 : les 6 champs scalaires obligatoires (comme les onglets Contact /
|
||||||
// Adresse, le bouton reste desactive tant que l'onglet n'est pas complet).
|
// Adresse, le bouton reste desactive tant que l'onglet n'est pas complet).
|
||||||
// RG-1.12 : banque requise si VIREMENT. RG-1.13 : >= 1 RIB complet si LCR.
|
// RG-1.12 : banque requise si VIREMENT. RG-1.13 : >= 1 RIB complet si LCR.
|
||||||
const canValidateAccounting = computed(() => {
|
const canValidateAccounting = computed(() => {
|
||||||
if (!hasAllRequiredAccountingFields(accounting)) return false
|
if (!hasAllRequiredAccountingFields(accounting)) return false
|
||||||
if (isBankRequired.value && (accounting.bankIri === null)) return false
|
if (isBankRequired.value && (accounting.bankIri === null)) return false
|
||||||
if (isRibRequired.value && !ribs.value.some(ribIsComplete)) return false
|
if (isRibRequired.value && !ribs.value.some(isRibComplete)) return false
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// « + RIB » desactive tant que le dernier bloc RIB n'est pas complet.
|
||||||
|
const canAddRib = computed(() => {
|
||||||
|
const last = ribs.value[ribs.value.length - 1]
|
||||||
|
return last !== undefined && isRibComplete(last)
|
||||||
|
})
|
||||||
|
|
||||||
function addRib(): void {
|
function addRib(): void {
|
||||||
ribs.value.push(emptyRib())
|
if (canAddRib.value) ribs.value.push(emptyRib())
|
||||||
}
|
}
|
||||||
|
|
||||||
function askRemoveRib(index: number): void {
|
function askRemoveRib(index: number): void {
|
||||||
|
|||||||
@@ -7,14 +7,18 @@ import {
|
|||||||
canSelectDeliveryOrBilling,
|
canSelectDeliveryOrBilling,
|
||||||
canSelectProspect,
|
canSelectProspect,
|
||||||
hasAllRequiredAccountingFields,
|
hasAllRequiredAccountingFields,
|
||||||
|
hasAtLeastOneInformationField,
|
||||||
hasAtLeastOneValidContact,
|
hasAtLeastOneValidContact,
|
||||||
|
isAddressValid,
|
||||||
isBankRequiredForPaymentType,
|
isBankRequiredForPaymentType,
|
||||||
isBillingEmailRequired,
|
isBillingEmailRequired,
|
||||||
isBlankRow,
|
isBlankRow,
|
||||||
isContactBlank,
|
isContactBlank,
|
||||||
isContactNamed,
|
isContactNamed,
|
||||||
isRibBlank,
|
isRibBlank,
|
||||||
|
isRibComplete,
|
||||||
isRibRequiredForPaymentType,
|
isRibRequiredForPaymentType,
|
||||||
|
type AddressValidityDraft,
|
||||||
type ContactDraft,
|
type ContactDraft,
|
||||||
type ContactFillableDraft,
|
type ContactFillableDraft,
|
||||||
} from '../clientFormRules'
|
} from '../clientFormRules'
|
||||||
@@ -271,3 +275,79 @@ describe('hasAllRequiredAccountingFields (RG-1.30)', () => {
|
|||||||
})).toBe(false)
|
})).toBe(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('hasAtLeastOneInformationField (pas de validation a vide a la creation)', () => {
|
||||||
|
const blank = {
|
||||||
|
description: null,
|
||||||
|
competitors: null,
|
||||||
|
foundedAt: null,
|
||||||
|
employeesCount: null,
|
||||||
|
revenueAmount: null,
|
||||||
|
profitAmount: null,
|
||||||
|
directorName: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
it('faux quand aucun champ n\'est rempli (onglet vierge)', () => {
|
||||||
|
expect(hasAtLeastOneInformationField(blank)).toBe(false)
|
||||||
|
expect(hasAtLeastOneInformationField({ ...blank, description: ' ' })).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('vrai des qu\'un champ porte une valeur', () => {
|
||||||
|
expect(hasAtLeastOneInformationField({ ...blank, description: 'Acteur majeur' })).toBe(true)
|
||||||
|
expect(hasAtLeastOneInformationField({ ...blank, employeesCount: '42' })).toBe(true)
|
||||||
|
expect(hasAtLeastOneInformationField({ ...blank, foundedAt: '2020-01-01' })).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('isAddressValid (gating « + Adresse » + validation onglet)', () => {
|
||||||
|
/** Adresse de livraison valide (type + site + categorie ; pas de facturation). */
|
||||||
|
function validDelivery(): AddressValidityDraft {
|
||||||
|
return {
|
||||||
|
isProspect: false,
|
||||||
|
isDelivery: true,
|
||||||
|
isBilling: false,
|
||||||
|
categoryIris: ['/api/client_categories/1'],
|
||||||
|
siteIris: ['/api/sites/1'],
|
||||||
|
billingEmail: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
it('vrai quand type + >= 1 site + >= 1 categorie (sans facturation)', () => {
|
||||||
|
expect(isAddressValid(validDelivery())).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('faux si aucun drapeau (type d\'adresse non renseigne, amorce vierge)', () => {
|
||||||
|
expect(isAddressValid({ ...validDelivery(), isDelivery: false })).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('faux si aucun site (RG-1.10)', () => {
|
||||||
|
expect(isAddressValid({ ...validDelivery(), siteIris: [] })).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('faux si aucune categorie', () => {
|
||||||
|
expect(isAddressValid({ ...validDelivery(), categoryIris: [] })).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('RG-1.11 : email de facturation obligatoire quand l\'adresse est de facturation', () => {
|
||||||
|
const billing: AddressValidityDraft = { ...validDelivery(), isBilling: true }
|
||||||
|
expect(isAddressValid({ ...billing, billingEmail: null })).toBe(false)
|
||||||
|
expect(isAddressValid({ ...billing, billingEmail: ' ' })).toBe(false)
|
||||||
|
expect(isAddressValid({ ...billing, billingEmail: 'facture@acme.fr' })).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('isRibComplete (gating « + RIB » + RG-1.13)', () => {
|
||||||
|
it('vrai quand label + BIC + IBAN sont remplis', () => {
|
||||||
|
expect(isRibComplete({ label: 'Compte courant', bic: 'BNPAFRPP', iban: 'FR1420041010050500013M02606' })).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('faux si un champ manque (null ou vide apres trim)', () => {
|
||||||
|
expect(isRibComplete({ label: null, bic: 'BNPAFRPP', iban: 'FR14...' })).toBe(false)
|
||||||
|
expect(isRibComplete({ label: 'Compte', bic: ' ', iban: 'FR14...' })).toBe(false)
|
||||||
|
expect(isRibComplete({ label: 'Compte', bic: 'BNPAFRPP', iban: null })).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('faux pour un bloc totalement vide (amorce)', () => {
|
||||||
|
expect(isRibComplete({ label: null, bic: null, iban: null })).toBe(false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -138,6 +138,16 @@ export function isRibBlank(rib: RibFillableDraft): boolean {
|
|||||||
return isBlankRow([rib.label, rib.bic, rib.iban])
|
return isBlankRow([rib.label, rib.bic, rib.iban])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RG-1.13 : un RIB est complet quand ses trois champs sont remplis (label, BIC,
|
||||||
|
* IBAN). Predicat par-bloc partage entre le gating du bouton « + RIB » (le
|
||||||
|
* dernier bloc doit etre complet avant d'en ajouter un autre) et la validation
|
||||||
|
* de l'onglet (au moins un RIB complet si reglement LCR).
|
||||||
|
*/
|
||||||
|
export function isRibComplete(rib: RibFillableDraft): boolean {
|
||||||
|
return isFilled(rib.label) && isFilled(rib.bic) && isFilled(rib.iban)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RG-1.06/07/08 : une adresse de prospection est exclusive d'une adresse de
|
* RG-1.06/07/08 : une adresse de prospection est exclusive d'une adresse de
|
||||||
* livraison/facturation. Prospect n'est selectionnable que si ni Livraison ni
|
* livraison/facturation. Prospect n'est selectionnable que si ni Livraison ni
|
||||||
@@ -226,6 +236,31 @@ export function addressTypeFromFlags(flags: AddressFlagsDraft): AddressType | nu
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sous-ensemble d'une adresse necessaire a sa validite par-bloc : drapeaux
|
||||||
|
* d'usage (pour le type + l'email de facturation conditionnel), sites et
|
||||||
|
* categories rattaches, email de facturation.
|
||||||
|
*/
|
||||||
|
export interface AddressValidityDraft extends AddressFlagsDraft {
|
||||||
|
categoryIris: string[]
|
||||||
|
siteIris: string[]
|
||||||
|
billingEmail: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validite par-bloc d'une adresse : type renseigne (RG-1.06/07/08), >= 1 site
|
||||||
|
* (RG-1.10), >= 1 categorie, et email de facturation rempli si l'adresse est de
|
||||||
|
* facturation (RG-1.11). Predicat partage entre le gating du bouton « + Adresse »
|
||||||
|
* (le dernier bloc doit etre valide avant d'en ajouter un autre) et la
|
||||||
|
* validation de l'onglet (toutes les adresses valides).
|
||||||
|
*/
|
||||||
|
export function isAddressValid(address: AddressValidityDraft): boolean {
|
||||||
|
return addressTypeFromFlags(address) !== null
|
||||||
|
&& address.siteIris.length >= 1
|
||||||
|
&& address.categoryIris.length >= 1
|
||||||
|
&& (!isBillingEmailRequired(address) || isFilled(address.billingEmail))
|
||||||
|
}
|
||||||
|
|
||||||
/** Code stable du type de reglement « virement » (cf. PaymentType.code, RG-1.12). */
|
/** Code stable du type de reglement « virement » (cf. PaymentType.code, RG-1.12). */
|
||||||
const PAYMENT_TYPE_TRANSFER = 'VIREMENT'
|
const PAYMENT_TYPE_TRANSFER = 'VIREMENT'
|
||||||
|
|
||||||
@@ -248,6 +283,36 @@ export function isRibRequiredForPaymentType(code: string | null | undefined): bo
|
|||||||
return code === PAYMENT_TYPE_LCR
|
return code === PAYMENT_TYPE_LCR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Champs saisissables de l'onglet Information (tous facultatifs). */
|
||||||
|
export interface InformationFieldsDraft {
|
||||||
|
description: string | null
|
||||||
|
competitors: string | null
|
||||||
|
foundedAt: string | null
|
||||||
|
employeesCount: string | null
|
||||||
|
revenueAmount: string | null
|
||||||
|
profitAmount: string | null
|
||||||
|
directorName: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vrai si au moins un champ de l'onglet Information est rempli. L'onglet est
|
||||||
|
* facultatif (aucun champ obligatoire), mais on n'autorise pas une validation
|
||||||
|
* « a vide » a la creation : sans donnee, rien a enregistrer, l'utilisateur
|
||||||
|
* passe directement a l'onglet Contact. (En edition, vider tous les champs reste
|
||||||
|
* une action legitime : ce gate n'y est pas applique.)
|
||||||
|
*/
|
||||||
|
export function hasAtLeastOneInformationField(information: InformationFieldsDraft): boolean {
|
||||||
|
return !isBlankRow([
|
||||||
|
information.description,
|
||||||
|
information.competitors,
|
||||||
|
information.foundedAt,
|
||||||
|
information.employeesCount,
|
||||||
|
information.revenueAmount,
|
||||||
|
information.profitAmount,
|
||||||
|
information.directorName,
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
/** Sous-ensemble du brouillon comptable portant les six champs obligatoires. */
|
/** Sous-ensemble du brouillon comptable portant les six champs obligatoires. */
|
||||||
export interface AccountingRequiredDraft {
|
export interface AccountingRequiredDraft {
|
||||||
siren: string | null
|
siren: string | null
|
||||||
|
|||||||
Reference in New Issue
Block a user