From 51e77daeed5476a35956996e270fc22f7de70551 Mon Sep 17 00:00:00 2001 From: ssedoudbgouv Date: Thu, 16 Jan 2025 09:20:05 +0100 Subject: [PATCH] TRELO-2862 last chance pro reminder --- app/services/emails/EmailDefinitionsPro.scala | 27 +++++++ app/tasks/report/ReportRemindersTask.scala | 22 ++++-- app/utils/Constants.scala | 2 + app/utils/EmailSubjects.scala | 1 + .../professional/reportReOpening.scala.html | 2 +- .../reportsLastChanceReminder.scala.html | 71 +++++++++++++++++++ .../reportsTransmittedReminder.scala.html | 2 +- .../reportsUnreadReminder.scala.html | 2 +- 8 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 app/views/mails/professional/reportsLastChanceReminder.scala.html diff --git a/app/services/emails/EmailDefinitionsPro.scala b/app/services/emails/EmailDefinitionsPro.scala index 318e9928..494ab7c4 100644 --- a/app/services/emails/EmailDefinitionsPro.scala +++ b/app/services/emails/EmailDefinitionsPro.scala @@ -182,6 +182,33 @@ object EmailDefinitionsPro { } + case object ProReportsLastChanceReminder extends EmailDefinition { + override val category = Pro + + override def examples = { + val report1 = genReport + val report2 = genReport.copy(companyId = report1.companyId) + val report3 = genReport.copy(companyId = report1.companyId, expirationDate = OffsetDateTime.now().plusDays(5)) + Seq( + "reports_last_chance_reminder" -> ((recipient, _) => + Email(List(recipient), List(report1, report2, report3), Period.ofDays(7)) + ) + ) + } + + final case class Email( + recipients: List[EmailAddress], + reports: List[Report], + period: Period + ) extends ProFilteredEmailMultipleReport { + override val subject: String = EmailSubjects.REPORT_LAST_CHANCE_REMINDER + + override def getBody: (FrontRoute, EmailAddress) => String = + (frontRoute, _) => + views.html.mails.professional.reportsLastChanceReminder(reports, period)(frontRoute).toString + } + } + case object ProReportsReadReminder extends EmailDefinition { override val category = Pro diff --git a/app/tasks/report/ReportRemindersTask.scala b/app/tasks/report/ReportRemindersTask.scala index 3038eb79..7811dc04 100644 --- a/app/tasks/report/ReportRemindersTask.scala +++ b/app/tasks/report/ReportRemindersTask.scala @@ -11,8 +11,7 @@ import orchestrators.CompaniesVisibilityOrchestrator import repositories.event.EventRepositoryInterface import repositories.report.ReportRepositoryInterface import repositories.tasklock.TaskRepositoryInterface -import services.emails.EmailDefinitionsPro.ProReportsReadReminder -import services.emails.EmailDefinitionsPro.ProReportsUnreadReminder +import services.emails.EmailDefinitionsPro.{ProReportsLastChanceReminder, ProReportsReadReminder, ProReportsUnreadReminder} import services.emails.BaseEmail import services.emails.MailServiceInterface import tasks.ScheduledTask @@ -50,6 +49,7 @@ class ReportRemindersTask( // At J+0, the pro receives the "new report" email // At J+8 during the night, the pro receives a reminder email // At J+16 during the night, the pro receives the second reminder email + // At J+24 last reminder // At J+25 the report is closed val delayBetweenReminderEmails: Period = Period.ofDays(7) val maxReminderCount = 2 @@ -74,11 +74,12 @@ class ReportRemindersTask( shouldSendReminderEmail(report, taskRunDate, eventsByReportId) } _ = logger.info(s"Found ${finalReportsWithUsers.size} reports for which we should send a reminder") - result <- sendReminderEmailsWithErrorHandling(finalReportsWithUsers) + result <- sendReminderEmailsWithErrorHandling(taskRunDate, finalReportsWithUsers) } yield result } private def sendReminderEmailsWithErrorHandling( + taskRunDate: OffsetDateTime, reportsWithUsers: List[(Report, List[User])] ): Future[(List[List[UUID]], List[List[UUID]])] = { logger.info(s"Sending reminders for ${reportsWithUsers.length} reports") @@ -89,9 +90,17 @@ class ReportRemindersTask( successesOrFailuresList <- Future.sequence(reportsPerCompanyPerUsers.toList.flatMap { case (users, reportsPerCompany) => reportsPerCompany.map { reports => - val (readByPros, notReadByPros) = reports.partition(_.isReadByPro) + val (reportsClosingTomorrow, otherReports) = + reports.partition(r => taskRunDate.toLocalDate.plusDays(1).isAfter(r.expirationDate.toLocalDate)) + val (readByPros, notReadByPros) = otherReports.partition(_.isReadByPro) for { + reportsClosingTomorrowSent <- sendReminderEmailIfAtLeastOneReport( + reportsClosingTomorrow, + users, + ProReportsLastChanceReminder.Email, + EMAIL_LAST_CHANCE_REMINDER_ACTION + ) readByProsSent <- sendReminderEmailIfAtLeastOneReport( readByPros, users, @@ -104,7 +113,7 @@ class ReportRemindersTask( ProReportsUnreadReminder.Email, EMAIL_PRO_REMIND_NO_READING ) - } yield List(readByProsSent, notReadByProsSent).flatten + } yield List(readByProsSent, notReadByProsSent,reportsClosingTomorrowSent).flatten } }) (failures, successes) = successesOrFailuresList.flatten.partitionMap(identity) @@ -147,7 +156,8 @@ class ReportRemindersTask( previousEmailsEvents.count(e => reminderEmailsActions.contains(e.action)) >= maxReminderCount val hadARecentEmail = previousEmailsEvents.exists(_.creationDate.isAfter(taskRunDate.minus(delayBetweenReminderEmails))) - val shouldSendEmail = !hadMaxReminderEmails && !hadARecentEmail + val isLastDay = taskRunDate.toLocalDate.plusDays(1).isAfter(report.expirationDate.toLocalDate) + val shouldSendEmail = (!hadMaxReminderEmails && !hadARecentEmail) || isLastDay shouldSendEmail } diff --git a/app/utils/Constants.scala b/app/utils/Constants.scala index 29cdcad9..0dd65055 100644 --- a/app/utils/Constants.scala +++ b/app/utils/Constants.scala @@ -94,6 +94,8 @@ object Constants { extends ActionEventValue("Email « Nouveau signalement non consulté » envoyé au professionnel") object EMAIL_PRO_REMIND_NO_ACTION extends ActionEventValue("Email « Nouveau signalement en attente de réponse » envoyé au professionnel") + object EMAIL_LAST_CHANCE_REMINDER_ACTION + extends ActionEventValue("EmailLastChanceProReminder") object REPORT_COMPANY_CHANGE extends ActionEventValue("Modification du commerçant") object REPORT_COUNTRY_CHANGE extends ActionEventValue("Modification du pays") diff --git a/app/utils/EmailSubjects.scala b/app/utils/EmailSubjects.scala index fdcd4a46..20228e16 100644 --- a/app/utils/EmailSubjects.scala +++ b/app/utils/EmailSubjects.scala @@ -16,6 +16,7 @@ object EmailSubjects { val REPORT_ASSIGNED = "Signalement affecté" val REPORT_UNREAD_REMINDER = "Nouveau(x) signalement(s)" val REPORT_TRANSMITTED_REMINDER = "Signalement(s) en attente de réponse" + val REPORT_LAST_CHANCE_REMINDER = "Signalement(s) expirant demain" val REPORT_NOTIF_DGCCRF = (count: Int, additional: String) => s"[SignalConso] $additional${if (count > 1) s"$count nouveaux signalements ont été déposés" else "Un nouveau signalement a été déposé"}" diff --git a/app/views/mails/professional/reportReOpening.scala.html b/app/views/mails/professional/reportReOpening.scala.html index 5c46a196..91b40fe8 100644 --- a/app/views/mails/professional/reportReOpening.scala.html +++ b/app/views/mails/professional/reportReOpening.scala.html @@ -25,7 +25,7 @@

Pour y apporter une réponse, il vous suffit de vous connecter sur votre Espace Professionnel à l'aide de votre adresse e-mail et du mot de passe que vous avez créé à votre première connexion sur SignalConso. - Allez dans le détail du signalement et cliquez sur le bouton "Répondre à ce signalement". + Allez dans le détail du signalement et cliquez sur le bouton "Répondre".

diff --git a/app/views/mails/professional/reportsLastChanceReminder.scala.html b/app/views/mails/professional/reportsLastChanceReminder.scala.html new file mode 100644 index 00000000..7b9ea3b4 --- /dev/null +++ b/app/views/mails/professional/reportsLastChanceReminder.scala.html @@ -0,0 +1,71 @@ +@import utils.FrontRoute +@import models.report.Report +@import java.time.Period +@import java.time.OffsetDateTime +@import java.time.Duration +@(reports: List[Report], delay: Period)(implicit frontRoute: FrontRoute) + +@views.html.mails.layout(s"Expiration de signalement(s).") { +

+ Bonjour, +

+ +

+ Vous avez @reports.length @plural(reports, "nouveau signalement", "nouveaux signalements") en attente depuis plus de @delay.getDays jours concernant votre entreprise : +

+ +

+ @views.html.fragments.addressFromReport(reports.head, includeSiret = true) +

+ +

+ @plural(reports, "Ce signalement expire", "Ces signalements expirent") demain. Passé ce délai, vous pourrez toujours @plural(reports, "le", "les") lire mais vous ne pourrez plus y répondre. +

+ +

+ Pour @plural(reports, "le", "les") consulter, il vous suffit de vous connecter sur votre Espace Professionnel + à l'aide de votre adresse e-mail et du mot de passe que vous avez créé à votre première connexion sur SignalConso. +

+ +

+ Si vous avez oublié votre mot de passe, vous pouvez le réinitialiser directement depuis la page de connexion. +

+ +

+ Pour apporter une réponse, allez sur votre Espace Professionnel. Dans le détail de chaque signalement, cliquez sur le bouton “Répondre”. +

+ +

+ Vous pouvez également indiquer si vous estimez qu'un signalement est infondé ou ne concerne pas votre entreprise. +

+ +

+ Ce service public est facultatif et gratuit. + À travers SignalConso, notre objectif est d’établir un rapport de confiance et de + transparence entre les consommateurs, les professionnels et les services de la DGCCRF. +

+ +

Cordialement,

+ +

+ L'équipe SignalConso +

+ + @views.html.fragments.linkNotificationsManager() +} + +@plural(reports: List[Report], s: String, p: String) = { + @if(reports.length > 1) { + @p + } else { + @s + } +} + +@highlight_expiration(expirationDate: OffsetDateTime) = { + @if(Duration.between(OffsetDateTime.now(), expirationDate).getSeconds <= 604800) { + @expirationDate.format(java.time.format.DateTimeFormatter.ofPattern("dd/MM/yyyy")) + } else { + @expirationDate.format(java.time.format.DateTimeFormatter.ofPattern("dd/MM/yyyy")) + } +} \ No newline at end of file diff --git a/app/views/mails/professional/reportsTransmittedReminder.scala.html b/app/views/mails/professional/reportsTransmittedReminder.scala.html index a9726766..11fabccb 100644 --- a/app/views/mails/professional/reportsTransmittedReminder.scala.html +++ b/app/views/mails/professional/reportsTransmittedReminder.scala.html @@ -31,7 +31,7 @@

- Pour apporter une réponse, allez dans le détail de chaque signalement et cliquez sur le bouton "Répondre à ce signalement". + Pour apporter une réponse, allez dans le détail de chaque signalement et cliquez sur le bouton "Répondre".

diff --git a/app/views/mails/professional/reportsUnreadReminder.scala.html b/app/views/mails/professional/reportsUnreadReminder.scala.html index b5cf5798..4a01e0e0 100644 --- a/app/views/mails/professional/reportsUnreadReminder.scala.html +++ b/app/views/mails/professional/reportsUnreadReminder.scala.html @@ -43,7 +43,7 @@

- Pour apporter une réponse, allez sur votre Espace Professionnel. Dans le détail de chaque signalement, cliquez sur le bouton “Apporter une réponse à ce signalement”. + Pour apporter une réponse, allez sur votre Espace Professionnel. Dans le détail de chaque signalement, cliquez sur le bouton “Répondre”.