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.
This commit is contained in:
parent
2f4cceaa6a
commit
2f98354f35
4 changed files with 175 additions and 3 deletions
|
|
@ -473,12 +473,14 @@ class CategoryFilter(FilterSet):
|
||||||
class BrandFilter(FilterSet):
|
class BrandFilter(FilterSet):
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||||
name = CharFilter(method="filter_name", label=_("Name"))
|
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"))
|
categories = CaseInsensitiveListFilter(field_name="categories__uuid", lookup_expr="exact", label=_("Categories"))
|
||||||
|
|
||||||
order_by = OrderingFilter(
|
order_by = OrderingFilter(
|
||||||
fields=(
|
fields=(
|
||||||
("priority", "priority"),
|
("priority", "priority"),
|
||||||
("uuid", "uuid"),
|
("uuid", "uuid"),
|
||||||
|
("slug", "slug"),
|
||||||
("name", "name"),
|
("name", "name"),
|
||||||
("?", "random"),
|
("?", "random"),
|
||||||
)
|
)
|
||||||
|
|
@ -486,7 +488,7 @@ class BrandFilter(FilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Brand
|
model = Brand
|
||||||
fields = ["uuid", "name"]
|
fields = ["uuid", "name", "slug", "priority"]
|
||||||
|
|
||||||
def filter_name(self, queryset, _name, value):
|
def filter_name(self, queryset, _name, value):
|
||||||
search_results = process_query(query=value, request=self.request)["brands"]
|
search_results = process_query(query=value, request=self.request)["brands"]
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ from core.utils import (
|
||||||
generate_human_readable_id,
|
generate_human_readable_id,
|
||||||
resolve_translations_for_elasticsearch,
|
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 evibes.utils.misc import create_object
|
||||||
from vibes_auth.models import User
|
from vibes_auth.models import User
|
||||||
|
|
||||||
|
|
@ -155,3 +155,9 @@ def update_category_name_lang(instance, created, **_kwargs):
|
||||||
pass
|
pass
|
||||||
resolve_translations_for_elasticsearch(instance, "name")
|
resolve_translations_for_elasticsearch(instance, "name")
|
||||||
resolve_translations_for_elasticsearch(instance, "description")
|
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)
|
||||||
|
|
|
||||||
122
core/templates/promocode_granted_email.html
Normal file
122
core/templates/promocode_granted_email.html
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
{% load tz static i18n filters conditions %}
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{% blocktrans %}promocode granted{% endblocktrans %}</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body, table, td, a {
|
||||||
|
text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-container {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-cell {
|
||||||
|
border: 3px solid #000000;
|
||||||
|
padding: 20px;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background-color: #000000;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header img {
|
||||||
|
width: 120px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
background-color: #000000;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-table {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-table th, .order-table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-table th {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.email-container {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link rel="icon" href="{% static 'favicon.png' %}" sizes="192x192">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<table class="email-container">
|
||||||
|
<tr>
|
||||||
|
<td class="header">
|
||||||
|
<img src="{% static 'logo.png' %}"
|
||||||
|
alt="{% blocktrans %}logo{% endblocktrans %}" width="120">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="content-cell">
|
||||||
|
<h2>{% blocktrans %}promocode granted{% endblocktrans %}</h2>
|
||||||
|
<p>{% blocktrans %}hello {{ user_first_name }},{% endblocktrans %}</p>
|
||||||
|
<p>{% blocktrans %}Thank you for staying with us! We have granted you with a promocode
|
||||||
|
for {% endblocktrans %}{% if promocode.discount_type == "amount" %}
|
||||||
|
{{ promocode.discount_amount }}{{ currency }}{% else %}{{ promocode.discount_percent }}
|
||||||
|
%{% endif %}</p>
|
||||||
|
|
||||||
|
<p>{% blocktrans %}if you have any questions, feel free to contact our support at
|
||||||
|
{{ contact_email }}.{% endblocktrans %}</p>
|
||||||
|
<p>{% blocktrans %}best regards,<br>the {{ project_name }} team{% endblocktrans %}</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="footer">
|
||||||
|
© {% now "Y" %} {{ project_name }}.
|
||||||
|
{% blocktrans %}all rights reserved{% endblocktrans %}.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -3,13 +3,14 @@ from datetime import datetime
|
||||||
from celery.app import shared_task
|
from celery.app import shared_task
|
||||||
from celery.utils.log import get_task_logger
|
from celery.utils.log import get_task_logger
|
||||||
from constance import config
|
from constance import config
|
||||||
|
from django.conf import settings
|
||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.core.mail import EmailMessage
|
from django.core.mail import EmailMessage
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.translation import activate
|
from django.utils.translation import activate
|
||||||
from django.utils.translation import gettext_lazy as _
|
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
|
from core.utils.constance import set_email_settings
|
||||||
|
|
||||||
logger = get_task_logger(__name__)
|
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)
|
send_thank_you_email(shipped_ops)
|
||||||
|
|
||||||
return True, str(order.uuid)
|
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)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue