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”.