Rename makecommand to checkout

This commit is contained in:
Antoine Bartuccio 2025-04-15 18:42:17 +02:00
parent 262ed7eb4c
commit bc99390b25
6 changed files with 31 additions and 45 deletions

View File

@ -32,48 +32,39 @@ susnommés afin de comprendre comment celui-ci marche.
Cette application contient les vues suivantes :
- `eboutic_main` (GET) : la vue retournant la page principale de la boutique en ligne.
- `EbouticMainView` (GET/POST) : la vue retournant la page principale de la boutique en ligne.
Cette vue effectue un filtrage des produits à montrer à l'utilisateur en
fonction de ce qu'il a le droit d'acheter.
Si cette vue est appelée lors d'une redirection parce qu'une erreur
est survenue au cours de la navigation sur la boutique, il est possible
de donner les messages d'erreur à donner à l'utilisateur dans la session
avec la clef ``"errors"``.
Elle est en charge de récupérer le formulaire de création d'un panier et
redirige alors vers la vue de checkout.
- ``payment_result`` (GET) : retourne une page assez simple disant à l'utilisateur
si son paiement a échoué ou réussi. Cette vue est appelée par redirection
lorsque l'utilisateur paye son panier avec son argent du compte AE.
- ``EbouticCommand`` (POST) : traite la soumission d'un panier par l'utilisateur.
Lors de l'appel de cette vue, la requête doit contenir un cookie avec l'état
du panier à valider. Ce panier doit strictement être de la forme :
```
[
{"id": <int>, "name": <str>, "quantity": <int>, "unit_price": <float>},
{"id": <int>, "name": <str>, "quantity": <int>, "unit_price": <float>},
<etc.>
]
```
Si le panier est mal formaté ou contient des valeurs invalides,
une redirection est faite vers `eboutic_main`.
- ``pay_with_sith`` (POST) : paie le panier avec l'argent présent sur le compte
- ``EbouticCheckout`` (GET/POST) : Page récapitulant le contenu d'un panier.
Permet de sélectionner le moyen de paiement et de mettre à jour ses coordonnées
de paiement par carte bancaire.
- ``PayWithSith`` (POST) : paie le panier avec l'argent présent sur le compte
AE. Redirige vers `payment_result`.
- ``ETransactionAutoAnswer`` (GET) : vue destinée à communiquer avec le service
de paiement bancaire pour valider ou non le paiement de l'utilisateur.
- ``BillingInfoFormFragment`` (GET/POST) : vue destinée à gérer les informations de paiement de l'utilisateur courant.
# Les templates
- ``eboutic_payment_result.jinja`` : très court template contenant juste
un message pour dire à l'utilisateur si son achat s'est bien déroulé.
Retourné par la vue ``payment_result``.
- ``eboutic_makecommand.jinja`` : template contenant un résumé du panier et deux
- ``eboutic_checkout.jinja`` : template contenant un résumé du panier et deux
boutons, un pour payer avec le site AE et l'autre pour payer par carte bancaire.
Retourné par la vue ``EbouticCommand``
Retourné par la vue ``EbouticCheckout``
- ``eboutic_billing_info.jinja`` : formulaire de modification des coordonnées bancaires.
Elle permet également de mettre à jour ses coordonnées de paiement
- ``eboutic_main.jinja`` : le plus gros template de cette application. Contient
une interface pour que l'utilisateur puisse consulter les produits et remplir
son panier. Les opérations de remplissage du panier se font entièrement côté client.
À chaque clic pour ajouter ou retirer un élément du panier, le script JS
(AlpineJS, plus précisément) édite en même temps un cookie.
Au moment de la validation du panier, ce cookie est envoyé au serveur pour
vérifier que la commande est valide et payer.
(AlpineJS, plus précisément) édite en même temps le localStorage du navigateur.
Cette vue fabrique dynamiquement un formulaire qui sera soumis au serveur.
# Les modèles

View File

@ -9,7 +9,7 @@
{% endblock %}
{% block additional_js %}
<script type="module" src="{{ static('bundled/eboutic/makecommand-index.ts') }}"></script>
<script type="module" src="{{ static('bundled/eboutic/checkout-index.ts') }}"></script>
{% endblock %}
{% block content %}

View File

@ -30,10 +30,10 @@
{{ form.management_form }}
</div>
{% if form.non_form_errors() %}
{% if form.non_form_errors() or form.errors %}
<div class="alert alert-red">
<div class="alert-main">
{% for error in form.non_form_errors() %}
{% for error in form.non_form_errors() + form.errors %}
<p style="margin: 0">{{ error }}</p>
{% endfor %}
</div>
@ -50,7 +50,7 @@
</span>
</li>
<template x-for="(item, index) in Object.values(basket)">
<template x-for="(item, index) in Object.values(basket)" :key="item.id">
<li class="item-row" x-show="item.quantity > 0">
<div class="item-quantity">
<i class="fa fa-minus fa-xs" @click="remove(item.id)"></i>
@ -94,8 +94,8 @@
<i class="fa fa-check"></i>
<input type="submit" value="{% trans %}Validate{% endtrans %}"/>
</button>
</form>
</div>
</form>
</div>
<div id="catalog">
{% if not request.user.date_of_birth %}

View File

@ -27,8 +27,8 @@ from django.urls import path, register_converter
from eboutic.converters import PaymentResultConverter
from eboutic.views import (
BillingInfoFormFragment,
EbouticCommand,
EbouticCreateBasket,
EbouticCheckout,
EbouticMainView,
EbouticPayWithSith,
EtransactionAutoAnswer,
EurokPartnerFragment,
@ -39,8 +39,8 @@ register_converter(PaymentResultConverter, "res")
urlpatterns = [
# Subscription views
path("", EbouticCreateBasket.as_view(), name="main"),
path("command/<int:basket_id>", EbouticCommand.as_view(), name="command"),
path("", EbouticMainView.as_view(), name="main"),
path("checkout/<int:basket_id>", EbouticCheckout.as_view(), name="checkout"),
path("billing-infos/", BillingInfoFormFragment.as_view(), name="billing_infos"),
path(
"pay/sith/<int:basket_id>", EbouticPayWithSith.as_view(), name="pay_with_sith"

View File

@ -18,7 +18,6 @@ from __future__ import annotations
import base64
import contextlib
import json
from datetime import datetime
from typing import TYPE_CHECKING
import sentry_sdk
@ -75,7 +74,7 @@ EbouticBasketForm = forms.formset_factory(
)
class EbouticCreateBasket(LoginRequiredMixin, FormView):
class EbouticMainView(LoginRequiredMixin, FormView):
"""Main view of the eboutic application.
The purchasable products are those of the eboutic which
@ -98,6 +97,7 @@ class EbouticCreateBasket(LoginRequiredMixin, FormView):
def form_valid(self, formset):
if len(formset) == 0:
formset.errors.append(_("Your basket is empty"))
return self.form_invalid(formset)
with transaction.atomic():
@ -110,7 +110,7 @@ class EbouticCreateBasket(LoginRequiredMixin, FormView):
return super().form_valid(formset)
def get_success_url(self):
return reverse("eboutic:command", kwargs={"basket_id": self.basket.id})
return reverse("eboutic:checkout", kwargs={"basket_id": self.basket.id})
@cached_property
def products(self) -> list[Product]:
@ -196,11 +196,11 @@ class BillingInfoFormFragment(
return self.request.path
class EbouticCommand(CanViewMixin, UseFragmentsMixin, DetailView):
class EbouticCheckout(CanViewMixin, UseFragmentsMixin, DetailView):
model = Basket
pk_url_kwarg = "basket_id"
context_object_name = "basket"
template_name = "eboutic/eboutic_makecommand.jinja"
template_name = "eboutic/eboutic_checkout.jinja"
fragments = {
"billing_infos_form": BillingInfoFormFragment,
}
@ -247,12 +247,7 @@ class EbouticPayWithSith(CanViewMixin, SingleObjectMixin, View):
basket.delete()
return redirect("eboutic:payment_result", "success")
except DatabaseError as e:
with sentry_sdk.push_scope() as scope:
scope.user = {"username": request.user.username}
scope.set_extra("someVariable", e.__repr__())
sentry_sdk.capture_message(
f"Erreur le {datetime.now()} dans eboutic.pay_with_sith"
)
sentry_sdk.capture_exception(e)
return redirect("eboutic:payment_result", "failure")