Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(invitation_email): add new scheduler after seven days #468

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
28 changes: 28 additions & 0 deletions app/domain/company.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 je me demande juste s'il ne faudrait pas s'assurer qu'on n'a pas déjà envoyé l'email de relance à cette personne ? Car vu qu'on regarde ceux qui ont reçu l'autre email il y a au moins 7 jours, il risque de recevoir le rappel tous les jours non ?

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()
)
25 changes: 19 additions & 6 deletions app/helpers/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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,
Expand All @@ -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):
Expand All @@ -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)
Expand Down
1 change: 1 addition & 0 deletions app/helpers/mail_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 3 additions & 0 deletions app/jobs/emails/bizdev/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@
from .send_reminder_no_invitation_emails import (
send_reminder_no_invitation_emails,
)
from .send_invitation_emails import (
send_invitation_emails,
)
31 changes: 31 additions & 0 deletions app/jobs/emails/bizdev/send_invitation_emails.py
Original file line number Diff line number Diff line change
@@ -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.")
40 changes: 20 additions & 20 deletions app/templates/invitation_email.html
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
{% extends "transactional_base.html" %}
{% import 'button.html' as button %}

{% block subject %}
{{ company_name }} vous invite à rejoindre Mobilic
{% endblock %}

{% block body %}
<p>Bonjour{% if first_name %} {{first_name | capitalize}}{% endif %},</p>
{% if not first_name %}
<p>Bonjour{% if first_name %} {{ first_name | capitalize }}{% endif %},</p>
{% if scheduled_reminder %}
<p>L'entreprise <strong>{{ company_name | upper }}</strong> vous rappelle que vous avez été invité à créer votre compte
sur <strong>Mobilic</strong>, l'outil numérique pour suivre et protéger vos droits en tant que salarié.</p>
<p>Grâce à <strong>Mobilic</strong>, vous pourrez facilement :</p>
<ul>
<li>Enregistrer vos heures de travail en toute simplicité</li>
<li>Assurer le respect de vos droits au quotidien</li>
</ul>
<p><strong>Il vous suffit de quelques clics pour activer votre compte et être prêt(e) à l'utiliser ! </strong></p>
<p>Cliquez sur le bouton ci-dessous pour créer votre compte ou l'associer à <strong>{{ company_name | upper }}</strong> :</p>
{{ button.button('Activer mon compte', invitation_link) }}
<p><strong>Petit rappel important :</strong> L’enregistrement de votre temps de travail via Mobilic ou le livret
individuel de contrôle (LIC) est obligatoire dans votre secteur.</p>
<p>À très bientôt sur Mobilic !</p>
{% else %}
<p>
{% if reminder %}
L'entreprise <strong>{{company_name | upper}}</strong> vous rappelle que vous avez été invité
L'entreprise <strong>{{ company_name | upper }}</strong> vous rappelle que vous avez été invité
{% else %}
Vous avez été invité(e) par l’entreprise <strong>{{company_name | upper}}</strong>
Vous avez été invité(e) par l’entreprise <strong>{{ company_name | upper }}</strong>
{% endif %} à créer un compte Mobilic pour enregistrer votre temps de travail.</p>
<p>Mobilic est la plateforme gouvernementale qui simplifie <strong>l'enregistrement et le suivi du temps de travail</strong> des travailleurs mobiles du transport routier léger et du déménagement.</p>
<p>Pour créer votre compte ou rattacher votre compte existant à l'entreprise <strong>{{company_name | upper}}</strong> cliquez sur le bouton d'activation suivant :</p>
{{button.button('Activer mon compte', invitation_link)}}
{% else %}
<p>
{% if reminder %}
L'entreprise <strong>{{company_name | upper}}</strong> vous rappelle que vous avez été invité à la rejoindre
{% else %}
Vous avez été invité(e) à rejoindre l'entreprise <strong>{{company_name | upper}}</strong>
{% endif %} sur Mobilic.
</p>
<p>Pour rattacher votre compte à l'entreprise <strong>{{company_name | upper}}</strong> cliquez sur le bouton d'activation suivant :</p>
{{button.button('Activer mon compte', invitation_link)}}
<p>Pour créer votre compte ou rattacher votre compte existant à l'entreprise <strong>{{ company_name | upper }}</strong> cliquez sur le bouton d'activation suivant :</p>
{{ button.button('Activer mon compte', invitation_link) }}
{% endif %}
<p>Bien à vous,</p>
{% endblock %}
Loading