From 9b136101f4340024fcf871c1d699cba748496bba Mon Sep 17 00:00:00 2001 From: achraf hafedh Date: Fri, 17 Oct 2025 11:54:25 +0200 Subject: [PATCH] fix(account-creation): add siren field in account creation ref: #MANAGER-20005 Signed-off-by: achraf hafedh --- .../account-details/Messages_de_DE.json | 1 + .../account-details/Messages_en_GB.json | 1 + .../account-details/Messages_es_ES.json | 1 + .../account-details/Messages_fr_CA.json | 1 + .../account-details/Messages_fr_FR.json | 1 + .../account-details/Messages_it_IT.json | 1 + .../account-details/Messages_pl_PL.json | 1 + .../account-details/Messages_pt_PT.json | 1 + .../src/helpers/flowHelper.test.ts | 65 +++++++++ .../src/helpers/flowHelper.ts | 18 ++- .../accountDetails/accountDetails.page.tsx | 128 ++++++++++++------ .../pages/accountType/AccountType.page.tsx | 4 +- 12 files changed, 180 insertions(+), 43 deletions(-) create mode 100644 packages/manager/apps/account-creation/src/helpers/flowHelper.test.ts diff --git a/packages/manager/apps/account-creation/public/translations/account-details/Messages_de_DE.json b/packages/manager/apps/account-creation/public/translations/account-details/Messages_de_DE.json index 1894cdeec076..94d9f9faacb8 100644 --- a/packages/manager/apps/account-creation/public/translations/account-details/Messages_de_DE.json +++ b/packages/manager/apps/account-creation/public/translations/account-details/Messages_de_DE.json @@ -12,6 +12,7 @@ "account_details_field_name": "Name", "account_details_field_corporation_name": "Firmenname", "account_details_field_siret": "SIRET", + "account_details_field_siren": "SIREN", "account_details_field_vat": "USt - IdNr.", "account_details_field_country": "Land des Wohnsitzes", "account_details_field_address": "Adresse", diff --git a/packages/manager/apps/account-creation/public/translations/account-details/Messages_en_GB.json b/packages/manager/apps/account-creation/public/translations/account-details/Messages_en_GB.json index 880f12c0ffcf..fcf04cca4fbf 100644 --- a/packages/manager/apps/account-creation/public/translations/account-details/Messages_en_GB.json +++ b/packages/manager/apps/account-creation/public/translations/account-details/Messages_en_GB.json @@ -12,6 +12,7 @@ "account_details_field_name": "Name", "account_details_field_corporation_name": "Name of company", "account_details_field_siret": "SIRET", + "account_details_field_siren": "SIREN", "account_details_field_vat": "VAT number", "account_details_field_country": "Country of residence", "account_details_field_address": "Address ", diff --git a/packages/manager/apps/account-creation/public/translations/account-details/Messages_es_ES.json b/packages/manager/apps/account-creation/public/translations/account-details/Messages_es_ES.json index 45ffd928fe63..59b2c5f217fc 100644 --- a/packages/manager/apps/account-creation/public/translations/account-details/Messages_es_ES.json +++ b/packages/manager/apps/account-creation/public/translations/account-details/Messages_es_ES.json @@ -12,6 +12,7 @@ "account_details_field_name": "Nombre", "account_details_field_corporation_name": "Razón social", "account_details_field_siret": "SIRET", + "account_details_field_siren": "SIREN", "account_details_field_vat": "Número de IVA", "account_details_field_country": "País de residencia", "account_details_field_address": "Dirección", diff --git a/packages/manager/apps/account-creation/public/translations/account-details/Messages_fr_CA.json b/packages/manager/apps/account-creation/public/translations/account-details/Messages_fr_CA.json index 92c378f60d5b..937702ead864 100644 --- a/packages/manager/apps/account-creation/public/translations/account-details/Messages_fr_CA.json +++ b/packages/manager/apps/account-creation/public/translations/account-details/Messages_fr_CA.json @@ -12,6 +12,7 @@ "account_details_field_name": "Nom", "account_details_field_corporation_name": "Raison sociale", "account_details_field_siret": "SIRET", + "account_details_field_siren": "SIREN", "account_details_field_vat": "Numéro de TVA", "account_details_field_country": "Pays de résidence", "account_details_field_address": "Adresse", diff --git a/packages/manager/apps/account-creation/public/translations/account-details/Messages_fr_FR.json b/packages/manager/apps/account-creation/public/translations/account-details/Messages_fr_FR.json index 5f0e4fca53fb..030ba7b457cd 100644 --- a/packages/manager/apps/account-creation/public/translations/account-details/Messages_fr_FR.json +++ b/packages/manager/apps/account-creation/public/translations/account-details/Messages_fr_FR.json @@ -19,6 +19,7 @@ "account_details_field_name": "Nom", "account_details_field_corporation_name": "Raison sociale", "account_details_field_siret": "SIRET", + "account_details_field_siren": "SIREN", "account_details_field_vat": "Numéro de TVA", "account_details_field_country": "Pays de résidence", "account_details_field_address": "Adresse", diff --git a/packages/manager/apps/account-creation/public/translations/account-details/Messages_it_IT.json b/packages/manager/apps/account-creation/public/translations/account-details/Messages_it_IT.json index 9314987d766c..5f3b10b672cc 100644 --- a/packages/manager/apps/account-creation/public/translations/account-details/Messages_it_IT.json +++ b/packages/manager/apps/account-creation/public/translations/account-details/Messages_it_IT.json @@ -12,6 +12,7 @@ "account_details_field_name": "Nome", "account_details_field_corporation_name": "Ragione sociale", "account_details_field_siret": "SIRET", + "account_details_field_siren": "SIREN", "account_details_field_vat": "Numero di P. IVA", "account_details_field_country": "Paese di residenza", "account_details_field_address": "Indirizzo", diff --git a/packages/manager/apps/account-creation/public/translations/account-details/Messages_pl_PL.json b/packages/manager/apps/account-creation/public/translations/account-details/Messages_pl_PL.json index e57d60c12b6e..8ccdf1849f49 100644 --- a/packages/manager/apps/account-creation/public/translations/account-details/Messages_pl_PL.json +++ b/packages/manager/apps/account-creation/public/translations/account-details/Messages_pl_PL.json @@ -12,6 +12,7 @@ "account_details_field_name": "Nazwa", "account_details_field_corporation_name": "Nazwa firmy", "account_details_field_siret": "SIRET", + "account_details_field_siren": "SIREN", "account_details_field_vat": "Numer NIP", "account_details_field_country": "Kraj", "account_details_field_address": "Adres siedziby/zamieszkania i pobytu", diff --git a/packages/manager/apps/account-creation/public/translations/account-details/Messages_pt_PT.json b/packages/manager/apps/account-creation/public/translations/account-details/Messages_pt_PT.json index 4c88a3c1bd04..2720b4552586 100644 --- a/packages/manager/apps/account-creation/public/translations/account-details/Messages_pt_PT.json +++ b/packages/manager/apps/account-creation/public/translations/account-details/Messages_pt_PT.json @@ -12,6 +12,7 @@ "account_details_field_name": "Nome", "account_details_field_corporation_name": "Razão social", "account_details_field_siret": "SIRET", + "account_details_field_siren": "SIREN", "account_details_field_vat": "Número de IVA", "account_details_field_country": "País de residência", "account_details_field_address": "Morada", diff --git a/packages/manager/apps/account-creation/src/helpers/flowHelper.test.ts b/packages/manager/apps/account-creation/src/helpers/flowHelper.test.ts new file mode 100644 index 000000000000..25273a00aa0e --- /dev/null +++ b/packages/manager/apps/account-creation/src/helpers/flowHelper.test.ts @@ -0,0 +1,65 @@ +import { describe, it, expect } from 'vitest'; +import { + shouldAccessOrganizationSearch, + shouldEnableSIRENDisplay, + getSirenFromSiret, +} from './flowHelper'; + +describe('shouldAccessOrganizationSearch', () => { + it('returns true for a French organization that is not individual', () => { + expect(shouldAccessOrganizationSearch('FR', 'corporation')).toBe(true); + expect(shouldAccessOrganizationSearch('FR', 'association')).toBe(true); + }); + + it('returns false for an individual', () => { + expect(shouldAccessOrganizationSearch('FR', 'individual')).toBe(false); + }); + + it('returns false for a non-French country', () => { + expect(shouldAccessOrganizationSearch('US', 'corporation')).toBe(false); + }); + + it('returns false if country or legalForm is missing', () => { + expect(shouldAccessOrganizationSearch(undefined, 'corporation')).toBe( + false, + ); + expect(shouldAccessOrganizationSearch('FR')).toBe(false); + }); +}); + +describe('shouldEnableSIRENDisplay', () => { + it('returns true for a French corporation', () => { + expect(shouldEnableSIRENDisplay('FR', 'corporation')).toBe(true); + }); + + it('returns false for other legal forms', () => { + expect(shouldEnableSIRENDisplay('FR', 'association')).toBe(false); + expect(shouldEnableSIRENDisplay('FR', 'individual')).toBe(false); + }); + + it('returns false for a non-French country', () => { + expect(shouldEnableSIRENDisplay('US', 'corporation')).toBe(false); + }); + + it('returns false if country or legalForm is missing', () => { + expect(shouldEnableSIRENDisplay(undefined, 'corporation')).toBe(false); + expect(shouldEnableSIRENDisplay('FR')).toBe(false); + }); +}); + +describe('getSirenFromSiret', () => { + const pattern = '^[0-9]{14}$'; + + it('returns the first 9 digits of a valid SIRET', () => { + expect(getSirenFromSiret('12345678912345', pattern)).toBe('123456789'); + }); + + it('returns null if the SIRET does not match the pattern', () => { + expect(getSirenFromSiret('ABC123', pattern)).toBeNull(); + }); + + it('returns null if the SIRET or pattern is missing', () => { + expect(getSirenFromSiret(undefined, pattern)).toBeNull(); + expect(getSirenFromSiret('12345678912345', null)).toBeNull(); + }); +}); diff --git a/packages/manager/apps/account-creation/src/helpers/flowHelper.ts b/packages/manager/apps/account-creation/src/helpers/flowHelper.ts index bb8dcf545070..6ed8af6c7766 100644 --- a/packages/manager/apps/account-creation/src/helpers/flowHelper.ts +++ b/packages/manager/apps/account-creation/src/helpers/flowHelper.ts @@ -1,6 +1,20 @@ import { Country, LegalForm } from '@ovh-ux/manager-config'; -export const shouldAccessCompanySearch = ( +export const shouldAccessOrganizationSearch = ( country?: Country, legalForm?: LegalForm, -) => country === 'FR' && legalForm && legalForm !== 'individual'; +) => country === 'FR' && !!legalForm && legalForm !== 'individual'; + +export const shouldEnableSIRENDisplay = ( + country?: Country, + legalForm?: LegalForm, +) => country === 'FR' && legalForm === 'corporation'; + +export const getSirenFromSiret = ( + siret?: string, + pattern?: string | null, +): string | null => { + if (!siret || !pattern) return null; + + return new RegExp(pattern).test(siret) ? siret.substring(0, 9) : null; +}; diff --git a/packages/manager/apps/account-creation/src/pages/accountDetails/accountDetails.page.tsx b/packages/manager/apps/account-creation/src/pages/accountDetails/accountDetails.page.tsx index 5ac454656313..5fb56e22a5a2 100644 --- a/packages/manager/apps/account-creation/src/pages/accountDetails/accountDetails.page.tsx +++ b/packages/manager/apps/account-creation/src/pages/accountDetails/accountDetails.page.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { Controller, SubmitHandler, useForm } from 'react-hook-form'; +import { Controller, SubmitHandler, useForm, useWatch } from 'react-hook-form'; import { useMutation } from '@tanstack/react-query'; import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; @@ -44,7 +44,11 @@ import { } from '@/hooks/zod/useZod'; import { putMe } from '@/data/api/me'; import { urls } from '@/routes/routes.constant'; -import { shouldAccessCompanySearch } from '@/helpers/flowHelper'; +import { + getSirenFromSiret, + shouldAccessOrganizationSearch, + shouldEnableSIRENDisplay, +} from '@/helpers/flowHelper'; type AccountDetailsFormProps = { rules: Record; @@ -113,6 +117,28 @@ function AccountDetailsForm({ resolver: zodResolver(zodSchema), }); + const shouldDisplaySIREN = useMemo( + () => shouldEnableSIRENDisplay(currentUser.country, legalForm), + [currentUser.country, legalForm], + ); + + const corporationIdValue = useWatch({ + control, + name: 'companyNationalIdentificationNumber', + }); + + const sirenValue = useMemo( + () => + getSirenFromSiret( + corporationIdValue, + rules?.companyNationalIdentificationNumber?.regularExpression, + ), + [ + corporationIdValue, + rules?.companyNationalIdentificationNumber?.regularExpression, + ], + ); + const phoneCountry = watch('phoneCountry'); useEffect(() => { @@ -291,41 +317,63 @@ function AccountDetailsForm({ control={control} name="companyNationalIdentificationNumber" render={({ field: { name, value, onChange, onBlur } }) => ( - - - - {errors[name] && - rules?.companyNationalIdentificationNumber && ( - - {renderTranslatedZodError( - errors[name].message, - rules?.companyNationalIdentificationNumber, - )} + <> + + + + + {errors[name] && + rules?.companyNationalIdentificationNumber && ( + + {renderTranslatedZodError( + errors[name].message, + rules?.companyNationalIdentificationNumber, + )} + + )} + + {shouldDisplaySIREN && ( + + + + + )} + )} /> )} @@ -695,7 +743,7 @@ export default function AccountDetailsPage() { const { t: tAction } = useTranslation(NAMESPACES.ACTIONS); const { legalForm, organisation } = useUserContext(); const { data: currentUser } = useMe(); - const wentThroughCompanySearch = shouldAccessCompanySearch( + const wentThroughOrganizationSearch = shouldAccessOrganizationSearch( currentUser?.country, legalForm, ); @@ -740,11 +788,13 @@ export default function AccountDetailsPage() { - {wentThroughCompanySearch && ( + {wentThroughOrganizationSearch && ( {tCommon('step', { current: 2, total: 2 })} diff --git a/packages/manager/apps/account-creation/src/pages/accountType/AccountType.page.tsx b/packages/manager/apps/account-creation/src/pages/accountType/AccountType.page.tsx index e9e190a4a613..1f019813a9ec 100644 --- a/packages/manager/apps/account-creation/src/pages/accountType/AccountType.page.tsx +++ b/packages/manager/apps/account-creation/src/pages/accountType/AccountType.page.tsx @@ -17,7 +17,7 @@ import { useLegalFormRules } from '@/data/hooks/useRules'; import { AVERAGE_NUMBER_OF_LEGAL_FORMS } from './accountType.constants'; import AccountTypeTooltipContent from './tooltip-content/TooltipContent.component'; import { urls } from '@/routes/routes.constant'; -import { shouldAccessCompanySearch } from '@/helpers/flowHelper'; +import { shouldAccessOrganizationSearch } from '@/helpers/flowHelper'; export default function AccountType() { const { t } = useTranslation('account-type'); @@ -34,7 +34,7 @@ export default function AccountType() { const validateStep = useCallback(() => { if (!legalForm) { setLegalFormError(true); - } else if (shouldAccessCompanySearch(country, legalForm)) { + } else if (shouldAccessOrganizationSearch(country, legalForm)) { navigate(urls.company); } else { navigate(urls.accountDetails);