fix(commercial) : ne sauter que les blocs contact/RIB totalement vides (bloc partiel sans nom -> 422 inline, ERP-110)
This commit is contained in:
@@ -7,11 +7,27 @@ import {
|
||||
hasAtLeastOneValidContact,
|
||||
isBankRequiredForPaymentType,
|
||||
isBillingEmailRequired,
|
||||
isBlankRow,
|
||||
isContactBlank,
|
||||
isContactNamed,
|
||||
isRibBlank,
|
||||
isRibRequiredForPaymentType,
|
||||
type ContactDraft,
|
||||
type ContactFillableDraft,
|
||||
} from '../clientFormRules'
|
||||
|
||||
/** Bloc contact totalement vide (amorce par defaut). */
|
||||
function blankContact(): ContactFillableDraft {
|
||||
return {
|
||||
firstName: null,
|
||||
lastName: null,
|
||||
jobTitle: null,
|
||||
phonePrimary: null,
|
||||
phoneSecondary: null,
|
||||
email: null,
|
||||
}
|
||||
}
|
||||
|
||||
describe('buildClientFormTabKeys (gating onglet Comptabilite + onglets edit-only)', () => {
|
||||
it('inclut l onglet accounting si l utilisateur a accounting.view', () => {
|
||||
expect(buildClientFormTabKeys(true)).toContain('accounting')
|
||||
@@ -59,6 +75,49 @@ describe('isContactNamed (RG-1.05)', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('isBlankRow (primitive : toutes les valeurs vides)', () => {
|
||||
it('vrai si toutes les valeurs sont nulles / vides / espaces', () => {
|
||||
expect(isBlankRow([null, undefined, '', ' '])).toBe(true)
|
||||
expect(isBlankRow([])).toBe(true)
|
||||
})
|
||||
|
||||
it('faux des qu une valeur porte un caractere non-espace', () => {
|
||||
expect(isBlankRow([null, 'x', ''])).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isRibBlank (bloc RIB totalement vide vs partiellement rempli)', () => {
|
||||
it('vrai si label / bic / iban sont tous vides', () => {
|
||||
expect(isRibBlank({ label: null, bic: null, iban: null })).toBe(true)
|
||||
expect(isRibBlank({ label: ' ', bic: '', iban: null })).toBe(true)
|
||||
})
|
||||
|
||||
it('faux si un IBAN seul est saisi (bloc a soumettre -> 422 NotBlank inline)', () => {
|
||||
expect(isRibBlank({ label: null, bic: null, iban: 'FR1420041010050500013M02606' })).toBe(false)
|
||||
})
|
||||
|
||||
it('faux si seul le libelle est saisi', () => {
|
||||
expect(isRibBlank({ label: 'Compte courant', bic: null, iban: null })).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('isContactBlank (bloc totalement vide vs partiellement rempli)', () => {
|
||||
it('vrai si aucun champ saisissable n est rempli', () => {
|
||||
expect(isContactBlank(blankContact())).toBe(true)
|
||||
expect(isContactBlank({ ...blankContact(), firstName: ' ', email: '' })).toBe(true)
|
||||
})
|
||||
|
||||
it('faux si un email seul est saisi (bloc a soumettre -> 422 RG-1.05 inline)', () => {
|
||||
expect(isContactBlank({ ...blankContact(), email: 'jean@acme.fr' })).toBe(false)
|
||||
})
|
||||
|
||||
it('faux si seul un telephone, une fonction ou un nom est saisi', () => {
|
||||
expect(isContactBlank({ ...blankContact(), phonePrimary: '0612345678' })).toBe(false)
|
||||
expect(isContactBlank({ ...blankContact(), jobTitle: 'Directeur' })).toBe(false)
|
||||
expect(isContactBlank({ ...blankContact(), firstName: 'Alice' })).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('hasAtLeastOneValidContact (RG-1.14)', () => {
|
||||
it('faux sur une liste vide', () => {
|
||||
expect(hasAtLeastOneValidContact([])).toBe(false)
|
||||
|
||||
@@ -86,6 +86,58 @@ export function hasAtLeastOneValidContact(contacts: ContactDraft[]): boolean {
|
||||
return contacts.some(isContactNamed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Primitive reutilisable : vrai si TOUTES les valeurs fournies sont vides (null /
|
||||
* undefined / espaces uniquement). Sert a detecter un bloc de collection
|
||||
* totalement vide (amorce non remplie). Un bloc qui porte la moindre donnee
|
||||
* n'est PAS « blank » : il doit etre soumis pour declencher sa 422 inline plutot
|
||||
* que d'etre saute silencieusement.
|
||||
*/
|
||||
export function isBlankRow(values: (string | null | undefined)[]): boolean {
|
||||
return values.every(value => !isFilled(value))
|
||||
}
|
||||
|
||||
/** Champs saisissables d'un bloc contact (pour detecter un bloc totalement vide). */
|
||||
export interface ContactFillableDraft extends ContactDraft {
|
||||
jobTitle: string | null
|
||||
phonePrimary: string | null
|
||||
phoneSecondary: string | null
|
||||
email: string | null
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrai si AUCUN champ saisissable du bloc contact n'est rempli. Distingue un bloc
|
||||
* d'amorce vide (a ignorer au submit) d'un bloc partiellement rempli sans nom
|
||||
* (email / telephone / fonction seul) : ce dernier doit etre soumis pour
|
||||
* declencher la 422 RG-1.05 (« prenom ou nom obligatoire ») affichee inline.
|
||||
*/
|
||||
export function isContactBlank(contact: ContactFillableDraft): boolean {
|
||||
return isBlankRow([
|
||||
contact.firstName,
|
||||
contact.lastName,
|
||||
contact.jobTitle,
|
||||
contact.phonePrimary,
|
||||
contact.phoneSecondary,
|
||||
contact.email,
|
||||
])
|
||||
}
|
||||
|
||||
/** Champs saisissables d'un bloc RIB (pour detecter un bloc totalement vide). */
|
||||
export interface RibFillableDraft {
|
||||
label: string | null
|
||||
bic: string | null
|
||||
iban: string | null
|
||||
}
|
||||
|
||||
/**
|
||||
* Vrai si AUCUN champ du bloc RIB n'est rempli. Un RIB partiellement rempli (ex.
|
||||
* IBAN seul) n'est PAS « blank » : il doit etre soumis pour declencher les 422
|
||||
* NotBlank (label / bic / iban) inline plutot que d'etre saute silencieusement.
|
||||
*/
|
||||
export function isRibBlank(rib: RibFillableDraft): boolean {
|
||||
return isBlankRow([rib.label, rib.bic, 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
|
||||
|
||||
Reference in New Issue
Block a user