diff --git a/back/src/domains/convention/use-cases/notifications/NotifyConventionReminder.ts b/back/src/domains/convention/use-cases/notifications/NotifyConventionReminder.ts index d4fc4a9063..8c5fa240c2 100644 --- a/back/src/domains/convention/use-cases/notifications/NotifyConventionReminder.ts +++ b/back/src/domains/convention/use-cases/notifications/NotifyConventionReminder.ts @@ -9,7 +9,6 @@ import { type EstablishmentRepresentative, type ExtractFromExisting, type GenericActor, - type Phone, type ReminderKind, type Role, type TemplatedEmail, @@ -19,6 +18,7 @@ import { frontRoutes, isEstablishmentTutorIsEstablishmentRepresentative, isSignatoryRole, + smsRecipientPhoneSchema, } from "shared"; import { AppConfig } from "../../../../config/bootstrap/appConfig"; import { GenerateConventionMagicLinkUrl } from "../../../../config/bootstrap/magicLinkUrl"; @@ -207,7 +207,9 @@ export class NotifyConventionReminder extends TransactionalUseCase< const signatories = Object.values(conventionRead.signatories); const smsSignatories = signatories.filter( - (signatory) => !signatory.signedAt && isValidMobilePhone(signatory.phone), + (signatory) => + !signatory.signedAt && + smsRecipientPhoneSchema.safeParse(signatory.phone).success, ); const emailActors = [ @@ -276,7 +278,7 @@ export class NotifyConventionReminder extends TransactionalUseCase< return { kind, - recipientPhone: makeInternationalPhone(phone), + recipientPhone: phone, params: { shortLink }, }; } @@ -395,21 +397,3 @@ const signStatus = (signAt: string | undefined): string => signAt ? `√ - A signé le ${format(new Date(signAt), "dd/MM/yyyy")}` : `❌ - N'a pas signé`; - -const isValidMobilePhone = (phone: string): boolean => - (phone.startsWith("06") || phone.startsWith("07")) && phone.length === 10; - -function makeInternationalPhone(phone: string): Phone { - if (phone.startsWith("0690") || phone.startsWith("0691")) - return `590${phone.substring(1)}`; - if (phone.startsWith("0694")) return `594${phone.substring(1)}`; - if (phone.startsWith("0696") || phone.startsWith("0697")) - return `596${phone.substring(1)}`; - if ( - phone.startsWith("0692") || - phone.startsWith("0693") || - phone.startsWith("0639") - ) - return `262${phone.substring(1)}`; - return `33${phone.substring(1)}`; -} diff --git a/back/src/domains/convention/use-cases/notifications/NotifyConventionReminder.unit.test.ts b/back/src/domains/convention/use-cases/notifications/NotifyConventionReminder.unit.test.ts index 6767cffbeb..55b70f220d 100644 --- a/back/src/domains/convention/use-cases/notifications/NotifyConventionReminder.unit.test.ts +++ b/back/src/domains/convention/use-cases/notifications/NotifyConventionReminder.unit.test.ts @@ -45,7 +45,7 @@ describe("NotifyThatConventionStillNeedToBeSigned use case", () => { email: "boss@mail.com", firstName: "lord", lastName: "voldemort", - phone: "0188776666", + phone: "+33188776666", role: "establishment-representative", }; let useCase: NotifyConventionReminder; @@ -456,16 +456,16 @@ describe("NotifyThatConventionStillNeedToBeSigned use case", () => { const convention = new ConventionDtoBuilder() .withAgencyId(agency.id) .withStatus(status) - .withBeneficiaryPhone("0611223344") + .withBeneficiaryPhone("+33611223344") .withBeneficiarySignedAt(undefined) - .withEstablishmentRepresentativePhone("0755667788") + .withEstablishmentRepresentativePhone("+33755667788") .withEstablishmentRepresentativeSignedAt(undefined) .withEstablishmentTutor({ email: "tutor@email.com", firstName: "Obiwan", lastName: "Kenobi", job: "Jedi Master", - phone: "0688997755", + phone: "+33688997755", role: "establishment-tutor", }) .build(); @@ -537,16 +537,13 @@ describe("NotifyThatConventionStillNeedToBeSigned use case", () => { ], sms: [ { - recipientPhone: `33${convention.signatories.beneficiary.phone.substring( - 1, - )}`, + recipientPhone: convention.signatories.beneficiary.phone, kind, params: { shortLink: makeShortLinkUrl(config, shortLinkIds[2]) }, }, { - recipientPhone: `33${convention.signatories.establishmentRepresentative.phone.substring( - 1, - )}`, + recipientPhone: + convention.signatories.establishmentRepresentative.phone, kind, params: { shortLink: makeShortLinkUrl(config, shortLinkIds[3]), @@ -566,8 +563,8 @@ describe("NotifyThatConventionStillNeedToBeSigned use case", () => { const convention = new ConventionDtoBuilder() .withAgencyId(agency.id) .withStatus(status) - .withBeneficiaryPhone("0111223344") - .withEstablishmentRepresentativePhone("0211223344") + .withBeneficiaryPhone("+33111223344") + .withEstablishmentRepresentativePhone("+33211223344") .build(); uow.conventionRepository.setConventions([convention]); uow.agencyRepository.setAgencies([agency]); @@ -731,14 +728,14 @@ describe("NotifyThatConventionStillNeedToBeSigned use case", () => { const convention = new ConventionDtoBuilder() .withAgencyId(agency.id) .withStatus(status) - .withEstablishmentRepresentativePhone("0611448866") + .withEstablishmentRepresentativePhone("+33611448866") .withEstablishmentRepresentativeSignedAt(undefined) .withEstablishmentTutor({ email: "tutor@email.com", firstName: "Obiwan", lastName: "Kenobi", job: "Jedi Master", - phone: "0688997755", + phone: "+33688997755", role: "establishment-tutor", }) .build(); @@ -798,9 +795,8 @@ describe("NotifyThatConventionStillNeedToBeSigned use case", () => { ], sms: [ { - recipientPhone: `33${convention.signatories.establishmentRepresentative.phone.substring( - 1, - )}`, + recipientPhone: + convention.signatories.establishmentRepresentative.phone, kind, params: { shortLink: makeShortLinkUrl(config, shortLinkIds[2]), @@ -918,27 +914,26 @@ describe("NotifyThatConventionStillNeedToBeSigned use case", () => { describe("handle SMS DOM", () => { it.each([ - ["0600000001", "33600000001"], // Metropole - ["0639000001", "262639000001"], // Mayotte - ["0690000001", "590690000001"], // Guadeloupe - ["0691000001", "590691000001"], // Guadeloupe - ["0694000001", "594694000001"], // Guyane - ["0696000001", "596696000001"], // Martinique - ["0697000001", "596697000001"], // Martinique - ["0692000001", "262692000001"], // Réunion - ["0693000001", "262693000001"], // Réunion + ["+33600000001"], // Metropole + ["+262639000001"], // Mayotte + ["+590690000001"], // Guadeloupe + ["+590691000001"], // Guadeloupe + ["+594694000001"], // Guyane + ["+596696000001"], // Martinique + ["+262692000001"], // Réunion + ["+262693000001"], // Réunion ])( "Should send SMS with mobile phone %s", - async (mobilePhone, internationalMobilePhone) => { + async (internationalMobilePhone) => { //Arrange const agency = new AgencyDtoBuilder().withId("agencyId").build(); const convention = new ConventionDtoBuilder() .withAgencyId(agency.id) .withStatus("READY_TO_SIGN") - .withBeneficiaryPhone(mobilePhone) + .withBeneficiaryPhone(internationalMobilePhone) .withBeneficiarySignedAt(undefined) - .withEstablishmentRepresentativePhone("0211223344") + .withEstablishmentRepresentativePhone("+262693000002") .build(); uow.conventionRepository.setConventions([convention]); diff --git a/shared/src/sms/sms.schema.unit.test.ts b/shared/src/sms/sms.schema.unit.test.ts new file mode 100644 index 0000000000..8b46a1eaad --- /dev/null +++ b/shared/src/sms/sms.schema.unit.test.ts @@ -0,0 +1,15 @@ +import { smsRecipientPhoneSchema } from "./sms.schema"; + +describe("sms phone number schema", () => { + it("should accept international only mobile phone numbers", () => { + const mobilePhoneNumber = "+596696000001"; // Martinique mobile phone number + expect(smsRecipientPhoneSchema.parse(mobilePhoneNumber)).toBe( + mobilePhoneNumber, + ); + }); + + it("wrong path", () => { + const mobilePhoneNumber = "+596697000001"; // Martinique, not a mobile phone number + expect(() => smsRecipientPhoneSchema.parse(mobilePhoneNumber)).toThrow(); + }); +});