feat(commercial) : valide tous les blocs contacts/adresses/RIB et affiche les erreurs par bloc (ERP-110)
This commit is contained in:
@@ -441,7 +441,7 @@ const {
|
||||
contactErrors,
|
||||
addressErrors,
|
||||
ribErrors,
|
||||
mapRowError,
|
||||
submitRows,
|
||||
} = useClientFormErrors()
|
||||
|
||||
useHead({ title: t('commercial.clients.form.title') })
|
||||
@@ -676,23 +676,21 @@ function askRemoveContact(index: number): void {
|
||||
async function submitContacts(): Promise<void> {
|
||||
if (clientId.value === null || !canValidateContacts.value || tabSubmitting.value) return
|
||||
tabSubmitting.value = true
|
||||
contactErrors.value = []
|
||||
try {
|
||||
for (let index = 0; index < contacts.value.length; index++) {
|
||||
const contact = contacts.value[index]
|
||||
// On ignore les blocs totalement vides (ni nom ni prenom).
|
||||
if (!isContactNamed(contact)) continue
|
||||
|
||||
const body = {
|
||||
firstName: contact.firstName || null,
|
||||
lastName: contact.lastName || null,
|
||||
jobTitle: contact.jobTitle || null,
|
||||
phonePrimary: contact.phonePrimary || null,
|
||||
phoneSecondary: contact.hasSecondaryPhone ? (contact.phoneSecondary || null) : null,
|
||||
email: contact.email || null,
|
||||
}
|
||||
|
||||
try {
|
||||
// On tente TOUS les blocs (collecte des erreurs par index, ERP-110) ; les
|
||||
// blocs vides (ni nom ni prenom) sont ignores.
|
||||
const hasError = await submitRows(
|
||||
contacts.value,
|
||||
contactErrors,
|
||||
async (contact) => {
|
||||
const body = {
|
||||
firstName: contact.firstName || null,
|
||||
lastName: contact.lastName || null,
|
||||
jobTitle: contact.jobTitle || null,
|
||||
phonePrimary: contact.phonePrimary || null,
|
||||
phoneSecondary: contact.hasSecondaryPhone ? (contact.phoneSecondary || null) : null,
|
||||
email: contact.email || null,
|
||||
}
|
||||
if (contact.id === null) {
|
||||
const created = await api.post<ContactResponse>(
|
||||
`/clients/${clientId.value}/contacts`,
|
||||
@@ -705,16 +703,12 @@ async function submitContacts(): Promise<void> {
|
||||
else {
|
||||
await api.patch(`/client_contacts/${contact.id}`, body, { toast: false })
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
// 422 → erreurs inline sous les champs de CETTE ligne ; on stoppe
|
||||
// a la premiere ligne en echec (les suivantes ne sont pas tentees).
|
||||
if (!mapRowError(error, contactErrors, index)) {
|
||||
toast.error({ title: t('commercial.clients.toast.error'), message: apiErrorMessage(error) })
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
error => toast.error({ title: t('commercial.clients.toast.error'), message: apiErrorMessage(error) }),
|
||||
contact => !isContactNamed(contact),
|
||||
)
|
||||
// Tant qu'un bloc reste en erreur : pas de validation d'onglet ni de toast succes.
|
||||
if (hasError) return
|
||||
completeTab('contact')
|
||||
toast.success({ title: t('commercial.clients.toast.updateSuccess') })
|
||||
}
|
||||
@@ -784,26 +778,26 @@ function onAddressDegraded(): void {
|
||||
async function submitAddresses(): Promise<void> {
|
||||
if (clientId.value === null || !canValidateAddresses.value || tabSubmitting.value) return
|
||||
tabSubmitting.value = true
|
||||
addressErrors.value = []
|
||||
try {
|
||||
for (let index = 0; index < addresses.value.length; index++) {
|
||||
const address = addresses.value[index]
|
||||
const body = {
|
||||
isProspect: address.isProspect,
|
||||
isDelivery: address.isDelivery,
|
||||
isBilling: address.isBilling,
|
||||
country: address.country,
|
||||
postalCode: address.postalCode || null,
|
||||
city: address.city || null,
|
||||
street: address.street || null,
|
||||
streetComplement: address.streetComplement || null,
|
||||
categories: address.categoryIris,
|
||||
sites: address.siteIris,
|
||||
contacts: address.contactIris,
|
||||
billingEmail: isBillingEmailRequired(address) ? (address.billingEmail || null) : null,
|
||||
}
|
||||
|
||||
try {
|
||||
// On tente TOUS les blocs d'adresse (collecte des erreurs par index, ERP-110).
|
||||
const hasError = await submitRows(
|
||||
addresses.value,
|
||||
addressErrors,
|
||||
async (address) => {
|
||||
const body = {
|
||||
isProspect: address.isProspect,
|
||||
isDelivery: address.isDelivery,
|
||||
isBilling: address.isBilling,
|
||||
country: address.country,
|
||||
postalCode: address.postalCode || null,
|
||||
city: address.city || null,
|
||||
street: address.street || null,
|
||||
streetComplement: address.streetComplement || null,
|
||||
categories: address.categoryIris,
|
||||
sites: address.siteIris,
|
||||
contacts: address.contactIris,
|
||||
billingEmail: isBillingEmailRequired(address) ? (address.billingEmail || null) : null,
|
||||
}
|
||||
if (address.id === null) {
|
||||
const created = await api.post<{ id: number }>(
|
||||
`/clients/${clientId.value}/addresses`,
|
||||
@@ -815,14 +809,10 @@ async function submitAddresses(): Promise<void> {
|
||||
else {
|
||||
await api.patch(`/client_addresses/${address.id}`, body, { toast: false })
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (!mapRowError(error, addressErrors, index)) {
|
||||
toast.error({ title: t('commercial.clients.toast.error'), message: apiErrorMessage(error) })
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
error => toast.error({ title: t('commercial.clients.toast.error'), message: apiErrorMessage(error) }),
|
||||
)
|
||||
if (hasError) return
|
||||
completeTab('address')
|
||||
toast.success({ title: t('commercial.clients.toast.updateSuccess') })
|
||||
}
|
||||
@@ -893,7 +883,6 @@ async function submitAccounting(): Promise<void> {
|
||||
if (clientId.value === null || !canValidateAccounting.value || tabSubmitting.value) return
|
||||
tabSubmitting.value = true
|
||||
accountingErrors.clearErrors()
|
||||
ribErrors.value = []
|
||||
try {
|
||||
// 1) PATCH des scalaires comptables (erreurs inline sur leurs champs).
|
||||
try {
|
||||
@@ -912,30 +901,29 @@ async function submitAccounting(): Promise<void> {
|
||||
return
|
||||
}
|
||||
|
||||
// 2) POST/PATCH des RIB (erreurs inline par ligne).
|
||||
for (let index = 0; index < ribs.value.length; index++) {
|
||||
const rib = ribs.value[index]
|
||||
if (!ribIsComplete(rib)) continue
|
||||
try {
|
||||
// 2) POST/PATCH des RIB (erreurs inline par ligne, tous les blocs tentes —
|
||||
// les blocs RIB incomplets sont ignores).
|
||||
const ribHasError = await submitRows(
|
||||
ribs.value,
|
||||
ribErrors,
|
||||
async (rib) => {
|
||||
const body = { label: rib.label, bic: rib.bic, iban: rib.iban }
|
||||
if (rib.id === null) {
|
||||
const created = await api.post<{ id: number }>(
|
||||
`/clients/${clientId.value}/ribs`,
|
||||
{ label: rib.label, bic: rib.bic, iban: rib.iban },
|
||||
body,
|
||||
{ headers: { Accept: 'application/ld+json' }, toast: false },
|
||||
)
|
||||
rib.id = created.id
|
||||
}
|
||||
else {
|
||||
await api.patch(`/client_ribs/${rib.id}`, { label: rib.label, bic: rib.bic, iban: rib.iban }, { toast: false })
|
||||
await api.patch(`/client_ribs/${rib.id}`, body, { toast: false })
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (!mapRowError(error, ribErrors, index)) {
|
||||
toast.error({ title: t('commercial.clients.toast.error'), message: apiErrorMessage(error) })
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
error => toast.error({ title: t('commercial.clients.toast.error'), message: apiErrorMessage(error) }),
|
||||
rib => !ribIsComplete(rib),
|
||||
)
|
||||
if (ribHasError) return
|
||||
|
||||
completeTab('accounting')
|
||||
toast.success({ title: t('commercial.clients.toast.updateSuccess') })
|
||||
|
||||
Reference in New Issue
Block a user