diff --git a/app/commands.py b/app/commands.py index 755f15c8..2a5274f8 100644 --- a/app/commands.py +++ b/app/commands.py @@ -295,12 +295,14 @@ def send_daily_emails(): send_companies_without_any_employee_invitation_emails, send_companies_with_employees_but_without_activities_emails, send_reminder_no_invitation_emails, + send_invitation_emails, ) send_onboarding_emails(date.today()) send_companies_without_any_employee_invitation_emails(date.today()) send_companies_with_employees_but_without_activities_emails(date.today()) send_reminder_no_invitation_emails(date.today()) + send_invitation_emails(date.today()) from app.jobs.emails.cgu import ( send_expiry_warning_email, diff --git a/app/domain/company.py b/app/domain/company.py index 44768b3b..ae7c388d 100644 --- a/app/domain/company.py +++ b/app/domain/company.py @@ -5,6 +5,7 @@ from sqlalchemy import exists, and_ from sqlalchemy import func, or_ from sqlalchemy.sql.functions import now +from sqlalchemy.orm import joinedload from app import db from app.helpers.mail_type import EmailType @@ -362,3 +363,30 @@ def find_admins_still_without_invitations( Employment.validation_status == EmploymentRequestValidationStatus.APPROVED, ).all() + + +def find_employee_for_invitation( + first_employee_invitation_date, companies_to_exclude=None +): + + return ( + db.session.query(Employment) + .options(joinedload(Employment.company)) + .join(Email, Email.employment_id == Employment.id) + .filter( + Email.type == EmailType.INVITATION, + Email.user_id.is_(None), + Email.creation_time + <= datetime.datetime.combine( + first_employee_invitation_date, + datetime.datetime.max.time(), + ), + Employment.has_admin_rights == False, + Employment.user_id.is_(None), + Employment.company_id.notin_(companies_to_exclude or []), + Employment.validation_status + == EmploymentRequestValidationStatus.PENDING, + ) + .yield_per(1000) + .all() + ) diff --git a/app/helpers/mail.py b/app/helpers/mail.py index 0a7da900..d8e1dbac 100644 --- a/app/helpers/mail.py +++ b/app/helpers/mail.py @@ -366,7 +366,9 @@ def remove_email_from_contact_list(self, email, contact_list): email, contact_list, action=MailjetSubscriptionActions.REMOVE ) - def generate_employee_invite(self, employment, reminder=False): + def generate_employee_invite( + self, employment, reminder=False, scheduled_reminder=False + ): if not employment.invite_token: raise ValueError( f"Cannot send invite for employment {employment} : it is already bound to a user" @@ -379,12 +381,18 @@ def generate_employee_invite(self, employment, reminder=False): invitation_link = f"{app.config['FRONTEND_URL']}/invite?token={employment.invite_token}" company_name = employment.company.name - subject = f"{'Rappel : ' if reminder else ''}{company_name} vous invite à rejoindre Mobilic." + subject = ( + f"{'Rappel : Urgent ! ' if scheduled_reminder else ''}" + f"{'Rappel : ' if reminder else ''}" + f"Votre entreprise {company_name} vous invite à rejoindre Mobilic." + ) return Mailer._create_message_from_flask_template( - "invitation_email.html", + template="invitation_email.html", subject=subject, - type_=EmailType.INVITATION, + type_=EmailType.SCHEDULED_INVITATION + if scheduled_reminder + else EmailType.INVITATION, recipient=employment.user.email if employment.user else employment.email, @@ -395,6 +403,7 @@ def generate_employee_invite(self, employment, reminder=False): invitation_link=Markup(invitation_link), company_name=company_name, reminder=reminder, + scheduled_reminder=scheduled_reminder, ) def send_employee_invite(self, employment, reminder=False): @@ -403,9 +412,13 @@ def send_employee_invite(self, employment, reminder=False): _disable_commit=True, ) - def batch_send_employee_invites(self, employments, reminder=False): + def batch_send_employee_invites( + self, employments, reminder=False, scheduled_reminder=False + ): messages = [ - self.generate_employee_invite(e, reminder=reminder) + self.generate_employee_invite( + e, reminder=reminder, scheduled_reminder=scheduled_reminder + ) for e in employments ] self.send_batch(messages, _disable_commit=True) diff --git a/app/helpers/mail_type.py b/app/helpers/mail_type.py index 3f630bdf..ea3b5b33 100644 --- a/app/helpers/mail_type.py +++ b/app/helpers/mail_type.py @@ -6,6 +6,7 @@ class EmailType(str, Enum): COMPANY_CREATION = "company_creation" EMPLOYMENT_VALIDATION = "employment_validation_confirmation" INVITATION = "invitation" + SCHEDULED_INVITATION = "scheduled_invitation" MISSION_CHANGES_WARNING = "mission_changes_warning" NEW_MISSION_INFORMATION = "new_mission_information" RESET_PASSWORD = "reset_password" diff --git a/app/jobs/emails/bizdev/__init__.py b/app/jobs/emails/bizdev/__init__.py index 28ea4032..9497036d 100644 --- a/app/jobs/emails/bizdev/__init__.py +++ b/app/jobs/emails/bizdev/__init__.py @@ -8,3 +8,6 @@ from .send_reminder_no_invitation_emails import ( send_reminder_no_invitation_emails, ) +from .send_invitation_emails import ( + send_invitation_emails, +) diff --git a/app/jobs/emails/bizdev/send_invitation_emails.py b/app/jobs/emails/bizdev/send_invitation_emails.py new file mode 100644 index 00000000..d6f660a2 --- /dev/null +++ b/app/jobs/emails/bizdev/send_invitation_emails.py @@ -0,0 +1,31 @@ +from datetime import timedelta + +from app import app, mailer +from app.domain.company import find_employee_for_invitation +from app.jobs import log_execution + +NB_DAYS_AGO = 7 + + +@log_execution +def send_invitation_emails(today): + app.logger.info("Starting the invitation email sending process.") + + trigger_date = today - timedelta(days=NB_DAYS_AGO) + + employments = find_employee_for_invitation(trigger_date) + app.logger.info( + f"Found {len(employments)} employments for sending invitations." + ) + + if employments: + try: + mailer.batch_send_employee_invites( + employments, reminder=False, scheduled_reminder=True + ) + app.logger.info(f"Emails sent for {len(employments)} employments.") + except Exception as e: + app.logger.error("Error during batch email sending.") + app.logger.exception(e) + + app.logger.info("Finished the invitation email sending process.") diff --git a/app/templates/invitation_email.html b/app/templates/invitation_email.html index a975e756..2e202415 100644 --- a/app/templates/invitation_email.html +++ b/app/templates/invitation_email.html @@ -1,32 +1,32 @@ {% extends "transactional_base.html" %} {% import 'button.html' as button %} -{% block subject %} -{{ company_name }} vous invite à rejoindre Mobilic -{% endblock %} - {% block body %} -

Bonjour{% if first_name %} {{first_name | capitalize}}{% endif %},

- {% if not first_name %} +

Bonjour{% if first_name %} {{ first_name | capitalize }}{% endif %},

+ {% if scheduled_reminder %} +

L'entreprise {{ company_name | upper }} vous rappelle que vous avez été invité à créer votre compte + sur Mobilic, l'outil numérique pour suivre et protéger vos droits en tant que salarié.

+

Grâce à Mobilic, vous pourrez facilement :

+ +

Il vous suffit de quelques clics pour activer votre compte et être prêt(e) à l'utiliser !

+

Cliquez sur le bouton ci-dessous pour créer votre compte ou l'associer à {{ company_name | upper }} :

+ {{ button.button('Activer mon compte', invitation_link) }} +

Petit rappel important : L’enregistrement de votre temps de travail via Mobilic ou le livret + individuel de contrôle (LIC) est obligatoire dans votre secteur.

+

À très bientôt sur Mobilic !

+ {% else %}

{% if reminder %} - L'entreprise {{company_name | upper}} vous rappelle que vous avez été invité + L'entreprise {{ company_name | upper }} vous rappelle que vous avez été invité {% else %} - Vous avez été invité(e) par l’entreprise {{company_name | upper}} + Vous avez été invité(e) par l’entreprise {{ company_name | upper }} {% endif %} à créer un compte Mobilic pour enregistrer votre temps de travail.

Mobilic est la plateforme gouvernementale qui simplifie l'enregistrement et le suivi du temps de travail des travailleurs mobiles du transport routier léger et du déménagement.

-

Pour créer votre compte ou rattacher votre compte existant à l'entreprise {{company_name | upper}} cliquez sur le bouton d'activation suivant :

- {{button.button('Activer mon compte', invitation_link)}} - {% else %} -

- {% if reminder %} - L'entreprise {{company_name | upper}} vous rappelle que vous avez été invité à la rejoindre - {% else %} - Vous avez été invité(e) à rejoindre l'entreprise {{company_name | upper}} - {% endif %} sur Mobilic. -

-

Pour rattacher votre compte à l'entreprise {{company_name | upper}} cliquez sur le bouton d'activation suivant :

- {{button.button('Activer mon compte', invitation_link)}} +

Pour créer votre compte ou rattacher votre compte existant à l'entreprise {{ company_name | upper }} cliquez sur le bouton d'activation suivant :

+ {{ button.button('Activer mon compte', invitation_link) }} {% endif %}

Bien à vous,

{% endblock %}