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:
@@ -7,14 +7,18 @@ import {
|
||||
canSelectDeliveryOrBilling,
|
||||
canSelectProspect,
|
||||
hasAllRequiredAccountingFields,
|
||||
hasAtLeastOneInformationField,
|
||||
hasAtLeastOneValidContact,
|
||||
isAddressValid,
|
||||
isBankRequiredForPaymentType,
|
||||
isBillingEmailRequired,
|
||||
isBlankRow,
|
||||
isContactBlank,
|
||||
isContactNamed,
|
||||
isRibBlank,
|
||||
isRibComplete,
|
||||
isRibRequiredForPaymentType,
|
||||
type AddressValidityDraft,
|
||||
type ContactDraft,
|
||||
type ContactFillableDraft,
|
||||
} from '../clientFormRules'
|
||||
@@ -271,3 +275,79 @@ describe('hasAllRequiredAccountingFields (RG-1.30)', () => {
|
||||
})).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])
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* livraison/facturation. Prospect n'est selectionnable que si ni Livraison ni
|
||||
@@ -226,6 +236,31 @@ export function addressTypeFromFlags(flags: AddressFlagsDraft): AddressType | nu
|
||||
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). */
|
||||
const PAYMENT_TYPE_TRANSFER = 'VIREMENT'
|
||||
|
||||
@@ -248,6 +283,36 @@ export function isRibRequiredForPaymentType(code: string | null | undefined): bo
|
||||
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. */
|
||||
export interface AccountingRequiredDraft {
|
||||
siren: string | null
|
||||
|
||||
Reference in New Issue
Block a user