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(Emails): avoir les logs d'envois des TemplateTransactional #1337

Merged
merged 4 commits into from
Jul 18, 2024
Merged
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
21 changes: 20 additions & 1 deletion lemarche/conversations/admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.contrib import admin
from django.http import HttpResponseRedirect

from lemarche.conversations.models import Conversation, TemplateTransactional
from lemarche.conversations.models import Conversation, TemplateTransactional, TemplateTransactionalSendLog
from lemarche.utils.admin.admin_site import admin_site
from lemarche.utils.fields import pretty_print_readonly_jsonfield_to_table
from lemarche.www.conversations.tasks import send_first_email_from_conversation
Expand Down Expand Up @@ -144,3 +144,22 @@ class TemplateTransactionalAdmin(admin.ModelAdmin):
("Paramètres d'envoi", {"fields": ("mailjet_id", "brevo_id", "source", "is_active")}),
("Dates", {"fields": ("created_at", "updated_at")}),
)


@admin.register(TemplateTransactionalSendLog, site=admin_site)
class TemplateTransactionalSendLogAdmin(admin.ModelAdmin):
list_display = ["id", "template_transactional", "content_type", "created_at"]
list_filter = [("content_type", admin.RelatedOnlyFieldListFilter)]
search_fields = ["id", "template_transactional"]
search_help_text = "Cherche sur les champs : ID, Template transactionnel"

readonly_fields = [field.name for field in TemplateTransactionalSendLog._meta.fields]

def has_add_permission(self, request):
return False

def has_change_permission(self, request, obj=None):
return False

def has_delete_permission(self, request, obj=None):
return False
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Generated by Django 4.2.13 on 2024-07-15 10:43

import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("contenttypes", "0002_remove_content_type_name"),
("conversations", "0015_remove_templatetransactional_email_from_email_and_more"),
]

operations = [
migrations.CreateModel(
name="TemplateTransactionalSendLog",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("object_id", models.PositiveBigIntegerField(blank=True, null=True)),
("extra_data", models.JSONField(default=dict, editable=False, verbose_name="Données complémentaires")),
(
"created_at",
models.DateTimeField(default=django.utils.timezone.now, verbose_name="Date de création"),
),
("updated_at", models.DateTimeField(auto_now=True, verbose_name="Date de modification")),
(
"content_type",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="contenttypes.contenttype",
),
),
(
"template_transactional",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="send_logs",
to="conversations.templatetransactional",
verbose_name="Template transactionnel",
),
),
],
options={
"verbose_name": "Template transactionnel: logs d'envois",
"verbose_name_plural": "Templates transactionnels: logs d'envois",
},
),
]
59 changes: 41 additions & 18 deletions lemarche/conversations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
from uuid import uuid4

from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import IntegrityError, models
from django.db.models import Func, IntegerField, Q
from django.utils import timezone
Expand Down Expand Up @@ -254,6 +256,9 @@ def get_template_id(self):
return self.brevo_id
return None

def create_send_log(self, **kwargs):
TemplateTransactionalSendLog.objects.create(template_transactional=self, **kwargs)

def send_transactional_email(
self,
recipient_email,
Expand All @@ -264,23 +269,41 @@ def send_transactional_email(
from_name=settings.DEFAULT_FROM_NAME,
):
if self.is_active:
args = {
"template_id": self.get_template_id,
"recipient_email": recipient_email,
"recipient_name": recipient_name,
"variables": variables,
"subject": subject,
"from_email": from_email,
"from_name": from_name,
}
if self.source == conversation_constants.SOURCE_MAILJET:
api_mailjet.send_transactional_email_with_template(
template_id=self.get_template_id,
recipient_email=recipient_email,
recipient_name=recipient_name,
variables=variables,
subject=subject,
from_email=from_email,
from_name=from_name,
)
result = api_mailjet.send_transactional_email_with_template(**args)
elif self.source == conversation_constants.SOURCE_BREVO:
api_brevo.send_transactional_email_with_template(
template_id=self.get_template_id,
recipient_email=recipient_email,
recipient_name=recipient_name,
variables=variables,
subject=subject,
from_email=from_email,
from_name=from_name,
)
result = api_brevo.send_transactional_email_with_template(**args)
# create log
self.create_send_log(extra_data={"source": self.source, "variables": args, "response": result()})


class TemplateTransactionalSendLog(models.Model):
template_transactional = models.ForeignKey(
"conversations.TemplateTransactional",
verbose_name="Template transactionnel",
on_delete=models.SET_NULL,
null=True,
related_name="send_logs",
)

content_type = models.ForeignKey(ContentType, blank=True, null=True, on_delete=models.CASCADE)
object_id = models.PositiveBigIntegerField(blank=True, null=True)
content_object = GenericForeignKey("content_type", "object_id")

extra_data = models.JSONField(verbose_name="Données complémentaires", editable=False, default=dict)

created_at = models.DateTimeField(verbose_name="Date de création", default=timezone.now)
updated_at = models.DateTimeField(verbose_name="Date de modification", auto_now=True)

class Meta:
verbose_name = "Template transactionnel: logs d'envois"
verbose_name_plural = "Templates transactionnels: logs d'envois"
1 change: 1 addition & 0 deletions lemarche/siaes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,6 +871,7 @@ class Siae(models.Model):
"Nombre de besoins intéressés", help_text=RECALCULATED_FIELD_HELP_TEXT, default=0
)
logs = models.JSONField(verbose_name="Logs historiques", editable=False, default=list)
transactional_send_logs = GenericRelation("conversations.TemplateTransactionalSendLog", related_query_name="siae")
source = models.CharField(
max_length=20, choices=siae_constants.SOURCE_CHOICES, default=siae_constants.SOURCE_STAFF_C4_CREATED
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
La structure {{ siae_name|safe }} souhaite répondre en co-traitance
La structure {{ SIAE_NAME|safe }} souhaite répondre en co-traitance

Titre : {{ tender_title|safe }}
Type : {{ tender_kind|safe }}
Contact email de l'ESI: {{ siae_contact_email|safe }}
SIRET : {{ siae_siret|safe }}
Titre : {{ TENDER_TITLE|safe }}
Type : {{ TENDER_KIND|safe }}
Contact email de l'ESI: {{ SIAE_CONTACT_EMAIL|safe }}
SIRET : {{ SIAE_SIRET|safe }}

Lien dans l'admin : {{ tender_admin_url }}
Lien dans l'admin : {{ TENDER_ADMIN_URL }}
22 changes: 11 additions & 11 deletions lemarche/templates/tenders/create_notification_email_admin_body.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
Dépôt de besoin : ajout d'un nouveau {{ tender_kind|safe }}
Dépôt de besoin : ajout d'un nouveau {{ TENDER_KIND|safe }}

titre : {{ tender_title|safe }}
type : {{ tender_kind|safe }}
lieu d'intervention : {{ tender_location|safe }}
date de clôture des réponses : {{ tender_deadline_date|safe }}
contact : {{ tender_author_full_name|safe }}
entreprise : {{ tender_author_company|safe }}
si le Marché n'existait pas, auriez-vous consulté des prestataires inclusifs ? : {{ tender_scale_marche_useless|safe }}
status : {{ tender_status|safe }}
source: {{ tender_source|safe }}
titre : {{ TENDER_TITLE|safe }}
type : {{ TENDER_KIND|safe }}
lieu d'intervention : {{ TENDER_LOCATION|safe }}
date de clôture des réponses : {{ TENDER_DEADLINE_DATE|safe }}
contact : {{ TENDER_AUTHOR_FULL_NAME|safe }}
entreprise : {{ TENDER_AUTHOR_COMPANY|safe }}
si le Marché n'existait pas, auriez-vous consulté des prestataires inclusifs ? : {{ TENDER_SCALE_MARCHE_USELESS|safe }}
status : {{ TENDER_STATUS|safe }}
source: {{ TENDER_SOURCE|safe }}

Lien dans l'admin : {{ tender_admin_url }}
Lien dans l'admin : {{ TENDER_ADMIN_URL }}
1 change: 1 addition & 0 deletions lemarche/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ class User(AbstractUser):
"Date de dernière visite sur la page 'besoins'", blank=True, null=True
)
extra_data = models.JSONField(verbose_name="Données complémentaires", editable=False, default=dict)
transactional_send_logs = GenericRelation("conversations.TemplateTransactionalSendLog", related_query_name="user")

# is_active, is_staff, is_superuser

Expand Down
3 changes: 2 additions & 1 deletion lemarche/utils/apis/api_brevo.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,8 @@ def send_transactional_email_with_template(
send_smtp_email = sib_api_v3_sdk.SendSmtpEmail(**data)
response = api_instance.send_transac_email(send_smtp_email)
logger.info("Brevo: send transactional email with template")
return response
# {'message_id': '<[email protected]>', 'message_ids': None}
return response.to_dict()
except ApiException as e:
print(f"Exception when calling SMTPApi->send_transac_email: {e}")
else:
Expand Down
1 change: 1 addition & 0 deletions lemarche/utils/apis/api_mailjet.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def send_transactional_email_with_template(
response = client.post(SEND_URL, json=data)
response.raise_for_status()
logger.info("Mailjet: send transactional email with template")
# {'Messages': [{'Status': 'success', 'CustomID': '', 'To': [{'Email': '<recipient_email>', 'MessageUUID': '<uuid>', 'MessageID': <id>, 'MessageHref': 'https://api.mailjet.com/v3/REST/message/<id>'}], 'Cc': [], 'Bcc': []}]} # noqa
return response.json()
except requests.exceptions.HTTPError as e:
logger.error("Error while fetching `%s`: %s", e.request.url, e)
Expand Down
18 changes: 18 additions & 0 deletions lemarche/www/dashboard_siaes/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ def send_siae_user_request_email_to_assignee(siae_user_request):
recipient_name = siae_user_request.assignee.full_name

variables = {
"ASSIGNEE_ID": siae_user_request.assignee.id,
"ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name,
"INITIATIOR_ID": siae_user_request.initiator.id,
"INITIATOR_FULL_NAME": siae_user_request.initiator.full_name,
"SIAE_ID": siae_user_request.siae.id,
"SIAE_NAME": siae_user_request.siae.name_display,
"SIAE_USERS_URL": f"https://{get_domain_url()}{reverse_lazy('dashboard_siaes:siae_users', args=[siae_user_request.siae.slug])}", # noqa
}
Expand Down Expand Up @@ -57,8 +60,11 @@ def send_siae_user_request_response_email_to_initiator(siae_user_request):
recipient_name = siae_user_request.initiator.full_name

variables = {
"ASSIGNEE_ID": siae_user_request.assignee.id,
"ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name,
"INITIATIOR_ID": siae_user_request.initiator.id,
"INITIATOR_FULL_NAME": siae_user_request.initiator.full_name,
"SIAE_ID": siae_user_request.siae.id,
"SIAE_NAME": siae_user_request.siae.name_display,
"DASHBOARD_URL": f"https://{get_domain_url()}{reverse_lazy('dashboard:home')}",
}
Expand Down Expand Up @@ -99,8 +105,11 @@ def send_siae_user_request_reminder_3_days_email_to_assignee(siae_user_request):
recipient_name = siae_user_request.assignee.full_name

variables = {
"ASSIGNEE_ID": siae_user_request.assignee.id,
"ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name,
"INITIATIOR_ID": siae_user_request.initiator.id,
"INITIATOR_FULL_NAME": siae_user_request.initiator.full_name,
"SIAE_ID": siae_user_request.siae.id,
"SIAE_NAME": siae_user_request.siae.name_display,
"SIAE_USERS_URL": f"https://{get_domain_url()}{reverse_lazy('dashboard_siaes:siae_users', args=[siae_user_request.siae.slug])}", # noqa
}
Expand Down Expand Up @@ -131,8 +140,11 @@ def send_siae_user_request_reminder_3_days_email_to_initiator(siae_user_request)
recipient_name = siae_user_request.initiator.full_name

variables = {
"ASSIGNEE_ID": siae_user_request.assignee.id,
"ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name,
"INITIATIOR_ID": siae_user_request.initiator.id,
"INITIATOR_FULL_NAME": siae_user_request.initiator.full_name,
"SIAE_ID": siae_user_request.siae.id,
"SIAE_NAME": siae_user_request.siae.name_display,
}

Expand Down Expand Up @@ -172,8 +184,11 @@ def send_siae_user_request_reminder_8_days_email_to_assignee(siae_user_request):
recipient_name = siae_user_request.assignee.full_name

variables = {
"ASSIGNEE_ID": siae_user_request.assignee.id,
"ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name,
"INITIATIOR_ID": siae_user_request.initiator.id,
"INITIATOR_FULL_NAME": siae_user_request.initiator.full_name,
"SIAE_ID": siae_user_request.siae.id,
"SIAE_NAME": siae_user_request.siae.name_display,
"SIAE_USERS_URL": f"https://{get_domain_url()}{reverse_lazy('dashboard_siaes:siae_users', args=[siae_user_request.siae.slug])}", # noqa
}
Expand Down Expand Up @@ -204,8 +219,11 @@ def send_siae_user_request_reminder_8_days_email_to_initiator(siae_user_request)
recipient_name = siae_user_request.initiator.full_name

variables = {
"ASSIGNEE_ID": siae_user_request.assignee.id,
"ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name,
"INITIATIOR_ID": siae_user_request.initiator.id,
"INITIATOR_FULL_NAME": siae_user_request.initiator.full_name,
"SIAE_ID": siae_user_request.siae.id,
"SIAE_NAME": siae_user_request.siae.name_display,
"SUPPORT_URL": f"https://{get_domain_url()}{reverse_lazy('pages:contact')}?siret={siae_user_request.siae.siret}", # noqa
}
Expand Down
Loading
Loading