From 2f98354f35f6a45c29abbf6dd666197fe9cf161b Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Tue, 9 Sep 2025 16:27:04 +0300 Subject: [PATCH] Features: 1) Add `slug` field to `BrandFilter` with filtering and ordering support; 2) Implement `send_promocode_created_email` task using a new email template; 3) Create signal to notify users upon promocode creation. Fixes: None; Extra: Refactor imports in `signals.py` and `emailing.py`; Add formatting and responsive styles for email template. --- core/filters.py | 4 +- core/signals.py | 8 +- core/templates/promocode_granted_email.html | 122 ++++++++++++++++++++ core/utils/emailing.py | 44 ++++++- 4 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 core/templates/promocode_granted_email.html diff --git a/core/filters.py b/core/filters.py index 6681d7f5..4871b135 100644 --- a/core/filters.py +++ b/core/filters.py @@ -473,12 +473,14 @@ class CategoryFilter(FilterSet): class BrandFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact") name = CharFilter(method="filter_name", label=_("Name")) + slug = CharFilter(field_name="slug", lookup_expr="exact", label=_("Slug")) categories = CaseInsensitiveListFilter(field_name="categories__uuid", lookup_expr="exact", label=_("Categories")) order_by = OrderingFilter( fields=( ("priority", "priority"), ("uuid", "uuid"), + ("slug", "slug"), ("name", "name"), ("?", "random"), ) @@ -486,7 +488,7 @@ class BrandFilter(FilterSet): class Meta: model = Brand - fields = ["uuid", "name"] + fields = ["uuid", "name", "slug", "priority"] def filter_name(self, queryset, _name, value): search_results = process_query(query=value, request=self.request)["brands"] diff --git a/core/signals.py b/core/signals.py index c9701718..0f7a668e 100644 --- a/core/signals.py +++ b/core/signals.py @@ -18,7 +18,7 @@ from core.utils import ( generate_human_readable_id, resolve_translations_for_elasticsearch, ) -from core.utils.emailing import send_order_created_email, send_order_finished_email +from core.utils.emailing import send_order_created_email, send_order_finished_email, send_promocode_created_email from evibes.utils.misc import create_object from vibes_auth.models import User @@ -155,3 +155,9 @@ def update_category_name_lang(instance, created, **_kwargs): pass resolve_translations_for_elasticsearch(instance, "name") resolve_translations_for_elasticsearch(instance, "description") + + +@receiver(post_save, sender=PromoCode) +def send_promocode_creation_email(instance, created, **_kwargs): + if created: + send_promocode_created_email.delay(instance.uuid) diff --git a/core/templates/promocode_granted_email.html b/core/templates/promocode_granted_email.html new file mode 100644 index 00000000..f04e9770 --- /dev/null +++ b/core/templates/promocode_granted_email.html @@ -0,0 +1,122 @@ +{% load tz static i18n filters conditions %} + + + + + {% blocktrans %}promocode granted{% endblocktrans %} + + + + + + + + +
+ + + + + + + + + + + +
+ + diff --git a/core/utils/emailing.py b/core/utils/emailing.py index ddd7aef3..375b052d 100644 --- a/core/utils/emailing.py +++ b/core/utils/emailing.py @@ -3,13 +3,14 @@ from datetime import datetime from celery.app import shared_task from celery.utils.log import get_task_logger from constance import config +from django.conf import settings from django.core import mail from django.core.mail import EmailMessage from django.template.loader import render_to_string from django.utils.translation import activate from django.utils.translation import gettext_lazy as _ -from core.models import Order, OrderProduct +from core.models import Order, OrderProduct, PromoCode from core.utils.constance import set_email_settings logger = get_task_logger(__name__) @@ -165,3 +166,44 @@ def send_order_finished_email(order_pk: str) -> tuple[bool, str]: send_thank_you_email(shipped_ops) return True, str(order.uuid) + + +@shared_task(queue="default") +def send_promocode_created_email(promocode_pk: str) -> tuple[bool, str]: + try: + promocode = PromoCode.objects.get(pk=promocode_pk) + except PromoCode.DoesNotExist: + return False, f"Promocode not found with the given pk: {promocode_pk}" + + if not promocode.user: + return True, "The promocode has no user" + + activate(promocode.user.language) + + set_email_settings() + connection = mail.get_connection() + + email = EmailMessage( + _(f"{config.PROJECT_NAME} | promocode granted"), + render_to_string( + template_name="promocode_granted_email.html", + context={ + "promocode": promocode, + "user_first_name": "" or promocode.user.first_name, + "project_name": config.PROJECT_NAME, + "contact_email": config.EMAIL_FROM, + "today": datetime.today(), + "currency": settings.CURRENCY_CODE, + }, + ), + to=[promocode.user.email], + from_email=f"{config.PROJECT_NAME} <{config.EMAIL_FROM}>", + connection=connection, + ) + email.content_subtype = "html" + result = email.send() + logger.debug( + "Promocode %s: Tried to send email to %s, resulted with %s", promocode.pk, promocode.user.email, result + ) + + return True, str(promocode.uuid)