From f0c23f31c62e14af1e04df767298dbc65f9b70eb Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Thu, 18 Jul 2024 11:19:47 +0200 Subject: [PATCH 1/6] TemplateTransactionalSendLog: add content_object (Siae, User) --- lemarche/conversations/models.py | 5 ++++- lemarche/siaes/tasks.py | 3 +++ lemarche/www/auth/tasks.py | 2 ++ lemarche/www/dashboard_siaes/tasks.py | 12 ++++++++++++ lemarche/www/tenders/tasks.py | 14 ++++++++------ 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/lemarche/conversations/models.py b/lemarche/conversations/models.py index bdadea13f..d85b15e50 100644 --- a/lemarche/conversations/models.py +++ b/lemarche/conversations/models.py @@ -267,6 +267,7 @@ def send_transactional_email( subject=None, from_email=settings.DEFAULT_FROM_EMAIL, from_name=settings.DEFAULT_FROM_NAME, + content_object=None, ): if self.is_active: args = { @@ -283,7 +284,9 @@ 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( + content_object=content_object, extra_data={"source": self.source, "args": args, "response": result()} + ) class TemplateTransactionalSendLog(models.Model): diff --git a/lemarche/siaes/tasks.py b/lemarche/siaes/tasks.py index 2779fe1b4..df78993f4 100644 --- a/lemarche/siaes/tasks.py +++ b/lemarche/siaes/tasks.py @@ -43,7 +43,9 @@ def send_completion_reminder_email_to_siae(siae): recipient_name = siae_user.full_name variables = { + "SIAE_USER_ID": siae_user.id, "SIAE_USER_FIRST_NAME": siae_user.first_name, + "SIAE_ID": siae.id, "SIAE_NAME": siae.name_display, "SIAE_URL": get_object_share_url(siae), "SIAE_EDIT_URL": f"https://{get_domain_url()}{reverse_lazy('dashboard_siaes:siae_edit_contact', args=[siae.slug])}", # noqa @@ -53,6 +55,7 @@ def send_completion_reminder_email_to_siae(siae): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=siae_user, ) # log email diff --git a/lemarche/www/auth/tasks.py b/lemarche/www/auth/tasks.py index 926bc6998..94f94a08d 100644 --- a/lemarche/www/auth/tasks.py +++ b/lemarche/www/auth/tasks.py @@ -49,6 +49,7 @@ def send_new_user_password_reset_link(user: User): recipient_name = user.full_name variables = { + "USER_ID": user.id, "USER_FIRST_NAME": user.first_name, "USER_EMAIL": user.email, "PASSWORD_RESET_LINK": generate_password_reset_link(user), @@ -58,4 +59,5 @@ def send_new_user_password_reset_link(user: User): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=user, ) diff --git a/lemarche/www/dashboard_siaes/tasks.py b/lemarche/www/dashboard_siaes/tasks.py index 87f02755d..6dfe2b18d 100644 --- a/lemarche/www/dashboard_siaes/tasks.py +++ b/lemarche/www/dashboard_siaes/tasks.py @@ -17,6 +17,7 @@ def send_siae_user_request_email_to_assignee(siae_user_request): recipient_name = siae_user_request.assignee.full_name variables = { + "SIAE_USER_REQUEST_ID": siae_user_request.id, "ASSIGNEE_ID": siae_user_request.assignee.id, "ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name, "INITIATIOR_ID": siae_user_request.initiator.id, @@ -30,6 +31,7 @@ def send_siae_user_request_email_to_assignee(siae_user_request): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=siae_user_request.assignee, ) # log email @@ -60,6 +62,7 @@ def send_siae_user_request_response_email_to_initiator(siae_user_request): recipient_name = siae_user_request.initiator.full_name variables = { + "SIAE_USER_REQUEST_ID": siae_user_request.id, "ASSIGNEE_ID": siae_user_request.assignee.id, "ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name, "INITIATIOR_ID": siae_user_request.initiator.id, @@ -73,6 +76,7 @@ def send_siae_user_request_response_email_to_initiator(siae_user_request): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=siae_user_request.initiator, ) # log email @@ -105,6 +109,7 @@ def send_siae_user_request_reminder_3_days_email_to_assignee(siae_user_request): recipient_name = siae_user_request.assignee.full_name variables = { + "SIAE_USER_REQUEST_ID": siae_user_request.id, "ASSIGNEE_ID": siae_user_request.assignee.id, "ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name, "INITIATIOR_ID": siae_user_request.initiator.id, @@ -118,6 +123,7 @@ def send_siae_user_request_reminder_3_days_email_to_assignee(siae_user_request): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=siae_user_request.assignee, ) # log email @@ -140,6 +146,7 @@ def send_siae_user_request_reminder_3_days_email_to_initiator(siae_user_request) recipient_name = siae_user_request.initiator.full_name variables = { + "SIAE_USER_REQUEST_ID": siae_user_request.id, "ASSIGNEE_ID": siae_user_request.assignee.id, "ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name, "INITIATIOR_ID": siae_user_request.initiator.id, @@ -152,6 +159,7 @@ def send_siae_user_request_reminder_3_days_email_to_initiator(siae_user_request) recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=siae_user_request.initiator, ) # log email @@ -184,6 +192,7 @@ def send_siae_user_request_reminder_8_days_email_to_assignee(siae_user_request): recipient_name = siae_user_request.assignee.full_name variables = { + "SIAE_USER_REQUEST_ID": siae_user_request.id, "ASSIGNEE_ID": siae_user_request.assignee.id, "ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name, "INITIATIOR_ID": siae_user_request.initiator.id, @@ -197,6 +206,7 @@ def send_siae_user_request_reminder_8_days_email_to_assignee(siae_user_request): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=siae_user_request.assignee, ) # log email @@ -219,6 +229,7 @@ def send_siae_user_request_reminder_8_days_email_to_initiator(siae_user_request) recipient_name = siae_user_request.initiator.full_name variables = { + "SIAE_USER_REQUEST_ID": siae_user_request.id, "ASSIGNEE_ID": siae_user_request.assignee.id, "ASSIGNEE_FULL_NAME": siae_user_request.assignee.full_name, "INITIATIOR_ID": siae_user_request.initiator.id, @@ -232,6 +243,7 @@ def send_siae_user_request_reminder_8_days_email_to_initiator(siae_user_request) recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=siae_user_request.initiator, ) # log email diff --git a/lemarche/www/tenders/tasks.py b/lemarche/www/tenders/tasks.py index 907ef5e9d..076516d86 100644 --- a/lemarche/www/tenders/tasks.py +++ b/lemarche/www/tenders/tasks.py @@ -150,8 +150,7 @@ def send_tender_email_to_siae(tender: Tender, siae: Siae, email_subject: str, re recipient_name=recipient_name, variables=variables, subject=email_subject, - from_email=settings.DEFAULT_FROM_EMAIL, - from_name=settings.DEFAULT_FROM_NAME, + content_object=recipient_to_override if recipient_to_override else siae, ) # update tendersiae @@ -297,8 +296,7 @@ def send_tender_contacted_reminder_email_to_siae(tendersiae: TenderSiae, email_t recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - from_email=settings.DEFAULT_FROM_EMAIL, - from_name=settings.DEFAULT_FROM_NAME, + content_object=tendersiae.siae, ) # log email @@ -374,8 +372,7 @@ def send_tender_interested_reminder_email_to_siae( recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - from_email=settings.DEFAULT_FROM_EMAIL, - from_name=settings.DEFAULT_FROM_NAME, + content_object=tendersiae.siae, ) # log email @@ -420,6 +417,7 @@ def send_confirmation_published_email_to_author(tender: Tender): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=tender.author, ) # log email @@ -486,6 +484,7 @@ def send_siae_interested_email_to_author(tender: Tender): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=tender.author, ) # log email @@ -564,6 +563,7 @@ def send_tenders_author_feedback_or_survey(tender: Tender, kind="feedback_30d"): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=tender.author, ) # log email @@ -636,6 +636,7 @@ def send_tenders_siae_survey(tendersiae: TenderSiae, kind="transactioned_questio recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=user, ) # update tendersiae @@ -713,6 +714,7 @@ def send_super_siaes_email_to_author(tender: Tender, top_siaes: list[Siae]): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, + content_object=tender.author, ) # log email From baf0c68b1d4b370c0b82ae34ad6a1f1575317a15 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Thu, 18 Jul 2024 12:42:48 +0200 Subject: [PATCH 2/6] Improve admin display --- lemarche/conversations/admin.py | 31 ++++++++++++++++++++++++++++++- lemarche/notes/admin.py | 31 +++++++++++++------------------ 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/lemarche/conversations/admin.py b/lemarche/conversations/admin.py index 1573cbaea..4ed103a03 100644 --- a/lemarche/conversations/admin.py +++ b/lemarche/conversations/admin.py @@ -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 @@ -155,6 +157,13 @@ class TemplateTransactionalSendLogAdmin(admin.ModelAdmin): readonly_fields = [field.name for field in TemplateTransactionalSendLog._meta.fields] + fieldsets = ( + (None, {"fields": ("template_transactional",)}), + ("Envoyé à…", {"fields": ("content_type", "object_id_with_link")}), + ("Logs", {"fields": ("extra_data_display",)}), + ("Dates", {"fields": ("created_at", "updated_at")}), + ) + def has_add_permission(self, request): return False @@ -163,3 +172,23 @@ def has_change_permission(self, request, obj=None): def has_delete_permission(self, request, obj=None): return False + + 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'{obj.object_id}') + elif obj.content_type.model == "siae": + url = reverse("admin:siaes_siae_change", args=[obj.object_id]) + return format_html(f'{obj.object_id}') + elif obj.content_type.model == "user": + url = reverse("admin:users_user_change", args=[obj.object_id]) + return format_html(f'{obj.object_id}') + return obj.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 diff --git a/lemarche/notes/admin.py b/lemarche/notes/admin.py index 052db5306..4a52876c3 100644 --- a/lemarche/notes/admin.py +++ b/lemarche/notes/admin.py @@ -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")}), ) @@ -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'{note.object_id}') - elif note.content_type.model == "siae": - url = reverse("admin:siaes_siae_change", args=[note.object_id]) - return format_html(f'{note.object_id}') - elif note.content_type.model == "user": - url = reverse("admin:users_user_change", args=[note.object_id]) - return format_html(f'{note.object_id}') - 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'{obj.object_id}') + elif obj.content_type.model == "siae": + url = reverse("admin:siaes_siae_change", args=[obj.object_id]) + return format_html(f'{obj.object_id}') + elif obj.content_type.model == "user": + url = reverse("admin:users_user_change", args=[obj.object_id]) + return format_html(f'{obj.object_id}') + return obj.object.id From 9054da97dea701b2e4e806a6e082c42b81675065 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Thu, 18 Jul 2024 13:04:28 +0200 Subject: [PATCH 3/6] Add to Siae & User admin --- lemarche/siaes/admin.py | 10 +++++++++- lemarche/users/admin.py | 26 ++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lemarche/siaes/admin.py b/lemarche/siaes/admin.py index 4fbdc2709..7f533d47b 100644 --- a/lemarche/siaes/admin.py +++ b/lemarche/siaes/admin.py @@ -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 @@ -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", + "transactional_send_logs_count_with_link", "brevo_company_id", "extra_data_display", "import_raw_object_display", @@ -362,6 +363,7 @@ class SiaeAdmin(FieldsetsInlineMixin, gis_admin.OSMGeoAdmin, SimpleHistoryAdmin) "fields": ( "signup_date", "content_filled_basic_date", + "transactional_send_logs_count_with_link", "brevo_company_id", "extra_data_display", ), @@ -665,6 +667,12 @@ def tender_detail_not_interested_count_annotated_with_link(self, siae): "tender_detail_not_interested_count_annotated" ) + def transactional_send_logs_count_with_link(self, obj): + url = reverse("admin:conversations_templatetransactionalsendlog_changelist") + f"?siae__id__exact={obj.id}" + return format_html(f'{obj.transactional_send_logs.count()}') + + 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) diff --git a/lemarche/users/admin.py b/lemarche/users/admin.py index b1307fc0e..75aa1f573 100644 --- a/lemarche/users/admin.py +++ b/lemarche/users/admin.py @@ -9,11 +9,13 @@ from django.utils.html import format_html, mark_safe from fieldsets_with_inlines import FieldsetsInlineMixin +from lemarche.conversations.models import TemplateTransactionalSendLog from lemarche.notes.models import Note from lemarche.siaes.models import Siae, SiaeUser from lemarche.users.forms import UserChangeForm, UserCreationForm from lemarche.users.models import User from lemarche.utils.admin.admin_site import admin_site +from lemarche.utils.fields import pretty_print_readonly_jsonfield class HasCompanyFilter(admin.SimpleListFilter): @@ -194,8 +196,9 @@ class UserAdmin(FieldsetsInlineMixin, UserAdmin): "favorite_list_count_with_link", "image_url", "image_url_display", + "transactional_send_logs_count_with_link", "brevo_contact_id", - "extra_data", + "extra_data_display", ] ) @@ -283,7 +286,13 @@ class UserAdmin(FieldsetsInlineMixin, UserAdmin): "Stats", { "classes": ["collapse"], - "fields": ("dashboard_last_seen_date", "tender_list_last_seen_date", "brevo_contact_id", "extra_data"), + "fields": ( + "dashboard_last_seen_date", + "tender_list_last_seen_date", + "transactional_send_logs_count_with_link", + "brevo_contact_id", + "extra_data_display", + ), }, ), ( @@ -384,3 +393,16 @@ def image_url_display(self, user): return mark_safe("
-
") image_url_display.short_description = "Image" + + def transactional_send_logs_count_with_link(self, obj): + url = reverse("admin:conversations_templatetransactionalsendlog_changelist") + f"?user__id__exact={obj.id}" + return format_html(f'{obj.transactional_send_logs.count()}') + + transactional_send_logs_count_with_link.short_description = TemplateTransactionalSendLog._meta.verbose_name + + def extra_data_display(self, instance: User = None): + if instance: + return pretty_print_readonly_jsonfield(instance.extra_data) + return "-" + + extra_data_display.short_description = User._meta.get_field("extra_data").verbose_name From c85c506cf29acbddad21266afc3bf02dda1db812 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Fri, 19 Jul 2024 11:15:07 +0200 Subject: [PATCH 4/6] Add to TemplateTransactional admin (count with link) --- lemarche/conversations/admin.py | 33 +++++++++++++++++++++++++++++--- lemarche/conversations/models.py | 11 ++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lemarche/conversations/admin.py b/lemarche/conversations/admin.py index 4ed103a03..c91a0f91e 100644 --- a/lemarche/conversations/admin.py +++ b/lemarche/conversations/admin.py @@ -136,22 +136,49 @@ 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'{obj.send_log_count}') + + 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_filter = ["template_transactional", ("content_type", admin.RelatedOnlyFieldListFilter)] search_fields = ["id", "template_transactional"] search_help_text = "Cherche sur les champs : ID, Template transactionnel" diff --git a/lemarche/conversations/models.py b/lemarche/conversations/models.py index d85b15e50..18cde6108 100644 --- a/lemarche/conversations/models.py +++ b/lemarche/conversations/models.py @@ -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 @@ -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( @@ -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" From 3f02c909ffb995023cfa7ec36f599f5018068a62 Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Mon, 22 Jul 2024 12:56:35 +0200 Subject: [PATCH 5/6] Also store parent content_object --- lemarche/conversations/admin.py | 48 +++++++++++++------ .../0016_templatetransactionalsendlog.py | 18 +++++-- lemarche/conversations/models.py | 23 +++++++-- lemarche/siaes/admin.py | 35 +++++++++----- lemarche/siaes/models.py | 13 ++++- lemarche/siaes/tasks.py | 3 +- lemarche/tenders/admin.py | 28 ++++++++++- lemarche/tenders/models.py | 13 +++++ lemarche/users/admin.py | 12 +++-- lemarche/users/models.py | 7 ++- lemarche/www/auth/tasks.py | 2 +- lemarche/www/dashboard_siaes/tasks.py | 18 ++++--- lemarche/www/tenders/tasks.py | 26 ++++++---- 13 files changed, 186 insertions(+), 60 deletions(-) diff --git a/lemarche/conversations/admin.py b/lemarche/conversations/admin.py index c91a0f91e..f5739c986 100644 --- a/lemarche/conversations/admin.py +++ b/lemarche/conversations/admin.py @@ -177,8 +177,12 @@ def template_transactional_send_log_count_with_link(self, obj): @admin.register(TemplateTransactionalSendLog, site=admin_site) class TemplateTransactionalSendLogAdmin(admin.ModelAdmin): - list_display = ["id", "template_transactional", "content_type", "created_at"] - list_filter = ["template_transactional", ("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" @@ -186,7 +190,8 @@ class TemplateTransactionalSendLogAdmin(admin.ModelAdmin): fieldsets = ( (None, {"fields": ("template_transactional",)}), - ("Envoyé à…", {"fields": ("content_type", "object_id_with_link")}), + ("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")}), ) @@ -200,18 +205,31 @@ def has_change_permission(self, request, obj=None): def has_delete_permission(self, request, obj=None): return False - 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'{obj.object_id}') - elif obj.content_type.model == "siae": - url = reverse("admin:siaes_siae_change", args=[obj.object_id]) - return format_html(f'{obj.object_id}') - elif obj.content_type.model == "user": - url = reverse("admin:users_user_change", args=[obj.object_id]) - return format_html(f'{obj.object_id}') - return obj.object.id + 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'{obj.recipient_object_id}') + elif obj.recipient_content_type.model == "siae": + url = reverse("admin:siaes_siae_change", args=[obj.recipient_object_id]) + return format_html(f'{obj.recipient_object_id}') + elif obj.recipient_content_type.model == "user": + url = reverse("admin:users_user_change", args=[obj.recipient_object_id]) + return format_html(f'{obj.recipient_object_id}') + 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.recipient_content_type.model == "tender": + url = reverse("admin:tenders_tender_change", args=[obj.parent_object_id]) + return format_html(f'{obj.parent_object_id}') + if obj.parent_content_type.model == "tendersiae": + url = reverse("admin:tenders_tendersiae_change", args=[obj.parent_object_id]) + return format_html(f'{obj.parent_object_id}') + elif obj.parent_content_type.model == "siaeuserrequest": + url = reverse("admin:siaes_siaeuserrequest_change", args=[obj.parent_object_id]) + return format_html(f'{obj.parent_object_id}') + return obj.context_object.id def extra_data_display(self, instance: TemplateTransactionalSendLog = None): if instance: diff --git a/lemarche/conversations/migrations/0016_templatetransactionalsendlog.py b/lemarche/conversations/migrations/0016_templatetransactionalsendlog.py index 27db331ed..cf6413edb 100644 --- a/lemarche/conversations/migrations/0016_templatetransactionalsendlog.py +++ b/lemarche/conversations/migrations/0016_templatetransactionalsendlog.py @@ -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 @@ -16,7 +16,8 @@ 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", @@ -24,11 +25,22 @@ class Migration(migrations.Migration): ), ("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", ), ), diff --git a/lemarche/conversations/models.py b/lemarche/conversations/models.py index 18cde6108..0114706a5 100644 --- a/lemarche/conversations/models.py +++ b/lemarche/conversations/models.py @@ -276,7 +276,8 @@ def send_transactional_email( subject=None, from_email=settings.DEFAULT_FROM_EMAIL, from_name=settings.DEFAULT_FROM_NAME, - content_object=None, + recipient_content_object=None, + parent_content_object=None, ): if self.is_active: args = { @@ -294,7 +295,9 @@ def send_transactional_email( result = api_brevo.send_transactional_email_with_template(**args) # create log self.create_send_log( - content_object=content_object, extra_data={"source": self.source, "args": args, "response": result()} + recipient_content_object=recipient_content_object, + parent_content_object=parent_content_object, + extra_data={"source": self.source, "args": args, "response": result()}, ) @@ -307,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) diff --git a/lemarche/siaes/admin.py b/lemarche/siaes/admin.py index 7f533d47b..15f91c2c8 100644 --- a/lemarche/siaes/admin.py +++ b/lemarche/siaes/admin.py @@ -212,7 +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", - "transactional_send_logs_count_with_link", + "recipient_transactional_send_logs_count_with_link", "brevo_company_id", "extra_data_display", "import_raw_object_display", @@ -363,7 +363,7 @@ class SiaeAdmin(FieldsetsInlineMixin, gis_admin.OSMGeoAdmin, SimpleHistoryAdmin) "fields": ( "signup_date", "content_filled_basic_date", - "transactional_send_logs_count_with_link", + "recipient_transactional_send_logs_count_with_link", "brevo_company_id", "extra_data_display", ), @@ -667,11 +667,13 @@ def tender_detail_not_interested_count_annotated_with_link(self, siae): "tender_detail_not_interested_count_annotated" ) - def transactional_send_logs_count_with_link(self, obj): + 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'{obj.transactional_send_logs.count()}') + return format_html(f'{obj.recipient_transactional_send_logs.count()}') - transactional_send_logs_count_with_link.short_description = TemplateTransactionalSendLog._meta.verbose_name + recipient_transactional_send_logs_count_with_link.short_description = ( + TemplateTransactionalSendLog._meta.verbose_name + ) def logs_display(self, siae=None): if siae: @@ -708,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 @@ -724,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'{obj.parent_transactional_send_logs.count()}') + + 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): diff --git a/lemarche/siaes/models.py b/lemarche/siaes/models.py index 8929fd1ae..83d8c8230 100644 --- a/lemarche/siaes/models.py +++ b/lemarche/siaes/models.py @@ -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 ) @@ -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) diff --git a/lemarche/siaes/tasks.py b/lemarche/siaes/tasks.py index df78993f4..2413b4ca6 100644 --- a/lemarche/siaes/tasks.py +++ b/lemarche/siaes/tasks.py @@ -55,7 +55,8 @@ def send_completion_reminder_email_to_siae(siae): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=siae_user, + recipient_content_object=siae_user, + parent_content_object=siae, ) # log email diff --git a/lemarche/tenders/admin.py b/lemarche/tenders/admin.py index 2f1d5179c..c5c06b594 100644 --- a/lemarche/tenders/admin.py +++ b/lemarche/tenders/admin.py @@ -13,6 +13,7 @@ from django_better_admin_arrayfield.admin.mixins import DynamicArrayMixin from fieldsets_with_inlines import FieldsetsInlineMixin +from lemarche.conversations.models import TemplateTransactionalSendLog from lemarche.notes.models import Note from lemarche.perimeters.admin import PerimeterRegionFilter from lemarche.perimeters.models import Perimeter @@ -339,6 +340,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin): "siae_transactioned_source", "siae_transactioned_last_updated", "source", + "parent_transactional_send_logs_count_with_link", "brevo_deal_id", "extra_data_display", "import_raw_object_display", @@ -511,6 +513,7 @@ class TenderAdmin(FieldsetsInlineMixin, admin.ModelAdmin): "marche_benefits", "siae_list_last_seen_date", "source", + "parent_transactional_send_logs_count_with_link", "brevo_deal_id", "extra_data_display", ), @@ -759,6 +762,12 @@ def siae_detail_not_interested_click_count_annotated_with_link(self, tender): "siae_detail_not_interested_click_count_annotated" ) + def parent_transactional_send_logs_count_with_link(self, obj): + url = reverse("admin:conversations_templatetransactionalsendlog_changelist") + f"?tender__id__exact={obj.id}" + return format_html(f'{obj.parent_transactional_send_logs.count()}') + + parent_transactional_send_logs_count_with_link.short_description = TemplateTransactionalSendLog._meta.verbose_name + def logs_display(self, tender=None): if tender: return pretty_print_readonly_jsonfield(tender.logs) @@ -950,6 +959,7 @@ class TenderSiaeAdmin(admin.ModelAdmin): "tender", "tender_with_link", "transactioned_source", + "parent_transactional_send_logs_count_with_link", "logs_display", ] @@ -964,7 +974,15 @@ class TenderSiaeAdmin(admin.ModelAdmin): {"fields": (*TenderSiae.FIELDS_SURVEY_TRANSACTIONED, "transactioned", "transactioned_source")}, ), ("Utilisateur", {"fields": ("user",)}), - ("Stats", {"fields": ("logs_display",)}), + ( + "Stats", + { + "fields": ( + "parent_transactional_send_logs_count_with_link", + "logs_display", + ) + }, + ), ("Dates", {"fields": ("created_at", "updated_at")}), ) @@ -1000,6 +1018,14 @@ def status(self, tendersiae): status.short_description = "Status" status.admin_order_field = "status" + def parent_transactional_send_logs_count_with_link(self, obj): + url = ( + reverse("admin:conversations_templatetransactionalsendlog_changelist") + f"?tendersiae__id__exact={obj.id}" + ) + return format_html(f'{obj.parent_transactional_send_logs.count()}') + + parent_transactional_send_logs_count_with_link.short_description = TemplateTransactionalSendLog._meta.verbose_name + def logs_display(self, tender=None): if tender: return pretty_print_readonly_jsonfield(tender.logs) diff --git a/lemarche/tenders/models.py b/lemarche/tenders/models.py index 0e471aa42..3960b74f3 100644 --- a/lemarche/tenders/models.py +++ b/lemarche/tenders/models.py @@ -676,6 +676,13 @@ class Tender(models.Model): related_name="tenders_admins", blank=True, ) + + parent_transactional_send_logs = GenericRelation( + "conversations.TemplateTransactionalSendLog", + related_query_name="tender", + content_type_field="parent_content_type", + object_id_field="parent_object_id", + ) logs = models.JSONField(verbose_name="Logs historiques", editable=False, default=list) source = models.CharField( verbose_name="Source", @@ -1189,6 +1196,12 @@ class TenderSiae(models.Model): null=True, ) + parent_transactional_send_logs = GenericRelation( + "conversations.TemplateTransactionalSendLog", + related_query_name="tendersiae", + content_type_field="parent_content_type", + object_id_field="parent_object_id", + ) logs = models.JSONField(verbose_name="Logs historiques", editable=False, default=list) created_at = models.DateTimeField(verbose_name="Date de création", default=timezone.now) diff --git a/lemarche/users/admin.py b/lemarche/users/admin.py index 75aa1f573..9f9f71343 100644 --- a/lemarche/users/admin.py +++ b/lemarche/users/admin.py @@ -196,7 +196,7 @@ class UserAdmin(FieldsetsInlineMixin, UserAdmin): "favorite_list_count_with_link", "image_url", "image_url_display", - "transactional_send_logs_count_with_link", + "recipient_transactional_send_logs_count_with_link", "brevo_contact_id", "extra_data_display", ] @@ -289,7 +289,7 @@ class UserAdmin(FieldsetsInlineMixin, UserAdmin): "fields": ( "dashboard_last_seen_date", "tender_list_last_seen_date", - "transactional_send_logs_count_with_link", + "recipient_transactional_send_logs_count_with_link", "brevo_contact_id", "extra_data_display", ), @@ -394,11 +394,13 @@ def image_url_display(self, user): image_url_display.short_description = "Image" - def transactional_send_logs_count_with_link(self, obj): + def recipient_transactional_send_logs_count_with_link(self, obj): url = reverse("admin:conversations_templatetransactionalsendlog_changelist") + f"?user__id__exact={obj.id}" - return format_html(f'{obj.transactional_send_logs.count()}') + return format_html(f'{obj.recipient_transactional_send_logs.count()}') - transactional_send_logs_count_with_link.short_description = TemplateTransactionalSendLog._meta.verbose_name + recipient_transactional_send_logs_count_with_link.short_description = ( + TemplateTransactionalSendLog._meta.verbose_name + ) def extra_data_display(self, instance: User = None): if instance: diff --git a/lemarche/users/models.py b/lemarche/users/models.py index ed3e09097..d5d6c7cf3 100644 --- a/lemarche/users/models.py +++ b/lemarche/users/models.py @@ -275,7 +275,12 @@ 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") + recipient_transactional_send_logs = GenericRelation( + "conversations.TemplateTransactionalSendLog", + related_query_name="user", + content_type_field="recipient_content_type", + object_id_field="recipient_object_id", + ) # is_active, is_staff, is_superuser diff --git a/lemarche/www/auth/tasks.py b/lemarche/www/auth/tasks.py index 94f94a08d..d7be75ec6 100644 --- a/lemarche/www/auth/tasks.py +++ b/lemarche/www/auth/tasks.py @@ -59,5 +59,5 @@ def send_new_user_password_reset_link(user: User): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=user, + recipient_content_object=user, ) diff --git a/lemarche/www/dashboard_siaes/tasks.py b/lemarche/www/dashboard_siaes/tasks.py index 6dfe2b18d..b0df718b3 100644 --- a/lemarche/www/dashboard_siaes/tasks.py +++ b/lemarche/www/dashboard_siaes/tasks.py @@ -31,7 +31,8 @@ def send_siae_user_request_email_to_assignee(siae_user_request): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=siae_user_request.assignee, + recipient_content_object=siae_user_request.assignee, + parent_content_object=siae_user_request, ) # log email @@ -76,7 +77,8 @@ def send_siae_user_request_response_email_to_initiator(siae_user_request): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=siae_user_request.initiator, + recipient_content_object=siae_user_request.initiator, + parent_content_object=siae_user_request, ) # log email @@ -123,7 +125,8 @@ def send_siae_user_request_reminder_3_days_email_to_assignee(siae_user_request): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=siae_user_request.assignee, + recipient_content_object=siae_user_request.assignee, + parent_content_object=siae_user_request, ) # log email @@ -159,7 +162,8 @@ def send_siae_user_request_reminder_3_days_email_to_initiator(siae_user_request) recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=siae_user_request.initiator, + recipient_content_object=siae_user_request.initiator, + parent_content_object=siae_user_request, ) # log email @@ -206,7 +210,8 @@ def send_siae_user_request_reminder_8_days_email_to_assignee(siae_user_request): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=siae_user_request.assignee, + recipient_content_object=siae_user_request.assignee, + parent_content_object=siae_user_request, ) # log email @@ -243,7 +248,8 @@ def send_siae_user_request_reminder_8_days_email_to_initiator(siae_user_request) recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=siae_user_request.initiator, + recipient_content_object=siae_user_request.initiator, + parent_content_object=siae_user_request, ) # log email diff --git a/lemarche/www/tenders/tasks.py b/lemarche/www/tenders/tasks.py index 076516d86..50366fe49 100644 --- a/lemarche/www/tenders/tasks.py +++ b/lemarche/www/tenders/tasks.py @@ -114,6 +114,7 @@ def send_tender_emails_to_siaes(tender: Tender): # @task() def send_tender_email_to_siae(tender: Tender, siae: Siae, email_subject: str, recipient_to_override: User = None): email_template = TemplateTransactional.objects.get(code="TENDERS_SIAE_PRESENTATION") + tendersiae = TenderSiae.objects.get(tender=tender, siae=siae) # override siae.contact_email if email_to_override is provided email_to = recipient_to_override.email if recipient_to_override else siae.contact_email recipient_list = whitelist_recipient_list([email_to]) @@ -150,11 +151,11 @@ def send_tender_email_to_siae(tender: Tender, siae: Siae, email_subject: str, re recipient_name=recipient_name, variables=variables, subject=email_subject, - content_object=recipient_to_override if recipient_to_override else siae, + recipient_content_object=recipient_to_override if recipient_to_override else siae, + parent_content_object=tendersiae, ) # update tendersiae - tendersiae = TenderSiae.objects.get(tender=tender, siae=siae) tendersiae.email_send_date = timezone.now() log_item = { "action": "email_sent", @@ -296,7 +297,8 @@ def send_tender_contacted_reminder_email_to_siae(tendersiae: TenderSiae, email_t recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=tendersiae.siae, + recipient_content_object=tendersiae.siae, + parent_content_object=tendersiae, ) # log email @@ -372,7 +374,8 @@ def send_tender_interested_reminder_email_to_siae( recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=tendersiae.siae, + recipient_content_object=tendersiae.siae, + parent_content_object=tendersiae, ) # log email @@ -417,7 +420,8 @@ def send_confirmation_published_email_to_author(tender: Tender): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=tender.author, + recipient_content_object=tender.author, + parent_content_object=tender, ) # log email @@ -484,7 +488,8 @@ def send_siae_interested_email_to_author(tender: Tender): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=tender.author, + recipient_content_object=tender.author, + parent_content_object=tender, ) # log email @@ -563,7 +568,8 @@ def send_tenders_author_feedback_or_survey(tender: Tender, kind="feedback_30d"): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=tender.author, + recipient_content_object=tender.author, + parent_content_object=tender, ) # log email @@ -636,7 +642,8 @@ def send_tenders_siae_survey(tendersiae: TenderSiae, kind="transactioned_questio recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=user, + recipient_content_object=user, + parent_content_object=tendersiae, ) # update tendersiae @@ -714,7 +721,8 @@ def send_super_siaes_email_to_author(tender: Tender, top_siaes: list[Siae]): recipient_email=recipient_email, recipient_name=recipient_name, variables=variables, - content_object=tender.author, + recipient_content_object=tender.author, + parent_content_object=tender, ) # log email From c041aa315cb5d400711b87eb0c4d95e1a507f8cb Mon Sep 17 00:00:00 2001 From: Raphael Odini Date: Thu, 25 Jul 2024 10:17:24 +0200 Subject: [PATCH 6/6] Fix typo --- lemarche/conversations/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lemarche/conversations/admin.py b/lemarche/conversations/admin.py index f5739c986..af18c87d0 100644 --- a/lemarche/conversations/admin.py +++ b/lemarche/conversations/admin.py @@ -220,7 +220,7 @@ def recipient_object_id_with_link(self, obj): def parent_object_id_with_link(self, obj): if obj.parent_content_type and obj.parent_object_id: - if obj.recipient_content_type.model == "tender": + if obj.parent_content_type.model == "tender": url = reverse("admin:tenders_tender_change", args=[obj.parent_object_id]) return format_html(f'{obj.parent_object_id}') if obj.parent_content_type.model == "tendersiae":