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 .
|
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 :
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
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>
|
</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>
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in a new issue