send mail notification on order

This commit is contained in:
Laetitia Getti 2023-08-04 11:26:36 +02:00 committed by Laetitia Getti
parent 8953e1adf2
commit 660117af80
10 changed files with 195 additions and 5 deletions

View file

@ -158,12 +158,22 @@ Si il y a des erreurs BLACK, on peut lancer black pour linter le code :
black . 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 ## Architecture de l'application
Les différentes applications Django créées sont : Les différentes applications Django créées sont :
- ``Order``, pour gérer tout ce qui tourne autour des commandes - ``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. - ``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 : A l'état actuel, le diagramme de classes est le suivant :

View file

@ -1,4 +1,9 @@
import datetime
import pytest import pytest
from django.utils import timezone
from la_chariotte.order.models import GroupedOrder, Item
@pytest.fixture @pytest.fixture
@ -16,3 +21,17 @@ def other_user(django_user_model):
password = "azertypassword" password = "azertypassword"
user = django_user_model.objects.create_user(username=username, password=password) user = django_user_model.objects.create_user(username=username, password=password)
return user 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

View file

View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class MailConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "la_chariotte.mail"

View 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>

View 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

View 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)

View file

@ -8,17 +8,16 @@
</p> </p>
<div class="box"> <div class="box">
<p class="title">Merci, {{ order.author.first_name }} !</p> <p class="title">Merci, {{ order.author.first_name }} !</p>
<p>Votre participation à la commande groupée "{{ order.grouped_order }}" a bien été confirmée ! <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.
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><strong>Votre commande</strong></p> <p><strong>Votre commande :</strong></p>
<ul> <ul>
{% for item in order.ordered_items.all %} {% for item in order.ordered_items.all %}
<li>{{ item.nb }} × {{ item.item }} : {{ item.get_price }} €</li> <li>{{ item.nb }} × {{ item.item }} : {{ item.get_price }} €</li>
{% endfor %} {% endfor %}
</ul> </ul>
<p>Prix total de la commande : <strong>{{ order.price }} €</strong> <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> <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>

View file

@ -4,6 +4,8 @@ from django.shortcuts import get_object_or_404, render
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.views import generic from django.views import generic
from la_chariotte.mail.utils import send_order_confirmation_mail
from ..models import GroupedOrder, Order, OrderAuthor, OrderedItem 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() order.compute_order_price()
grouped_order.compute_items_ordered_nb() grouped_order.compute_items_ordered_nb()
send_order_confirmation_mail(order)
# Always return an http.HttpResponseRedirect after successfully dealing # Always return an http.HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a # with POST data. This prevents data from being posted twice if a
# user hits the Back button. # user hits the Back button.

View file

@ -40,6 +40,7 @@ if os.getenv("ALLOWED_HOSTS"):
INSTALLED_APPS = [ INSTALLED_APPS = [
"la_chariotte.order", "la_chariotte.order",
"la_chariotte.accounts", "la_chariotte.accounts",
"la_chariotte.mail",
"django.contrib.admin", "django.contrib.admin",
"django.contrib.auth", "django.contrib.auth",
"django.contrib.contenttypes", "django.contrib.contenttypes",