Use django messages for billing info ux

This commit is contained in:
Antoine Bartuccio 2025-04-13 00:20:57 +02:00
parent d6e858e0e3
commit 42317bfecc
6 changed files with 83 additions and 69 deletions

View File

@ -361,19 +361,22 @@ body {
align-items: center; align-items: center;
text-align: justify; text-align: justify;
&.alert-yellow { &.alert-yellow,
&.alert-warning {
background-color: rgb(255, 255, 240); background-color: rgb(255, 255, 240);
color: rgb(99, 87, 6); color: rgb(99, 87, 6);
border: rgb(192, 180, 16) 1px solid; border: rgb(192, 180, 16) 1px solid;
} }
&.alert-green { &.alert-green,
&.alert-success {
background-color: rgb(245, 255, 245); background-color: rgb(245, 255, 245);
color: rgb(3, 84, 63); color: rgb(3, 84, 63);
border: rgb(14, 159, 110) 1px solid; border: rgb(14, 159, 110) 1px solid;
} }
&.alert-red { &.alert-red,
&.alert-error {
background-color: rgb(255, 245, 245); background-color: rgb(255, 245, 245);
color: #c53030; color: #c53030;
border: #fc8181 1px solid; border: #fc8181 1px solid;

View File

@ -1,8 +1,8 @@
<span> <div id=billing-infos-fragment>
<div <div
class="collapse" class="collapse"
:class="{'shadow': collapsed}" :class="{'shadow': collapsed}"
x-data="{collapsed: !{{ "true" if billing_infos_state == BillingInfoState.VALID and not form.errors else "false" }}}" x-data="{collapsed: {{ "true" if messages or form.errors else "false" }}}"
> >
<div class="collapse-header clickable" @click="collapsed = !collapsed"> <div class="collapse-header clickable" @click="collapsed = !collapsed">
<span class="collapse-header-text"> <span class="collapse-header-text">
@ -17,11 +17,12 @@
hx-trigger="submit" hx-trigger="submit"
hx-post="{{ action }}" hx-post="{{ action }}"
hx-swap="outerHTML" hx-swap="outerHTML"
hx-target="closest span" hx-target="#billing-infos-fragment"
x-show="collapsed" x-show="collapsed"
> >
{% csrf_token %} {% csrf_token %}
{{ form.as_p() }} {{ form.as_p() }}
<br>
<input <input
type="submit" class="btn btn-blue clickable" type="submit" class="btn btn-blue clickable"
value="{% trans %}Validate{% endtrans %}" value="{% trans %}Validate{% endtrans %}"
@ -31,20 +32,11 @@
<br> <br>
{% if billing_infos_state == BillingInfoState.EMPTY %} {% if messages %}
<div class="alert alert-yellow"> {% for message in messages %}
{% trans trimmed %} <div class="alert alert-{{ message.tags }}">
You must fill your billing infos if you want to pay with your credit card {{ message }}
{% endtrans %} </div>
</div> {% endfor %}
{% elif billing_infos_state == BillingInfoState.MISSING_PHONE_NUMBER %}
<div class="alert alert-yellow">
{% trans trimmed %}
The Crédit Agricole changed its policy related to the billing
information that must be provided in order to pay with a credit card.
If you want to pay with your credit card, you must add a phone number
to the data you already provided.
{% endtrans %}
</div>
{% endif %} {% endif %}
</span> </div>

View File

@ -16,7 +16,7 @@
<h3>{% trans %}Eboutic{% endtrans %}</h3> <h3>{% trans %}Eboutic{% endtrans %}</h3>
<script type="text/javascript"> <script type="text/javascript">
let billingInfos = {{ billing_infos|tojson }}; let billingInfos = {{ billing_infos|safe }};
</script> </script>
<div x-data="etransaction(billingInfos)"> <div x-data="etransaction(billingInfos)">

View File

@ -17,6 +17,7 @@ from __future__ import annotations
import base64 import base64
import contextlib import contextlib
import json
from datetime import datetime from datetime import datetime
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -26,10 +27,12 @@ from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
from cryptography.hazmat.primitives.hashes import SHA1 from cryptography.hazmat.primitives.hashes import SHA1
from cryptography.hazmat.primitives.serialization import load_pem_public_key from cryptography.hazmat.primitives.serialization import load_pem_public_key
from django.conf import settings from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import ( from django.contrib.auth.mixins import (
LoginRequiredMixin, LoginRequiredMixin,
) )
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import SuspiciousOperation from django.core.exceptions import SuspiciousOperation
from django.db import DatabaseError, transaction from django.db import DatabaseError, transaction
from django.db.utils import cached_property from django.db.utils import cached_property
@ -37,6 +40,7 @@ from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect, render from django.shortcuts import redirect, render
from django.urls import reverse from django.urls import reverse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _
from django.views.decorators.http import require_GET, require_POST from django.views.decorators.http import require_GET, require_POST
from django.views.generic import TemplateView, UpdateView, View from django.views.generic import TemplateView, UpdateView, View
from django_countries.fields import Country from django_countries.fields import Country
@ -95,12 +99,15 @@ def payment_result(request, result: str) -> HttpResponse:
return render(request, "eboutic/eboutic_payment_result.jinja", context) return render(request, "eboutic/eboutic_payment_result.jinja", context)
class BillingInfoFormFragment(LoginRequiredMixin, FragmentMixin, UpdateView): class BillingInfoFormFragment(
LoginRequiredMixin, FragmentMixin, SuccessMessageMixin, UpdateView
):
"""Update billing info""" """Update billing info"""
model = BillingInfo model = BillingInfo
form_class = BillingInfoForm form_class = BillingInfoForm
template_name = "eboutic/eboutic_billing_info.jinja" template_name = "eboutic/eboutic_billing_info.jinja"
success_message = _("Billing info registration success")
def get_initial(self): def get_initial(self):
if self.object is None: if self.object is None:
@ -128,9 +135,26 @@ class BillingInfoFormFragment(LoginRequiredMixin, FragmentMixin, UpdateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs = super().get_context_data(**kwargs) kwargs = super().get_context_data(**kwargs)
kwargs["action"] = reverse("eboutic:billing_infos")
kwargs["BillingInfoState"] = BillingInfoState
kwargs["billing_infos_state"] = BillingInfoState.from_model(self.object) kwargs["billing_infos_state"] = BillingInfoState.from_model(self.object)
kwargs["action"] = reverse("eboutic:billing_infos")
match BillingInfoState.from_model(self.object):
case BillingInfoState.EMPTY:
messages.warning(
self.request,
_(
"You must fill your billing infos if you want to pay with your credit card"
),
)
case BillingInfoState.MISSING_PHONE_NUMBER:
messages.warning(
self.request,
_(
"The Crédit Agricole changed its policy related to the billing "
+ "information that must be provided in order to pay with a credit card. "
+ "If you want to pay with your credit card, you must add a phone number "
+ "to the data you already provided.",
),
)
return kwargs return kwargs
def get_success_url(self, **kwargs): def get_success_url(self, **kwargs):
@ -188,8 +212,11 @@ class EbouticCommand(LoginRequiredMixin, UseFragmentsMixin, TemplateView):
kwargs["customer_amount"] = None kwargs["customer_amount"] = None
kwargs["basket"] = self.basket kwargs["basket"] = self.basket
kwargs["billing_infos"] = {} kwargs["billing_infos"] = {}
with contextlib.suppress(BillingInfo.DoesNotExist): with contextlib.suppress(BillingInfo.DoesNotExist):
kwargs["billing_infos"] = dict(self.basket.get_e_transaction_data()) kwargs["billing_infos"] = json.dumps(
dict(self.basket.get_e_transaction_data())
)
return kwargs return kwargs

View File

@ -6,7 +6,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-08 16:20+0200\n" "POT-Creation-Date: 2025-04-13 00:18+0200\n"
"PO-Revision-Date: 2016-07-18\n" "PO-Revision-Date: 2016-07-18\n"
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n" "Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -3770,6 +3770,15 @@ msgstr "panier"
msgid "invoice" msgid "invoice"
msgstr "facture" msgstr "facture"
#: eboutic/templates/eboutic/eboutic_billing_info.jinja
msgid "Billing information"
msgstr "Informations de facturation"
#: eboutic/templates/eboutic/eboutic_billing_info.jinja
#: eboutic/templates/eboutic/eboutic_main.jinja
msgid "Validate"
msgstr "Valider"
#: eboutic/templates/eboutic/eboutic_main.jinja #: eboutic/templates/eboutic/eboutic_main.jinja
#: eboutic/templates/eboutic/eboutic_makecommand.jinja #: eboutic/templates/eboutic/eboutic_makecommand.jinja
msgid "Current account amount: " msgid "Current account amount: "
@ -3784,11 +3793,6 @@ msgstr "Valeur du panier : "
msgid "Clear" msgid "Clear"
msgstr "Vider" msgstr "Vider"
#: eboutic/templates/eboutic/eboutic_main.jinja
#: eboutic/templates/eboutic/eboutic_makecommand.jinja
msgid "Validate"
msgstr "Valider"
#: eboutic/templates/eboutic/eboutic_main.jinja #: eboutic/templates/eboutic/eboutic_main.jinja
msgid "" msgid ""
"You have not filled in your date of birth. As a result, you may not have " "You have not filled in your date of birth. As a result, you may not have "
@ -3837,29 +3841,6 @@ msgstr "État du panier"
msgid "Remaining account amount: " msgid "Remaining account amount: "
msgstr "Solde restant : " msgstr "Solde restant : "
#: eboutic/templates/eboutic/eboutic_makecommand.jinja
msgid "Billing information"
msgstr "Informations de facturation"
#: eboutic/templates/eboutic/eboutic_makecommand.jinja
msgid ""
"You must fill your billing infos if you want to pay with your credit card"
msgstr ""
"Vous devez renseigner vos coordonnées de facturation si vous voulez payer "
"par carte bancaire"
#: eboutic/templates/eboutic/eboutic_makecommand.jinja
msgid ""
"The Crédit Agricole changed its policy related to the billing information "
"that must be provided in order to pay with a credit card. If you want to pay "
"with your credit card, you must add a phone number to the data you already "
"provided."
msgstr ""
"Le Crédit Agricole a changé sa politique relative aux informations à "
"fournir pour effectuer un paiement par carte bancaire. De ce fait, si vous "
"souhaitez payer par carte, vous devez rajouter un numéro de téléphone aux "
"données que vous aviez déjà fourni."
#: eboutic/templates/eboutic/eboutic_makecommand.jinja #: eboutic/templates/eboutic/eboutic_makecommand.jinja
msgid "Pay with credit card" msgid "Pay with credit card"
msgstr "Payer avec une carte bancaire" msgstr "Payer avec une carte bancaire"
@ -3893,6 +3874,29 @@ msgstr "Le paiement a échoué"
msgid "Return to eboutic" msgid "Return to eboutic"
msgstr "Retourner à l'eboutic" msgstr "Retourner à l'eboutic"
#: eboutic/views.py
msgid "Billing info registration success"
msgstr "Informations de facturation enregistrées"
#: eboutic/views.py
msgid ""
"You must fill your billing infos if you want to pay with your credit card"
msgstr ""
"Vous devez renseigner vos coordonnées de facturation si vous voulez payer "
"par carte bancaire"
#: eboutic/views.py
msgid ""
"The Crédit Agricole changed its policy related to the billing information "
"that must be provided in order to pay with a credit card. If you want to pay "
"with your credit card, you must add a phone number to the data you already "
"provided."
msgstr ""
"Le Crédit Agricole a changé sa politique relative aux informations à "
"fournir pour effectuer un paiement par carte bancaire. De ce fait, si vous "
"souhaitez payer par carte, vous devez rajouter un numéro de téléphone aux "
"données que vous aviez déjà fourni."
#: election/models.py #: election/models.py
msgid "start candidature" msgid "start candidature"
msgstr "début des candidatures" msgstr "début des candidatures"

View File

@ -7,7 +7,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-09 23:23+0200\n" "POT-Creation-Date: 2025-04-13 00:18+0200\n"
"PO-Revision-Date: 2024-09-17 11:54+0200\n" "PO-Revision-Date: 2024-09-17 11:54+0200\n"
"Last-Translator: Sli <antoine@bartuccio.fr>\n" "Last-Translator: Sli <antoine@bartuccio.fr>\n"
"Language-Team: AE info <ae.info@utbm.fr>\n" "Language-Team: AE info <ae.info@utbm.fr>\n"
@ -247,18 +247,6 @@ msgstr "Types de produits réordonnés !"
msgid "Product type reorganisation failed with status code : %d" msgid "Product type reorganisation failed with status code : %d"
msgstr "La réorganisation des types de produit a échoué avec le code : %d" msgstr "La réorganisation des types de produit a échoué avec le code : %d"
#: eboutic/static/bundled/eboutic/makecommand-index.ts
msgid "Incorrect value"
msgstr "Valeur incorrecte"
#: eboutic/static/bundled/eboutic/makecommand-index.ts
msgid "Billing info registration success"
msgstr "Informations de facturation enregistrées"
#: eboutic/static/bundled/eboutic/makecommand-index.ts
msgid "Billing info registration failure"
msgstr "Echec de l'enregistrement des informations de facturation."
#: sas/static/bundled/sas/pictures-download-index.ts #: sas/static/bundled/sas/pictures-download-index.ts
msgid "pictures.%(extension)s" msgid "pictures.%(extension)s"
msgstr "photos.%(extension)s" msgstr "photos.%(extension)s"