Skip to content

Commit

Permalink
refactor(Emails): ajout du User ou Siae dans les TemplateTransactiona…
Browse files Browse the repository at this point in the history
…lSendLogs (#1352)
  • Loading branch information
raphodn authored Jul 25, 2024
1 parent f527985 commit 88fa396
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 51 deletions.
84 changes: 79 additions & 5 deletions lemarche/conversations/admin.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from django.contrib import admin
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.utils.html import format_html

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.utils.fields import pretty_print_readonly_jsonfield, pretty_print_readonly_jsonfield_to_table
from lemarche.www.conversations.tasks import send_first_email_from_conversation


Expand Down Expand Up @@ -134,27 +136,66 @@ def data_display(self, conversation: Conversation = None):

@admin.register(TemplateTransactional, site=admin_site)
class TemplateTransactionalAdmin(admin.ModelAdmin):
list_display = ["id", "name", "code", "mailjet_id", "brevo_id", "source", "is_active", "created_at", "updated_at"]
list_display = [
"id",
"name",
"code",
"mailjet_id",
"brevo_id",
"source",
"is_active",
"template_transactional_send_log_count_with_link",
"created_at",
"updated_at",
]
search_fields = ["id", "name", "code", "mailjet_id", "brevo_id"]

readonly_fields = ["code", "created_at", "updated_at"]
readonly_fields = ["code", "template_transactional_send_log_count_with_link", "created_at", "updated_at"]

fieldsets = (
(None, {"fields": ("name", "code", "description")}),
("Paramètres d'envoi", {"fields": ("mailjet_id", "brevo_id", "source", "is_active")}),
("Stats", {"fields": ("template_transactional_send_log_count_with_link",)}),
("Dates", {"fields": ("created_at", "updated_at")}),
)

def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.with_stats()
return qs

def template_transactional_send_log_count_with_link(self, obj):
url = (
reverse("admin:conversations_templatetransactionalsendlog_changelist")
+ f"?template_transactionals__in={obj.id}"
)
return format_html(f'<a href="{url}">{obj.send_log_count}</a>')

template_transactional_send_log_count_with_link.short_description = "Logs d'envois"
template_transactional_send_log_count_with_link.admin_order_field = "send_log_count"


@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)]
list_display = ["id", "template_transactional", "recipient_content_type", "parent_content_type", "created_at"]
list_filter = [
"template_transactional",
("recipient_content_type", admin.RelatedOnlyFieldListFilter),
("parent_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]

fieldsets = (
(None, {"fields": ("template_transactional",)}),
("Envoyé à…", {"fields": ("recipient_content_type", "recipient_object_id_with_link")}),
("Contexte…", {"fields": ("parent_content_type", "parent_object_id_with_link")}),
("Logs", {"fields": ("extra_data_display",)}),
("Dates", {"fields": ("created_at", "updated_at")}),
)

def has_add_permission(self, request):
return False

Expand All @@ -163,3 +204,36 @@ def has_change_permission(self, request, obj=None):

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

def recipient_object_id_with_link(self, obj):
if obj.recipient_content_type and obj.recipient_object_id:
if obj.recipient_content_type.model == "tender":
url = reverse("admin:tenders_tender_change", args=[obj.recipient_object_id])
return format_html(f'<a href="{url}">{obj.recipient_object_id}</a>')
elif obj.recipient_content_type.model == "siae":
url = reverse("admin:siaes_siae_change", args=[obj.recipient_object_id])
return format_html(f'<a href="{url}">{obj.recipient_object_id}</a>')
elif obj.recipient_content_type.model == "user":
url = reverse("admin:users_user_change", args=[obj.recipient_object_id])
return format_html(f'<a href="{url}">{obj.recipient_object_id}</a>')
return obj.recipient_object.id

def parent_object_id_with_link(self, obj):
if obj.parent_content_type and obj.parent_object_id:
if obj.parent_content_type.model == "tender":
url = reverse("admin:tenders_tender_change", args=[obj.parent_object_id])
return format_html(f'<a href="{url}">{obj.parent_object_id}</a>')
if obj.parent_content_type.model == "tendersiae":
url = reverse("admin:tenders_tendersiae_change", args=[obj.parent_object_id])
return format_html(f'<a href="{url}">{obj.parent_object_id}</a>')
elif obj.parent_content_type.model == "siaeuserrequest":
url = reverse("admin:siaes_siaeuserrequest_change", args=[obj.parent_object_id])
return format_html(f'<a href="{url}">{obj.parent_object_id}</a>')
return obj.context_object.id

def extra_data_display(self, instance: TemplateTransactionalSendLog = None):
if instance:
return pretty_print_readonly_jsonfield(instance.extra_data)
return "-"

extra_data_display.short_description = TemplateTransactionalSendLog._meta.get_field("extra_data").verbose_name
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.13 on 2024-07-15 10:43
# Generated by Django 4.2.13 on 2024-07-22 10:30

import django.db.models.deletion
import django.utils.timezone
Expand All @@ -16,19 +16,31 @@ class Migration(migrations.Migration):
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)),
("recipient_object_id", models.PositiveBigIntegerField(blank=True, null=True)),
("parent_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",
"parent_content_type",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="parent_send_logs",
to="contenttypes.contenttype",
),
),
(
"recipient_content_type",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="recipient_send_logs",
to="contenttypes.contenttype",
),
),
Expand Down
35 changes: 30 additions & 5 deletions lemarche/conversations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
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.db.models import Count, Func, IntegerField, Q
from django.utils import timezone
from django.utils.text import slugify
from django_extensions.db.fields import ShortUUIDField
Expand Down Expand Up @@ -198,6 +198,13 @@ def set_validated(self):
self.save()


class TemplateTransactionalQuerySet(models.QuerySet):
def with_stats(self):
return self.annotate(
send_log_count=Count("send_logs"),
)


class TemplateTransactional(models.Model):
name = models.CharField(verbose_name="Nom", max_length=255)
code = models.CharField(
Expand Down Expand Up @@ -238,6 +245,8 @@ class TemplateTransactional(models.Model):
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)

objects = models.Manager.from_queryset(TemplateTransactionalQuerySet)()

class Meta:
verbose_name = "Template transactionnel"
verbose_name_plural = "Templates transactionnels"
Expand Down Expand Up @@ -267,6 +276,8 @@ def send_transactional_email(
subject=None,
from_email=settings.DEFAULT_FROM_EMAIL,
from_name=settings.DEFAULT_FROM_NAME,
recipient_content_object=None,
parent_content_object=None,
):
if self.is_active:
args = {
Expand All @@ -283,7 +294,11 @@ def send_transactional_email(
elif self.source == conversation_constants.SOURCE_BREVO:
result = api_brevo.send_transactional_email_with_template(**args)
# create log
self.create_send_log(extra_data={"source": self.source, "args": args, "response": result()})
self.create_send_log(
recipient_content_object=recipient_content_object,
parent_content_object=parent_content_object,
extra_data={"source": self.source, "args": args, "response": result()},
)


class TemplateTransactionalSendLog(models.Model):
Expand All @@ -295,9 +310,19 @@ class TemplateTransactionalSendLog(models.Model):
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")
# the object that is the recipient of the email (User, Siae...)
recipient_content_type = models.ForeignKey(
ContentType, blank=True, null=True, on_delete=models.CASCADE, related_name="recipient_send_logs"
)
recipient_object_id = models.PositiveBigIntegerField(blank=True, null=True)
recipient_content_object = GenericForeignKey("recipient_content_type", "recipient_object_id")

# the object that is the parent of the email (TenderSiae, SiaeUserRequest...)
parent_content_type = models.ForeignKey(
ContentType, blank=True, null=True, on_delete=models.CASCADE, related_name="parent_send_logs"
)
parent_object_id = models.PositiveBigIntegerField(blank=True, null=True)
parent_content_object = GenericForeignKey("parent_content_type", "parent_object_id")

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

Expand Down
31 changes: 13 additions & 18 deletions lemarche/notes/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,7 @@ class NoteAdmin(admin.ModelAdmin):
formfield_overrides = {models.TextField: {"widget": CKEditorWidget(config_name="admin_note_text")}}

fieldsets = (
(
None,
{
"fields": ("text", "author"),
},
),
(None, {"fields": ("text", "author")}),
("Rattachée à…", {"fields": ("content_type", "object_id_with_link")}),
("Dates", {"fields": ("created_at", "updated_at")}),
)
Expand All @@ -41,15 +36,15 @@ def save_model(self, request, obj: Note, form, change):
obj.author = request.user
obj.save()

def object_id_with_link(self, note):
if note.content_type and note.object_id:
if note.content_type.model == "tender":
url = reverse("admin:tenders_tender_change", args=[note.object_id])
return format_html(f'<a href="{url}">{note.object_id}</a>')
elif note.content_type.model == "siae":
url = reverse("admin:siaes_siae_change", args=[note.object_id])
return format_html(f'<a href="{url}">{note.object_id}</a>')
elif note.content_type.model == "user":
url = reverse("admin:users_user_change", args=[note.object_id])
return format_html(f'<a href="{url}">{note.object_id}</a>')
return note.object.id
def object_id_with_link(self, obj):
if obj.content_type and obj.object_id:
if obj.content_type.model == "tender":
url = reverse("admin:tenders_tender_change", args=[obj.object_id])
return format_html(f'<a href="{url}">{obj.object_id}</a>')
elif obj.content_type.model == "siae":
url = reverse("admin:siaes_siae_change", args=[obj.object_id])
return format_html(f'<a href="{url}">{obj.object_id}</a>')
elif obj.content_type.model == "user":
url = reverse("admin:users_user_change", args=[obj.object_id])
return format_html(f'<a href="{url}">{obj.object_id}</a>')
return obj.object.id
35 changes: 27 additions & 8 deletions lemarche/siaes/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from fieldsets_with_inlines import FieldsetsInlineMixin
from simple_history.admin import SimpleHistoryAdmin

from lemarche.conversations.models import Conversation
from lemarche.conversations.models import Conversation, TemplateTransactionalSendLog
from lemarche.labels.models import Label
from lemarche.networks.models import Network
from lemarche.notes.models import Note
Expand Down Expand Up @@ -212,6 +212,7 @@ class SiaeAdmin(FieldsetsInlineMixin, gis_admin.OSMGeoAdmin, SimpleHistoryAdmin)
"tender_detail_display_count_annotated_with_link",
"tender_detail_contact_click_count_annotated_with_link",
"tender_detail_not_interested_count_annotated_with_link",
"recipient_transactional_send_logs_count_with_link",
"brevo_company_id",
"extra_data_display",
"import_raw_object_display",
Expand Down Expand Up @@ -362,6 +363,7 @@ class SiaeAdmin(FieldsetsInlineMixin, gis_admin.OSMGeoAdmin, SimpleHistoryAdmin)
"fields": (
"signup_date",
"content_filled_basic_date",
"recipient_transactional_send_logs_count_with_link",
"brevo_company_id",
"extra_data_display",
),
Expand Down Expand Up @@ -665,6 +667,14 @@ def tender_detail_not_interested_count_annotated_with_link(self, siae):
"tender_detail_not_interested_count_annotated"
)

def recipient_transactional_send_logs_count_with_link(self, obj):
url = reverse("admin:conversations_templatetransactionalsendlog_changelist") + f"?siae__id__exact={obj.id}"
return format_html(f'<a href="{url}">{obj.recipient_transactional_send_logs.count()}</a>')

recipient_transactional_send_logs_count_with_link.short_description = (
TemplateTransactionalSendLog._meta.verbose_name
)

def logs_display(self, siae=None):
if siae:
return pretty_print_readonly_jsonfield(siae.logs)
Expand Down Expand Up @@ -700,13 +710,6 @@ class SiaeUserRequestAdmin(admin.ModelAdmin):
readonly_fields = [field.name for field in SiaeUserRequest._meta.fields]
fields = ["logs_display" if field_name == "logs" else field_name for field_name in readonly_fields]

def logs_display(self, siaeuserrequest=None):
if siaeuserrequest:
return pretty_print_readonly_jsonfield(siaeuserrequest.logs)
return "-"

logs_display.short_description = SiaeUserRequest._meta.get_field("logs").verbose_name

def has_add_permission(self, request):
return False

Expand All @@ -716,6 +719,22 @@ def has_change_permission(self, request, obj=None):
def has_delete_permission(self, request, obj=None):
return False

def parent_transactional_send_logs_count_with_link(self, obj):
url = (
reverse("admin:conversations_templatetransactionalsendlog_changelist")
+ f"?siaeuserrequest__id__exact={obj.id}"
)
return format_html(f'<a href="{url}">{obj.parent_transactional_send_logs.count()}</a>')

parent_transactional_send_logs_count_with_link.short_description = TemplateTransactionalSendLog._meta.verbose_name

def logs_display(self, siaeuserrequest=None):
if siaeuserrequest:
return pretty_print_readonly_jsonfield(siaeuserrequest.logs)
return "-"

logs_display.short_description = SiaeUserRequest._meta.get_field("logs").verbose_name


@admin.register(SiaeActivity, site=admin_site)
class SiaeActivityAdmin(admin.ModelAdmin):
Expand Down
13 changes: 12 additions & 1 deletion lemarche/siaes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,12 @@ 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")
recipient_transactional_send_logs = GenericRelation(
"conversations.TemplateTransactionalSendLog",
related_query_name="siae",
content_type_field="recipient_content_type",
object_id_field="recipient_object_id",
)
source = models.CharField(
max_length=20, choices=siae_constants.SOURCE_CHOICES, default=siae_constants.SOURCE_STAFF_C4_CREATED
)
Expand Down Expand Up @@ -1381,6 +1386,12 @@ class SiaeUserRequest(models.Model):
response = models.BooleanField(verbose_name="Réponse", blank=True, null=True)
response_date = models.DateTimeField("Date de la réponse", blank=True, null=True)

parent_transactional_send_logs = GenericRelation(
"conversations.TemplateTransactionalSendLog",
related_query_name="siaeuserrequest",
content_type_field="parent_content_type",
object_id_field="parent_object_id",
)
logs = models.JSONField(verbose_name="Logs des échanges", editable=False, default=list)

created_at = models.DateTimeField(verbose_name="Date de création", default=timezone.now)
Expand Down
Loading

0 comments on commit 88fa396

Please sign in to comment.