mirror of
https://framagit.org/la-chariotte/la-chariotte.git
synced 2025-05-02 20:01:51 +02:00
send mail notification on order
This commit is contained in:
parent
8953e1adf2
commit
660117af80
10 changed files with 195 additions and 5 deletions
10
README.md
10
README.md
|
@ -158,12 +158,22 @@ Si il y a des erreurs BLACK, on peut lancer black pour linter le code :
|
|||
black .
|
||||
```
|
||||
|
||||
## Tests de l'envoi de mails
|
||||
|
||||
Pour tester l'apparence des mails, on peut utiliser Sendria :
|
||||
```bash
|
||||
pip install sendria
|
||||
sendria --db mails.sqlite
|
||||
$NAVIGATOR http://127.0.0.1:1080
|
||||
```
|
||||
|
||||
## Architecture de l'application
|
||||
|
||||
Les différentes applications Django créées sont :
|
||||
|
||||
- ``Order``, pour gérer tout ce qui tourne autour des commandes
|
||||
- ``Accounts``, pour gérer la création de comptes. Pour la connexion, la déconnexion et le changement de mot de passe, on utilise l'application auth intégrée à Django.
|
||||
- ``mail``, pour l'envoi des mails.
|
||||
|
||||
A l'état actuel, le diagramme de classes est le suivant :
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import datetime
|
||||
|
||||
import pytest
|
||||
from django.utils import timezone
|
||||
|
||||
from la_chariotte.order.models import GroupedOrder, Item
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -16,3 +21,17 @@ def other_user(django_user_model):
|
|||
password = "azertypassword"
|
||||
user = django_user_model.objects.create_user(username=username, password=password)
|
||||
return user
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def simple_grouped_order(other_user):
|
||||
date = timezone.now().date() + datetime.timedelta(days=30)
|
||||
deadline = timezone.now() + datetime.timedelta(days=5)
|
||||
grouped_order = GroupedOrder.objects.create(
|
||||
name="Test grouped order",
|
||||
orga=other_user,
|
||||
delivery_date=date,
|
||||
deadline=deadline,
|
||||
)
|
||||
item = Item.objects.create(name="test item", grouped_order=grouped_order, price=2)
|
||||
return grouped_order
|
||||
|
|
0
la_chariotte/mail/__init__.py
Normal file
0
la_chariotte/mail/__init__.py
Normal file
6
la_chariotte/mail/apps.py
Normal file
6
la_chariotte/mail/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class MailConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "la_chariotte.mail"
|
91
la_chariotte/mail/templates/mail/order_confirm_mail.html
Normal file
91
la_chariotte/mail/templates/mail/order_confirm_mail.html
Normal file
|
@ -0,0 +1,91 @@
|
|||
{% load i18n static %}
|
||||
|
||||
<html lang="fr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style type="text/css">
|
||||
* {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: f5f5f5;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 1rem 2rem;
|
||||
width: 80vw;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
p.title {
|
||||
font-weight: 300;
|
||||
color: #A52951;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #A52951;
|
||||
}
|
||||
|
||||
a.button {
|
||||
margin: 0 auto;
|
||||
padding: 8px 25px;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
white-space: normal;
|
||||
border: #A52951 1px solid;
|
||||
}
|
||||
|
||||
img.logo {
|
||||
width: 200px;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="content">
|
||||
<a href="{{ base_url }}{% url 'home' %}">
|
||||
<img class="logo" src="{{ base_url }}{% static 'img/logos/logo_la_chariotte.png' %}">
|
||||
</a>
|
||||
|
||||
<p>Merci, {{ order.author.first_name }} !</p>
|
||||
<p>Votre participation à la commande groupée "{{ order.grouped_order }}" a bien été confirmée.</p>
|
||||
|
||||
<p><strong>Votre commande :</strong></p>
|
||||
<ul>
|
||||
{% for item in order.ordered_items.all %}
|
||||
<li>{{ item.nb }} × {{ item.item }} : {{ item.get_price }} €</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p>Prix total de la commande : <strong>{{ order.price }} €</strong>
|
||||
<p><i>Le paiement n'est pas (encore) pris en charge par la Chariotte. C'est l'organisateur·ice de la commande qui doit vous indiquer les moyens de paiement.</i></p>
|
||||
|
||||
|
||||
<p>Rendez-vous le <strong>{{ order.grouped_order.delivery_date }}</strong>{% if order.grouped_order.place %} à <strong>{{ order.grouped_order.place }}</strong>{% endif %} pour récupérer vos produits !</p>
|
||||
|
||||
<p>Pour toute question, vous pouvez contacter l'organisateur·ice de la commande, <strong>{{ order.grouped_order.orga }}</strong> :
|
||||
<a href="mailto:{{ order.grouped_order.orga.username }}">Envoyer un mail</a></p>
|
||||
|
||||
<div class="buttons">
|
||||
<a class="button" href="[[ base_url }}{% url 'order:grouped_order_detail' order.grouped_order.pk %}">
|
||||
<i class="fa fa-arrow-left mr-3" aria-hidden="true"></i>Voir la page de commande
|
||||
</a>
|
||||
</div>
|
||||
</content>
|
||||
</body>
|
||||
|
||||
</html>
|
41
la_chariotte/mail/test_mail.py
Normal file
41
la_chariotte/mail/test_mail.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
import pytest
|
||||
from django.urls import reverse
|
||||
|
||||
from la_chariotte import settings
|
||||
from la_chariotte.order.models import GroupedOrder
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
||||
def test_send_order_confirmation_mail(mailoutbox, simple_grouped_order, client):
|
||||
"""
|
||||
When a user orders, they receive a confirmation email
|
||||
"""
|
||||
item = simple_grouped_order.item_set.first()
|
||||
|
||||
# the user places an order
|
||||
order_url = reverse(
|
||||
"order:order",
|
||||
kwargs={
|
||||
"grouped_order_id": simple_grouped_order.pk,
|
||||
},
|
||||
)
|
||||
response = client.post(
|
||||
order_url,
|
||||
{
|
||||
f"quantity_{item.pk}": [4, 0],
|
||||
"first_name": "Prénom",
|
||||
"last_name": "Nom",
|
||||
"phone": "0645632569",
|
||||
"email": "test@mail.fr",
|
||||
"note": "",
|
||||
},
|
||||
)
|
||||
assert len(mailoutbox) == 1
|
||||
m = mailoutbox[0]
|
||||
assert m.subject == "[La Chariotte] Votre commande pour Test grouped order"
|
||||
assert "Votre participation à la commande groupée" in m.body
|
||||
assert "Votre participation à la commande groupée" in m.alternatives[0][0]
|
||||
assert f"{settings.BASE_URL}" in m.alternatives[0][0]
|
||||
assert m.alternatives[0][1] == "text/html"
|
||||
assert "test@mail.fr" in mailoutbox[0].to
|
19
la_chariotte/mail/utils.py
Normal file
19
la_chariotte/mail/utils.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
from django.core import mail
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.html import strip_tags
|
||||
|
||||
from la_chariotte import settings
|
||||
|
||||
|
||||
def send_order_confirmation_mail(order):
|
||||
template_name = "mail/order_confirm_mail.html"
|
||||
|
||||
subject = f"[La Chariotte] Votre commande pour {order.grouped_order.name}"
|
||||
html_message = render_to_string(
|
||||
template_name, {"order": order, "base_url": settings.BASE_URL}
|
||||
)
|
||||
plain_message = strip_tags(html_message)
|
||||
from_email = "notification@chariotte.fr"
|
||||
to = order.author.email
|
||||
|
||||
mail.send_mail(subject, plain_message, from_email, [to], html_message=html_message)
|
|
@ -8,17 +8,16 @@
|
|||
</p>
|
||||
<div class="box">
|
||||
<p class="title">Merci, {{ order.author.first_name }} !</p>
|
||||
<p>Votre participation à la commande groupée "{{ order.grouped_order }}" a bien été confirmée !
|
||||
Dans une prochaine version de la Chariotte, vous recevrez un mail de confirmation :)</p>
|
||||
<p>En attendant, vous pouvez bien noter ces infos :</p>
|
||||
<p>Votre participation à la commande groupée "{{ order.grouped_order }}" a bien été confirmée et vous avez normalement reçu un mail de confirmation.
|
||||
|
||||
<p><strong>Votre commande</strong></p>
|
||||
<p><strong>Votre commande :</strong></p>
|
||||
<ul>
|
||||
{% for item in order.ordered_items.all %}
|
||||
<li>{{ item.nb }} × {{ item.item }} : {{ item.get_price }} €</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p>Prix total de la commande : <strong>{{ order.price }} €</strong>
|
||||
<p>Le paiement n'est pas (encore) pris en charge par la Chariotte. C'est l'organisateur·ice de la commande qui doit vous indiquer les moyens de paiement.</p>
|
||||
|
||||
<p>Rendez-vous le <strong>{{ order.grouped_order.delivery_date }}</strong>{% if order.grouped_order.place %} à <strong>{{ order.grouped_order.place }}</strong>{% endif %} pour récupérer vos produits !</p>
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ from django.shortcuts import get_object_or_404, render
|
|||
from django.urls import reverse, reverse_lazy
|
||||
from django.views import generic
|
||||
|
||||
from la_chariotte.mail.utils import send_order_confirmation_mail
|
||||
|
||||
from ..models import GroupedOrder, Order, OrderAuthor, OrderedItem
|
||||
|
||||
|
||||
|
@ -94,9 +96,11 @@ def place_order(request, code):
|
|||
},
|
||||
)
|
||||
|
||||
# Redirect to confirmation page
|
||||
# Send confirmation mail and redirect to confirmation page
|
||||
order.compute_order_price()
|
||||
grouped_order.compute_items_ordered_nb()
|
||||
send_order_confirmation_mail(order)
|
||||
|
||||
# Always return an http.HttpResponseRedirect after successfully dealing
|
||||
# with POST data. This prevents data from being posted twice if a
|
||||
# user hits the Back button.
|
||||
|
|
|
@ -40,6 +40,7 @@ if os.getenv("ALLOWED_HOSTS"):
|
|||
INSTALLED_APPS = [
|
||||
"la_chariotte.order",
|
||||
"la_chariotte.accounts",
|
||||
"la_chariotte.mail",
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
|
|
Loading…
Reference in a new issue