Ca marche pas chez moi
Bonsoir Christian,
Il semble effectivement qu'il y a eu un changement dans l'API de Stripe :
Il faut désormais indiquer explicitement si tu souhaites créer l'utilisateur avec le paramètre customer_creation :
https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-customer_creation
Je vais coder une fonctionnalité sur Docstring pour pouvoir annoter les sessions afin d'indiquer ces changements sur les API et autres par rapport à la vidéo pour que ce soit plus clair.
Essaie avec customer_creation à always et tiens-nous au courant si ça ne fonctionne toujours pas.
Bonne continuation !
Alors ca marche, mais maintenant j'ai un autre probleme ...
J'ai que des codes 403 dans mon terminal qui écoute stripe
et ca dans mon terminal Django :
[17/Jan/2023 08:20:44] "GET /cart/ HTTP/1.1" 200 960
[17/Jan/2023 08:21:20] "POST /cart/create-checkout-session HTTP/1.1" 302 0
Forbidden (CSRF cookie not set.): /
[17/Jan/2023 08:21:49] "POST / HTTP/1.1" 403 2986
Forbidden (CSRF cookie not set.): /
[17/Jan/2023 08:21:49] "POST / HTTP/1.1" 403 2986
Forbidden (CSRF cookie not set.): /
[17/Jan/2023 08:21:49] "POST / HTTP/1.1" 403 2986
Forbidden (CSRF cookie not set.): /
[17/Jan/2023 08:21:49] "POST / HTTP/1.1" 403 2986
Forbidden (CSRF cookie not set.): /
[17/Jan/2023 08:21:50] "POST / HTTP/1.1" 403 2986
Forbidden (CSRF cookie not set.): /
[17/Jan/2023 08:21:50] "POST / HTTP/1.1" 403 2986
[17/Jan/2023 08:21:51] "GET /cart/succes HTTP/1.1" 200 611
J'ai testé avec des print, je ne passe plus dans ma vue stripe_webhook
Bonjour,
Par contre le customer_creation always je n'ai pas compris à quel niveau le mettre ?
Car j'ai essayé de l'intégrer dans checkout_data mais ça me sort cette erreur
https://zupimages.net/viewer.php?id=23/12/20el.jpg
Lien vers mon repo : https://github.com/gabigab117/DocShop.git
Si tu avais un exemple de code à me montrer pour l'intégrer ^^ Car jusque maintenant j'ai réussi à tout faire mais là j'avoue que sur la création de l'utilisateur dans stripe je rame à fond :s.
merci d'avance
Salut Gab !
C'est dans la création de ta checkout session, l'erreur que tu as c'est que tu spécifies à la fois une entrée pour customer et pour customer_creation. Et tu ne peux spécifier que l'un des deux (ce qui est logique, si tu donnes un client et que tu lui dis de créer un client, ça rentre en conflit). Le customer_creation ne devrait être spécifié que si tu ne donnes pas de client au préalable. Si tu donnes un client (customer), il ne peut pas le créer, car il existe déjà.
Mais oui je suis bête !!
Hier je saturais je n'arrivais plus à réfléchir !
Tout est ok ! J'ai même fait des modif dans mon code et quelques adaptations.
Merci Thibault !
Juste dernière question :
Mais pour que tout fonctionne faut forcémment activer le client stripe et faire stripe listen --forward-to 127.0.0.1:8000/stripe-webhook/ ?
Car sans ça tout ce que je fais ça ne fonctionne pas (le delete du panier, etc....).
Hello, à mon tour de devenir fou avec Stripe. Je veux relier l'utilisateur qui fait l'achat à un utilisateur Stripe en ajoutant la ligne customer=user.stripe_id dans ma checkout session. Mais quand je rajoute cette simple ligne, la vue (qui s'affichait correctement avant) déclenche une erreur pas très explicite:
AttributeError at /cart/stripe_checkout_session/
'str' object has no attribute 'get'
Pourtant, mon utilisateur a bien déjà un stripe_id (chaîne de caractère 'cus_RBG7EYgHgkzrta'). Voici l'état de ma vue:
def stripe_checkout_session(request: HttpRequest) -> HttpRequest | str:
"""Stripe checkout session for payments"""
user = request.user # type: ignore
user_cart = user.cart
try:
checkout_session = stripe.checkout.Session.create(
customer=user.stripe_id,
locale="fr",
line_items=[
{"quantity": order.quantity,
"price": order.product.stripe_id}
for order in user_cart.orders.all()
],
mode='payment',
success_url=request.build_absolute_uri(reverse("checkout_success")),
cancel_url=request.build_absolute_uri(reverse("cart")),
automatic_tax={'enabled': True},
shipping_address_collection={"allowed_countries": ["FR", "CH", "US", "CA"]}
)
except Exception as e:
return str(e)
return redirect(checkout_session.url, code=303)
J'ai tenté de comprendre en lisant la doc de l'api de Stripe, mais celle-ci mentionne bien que customer attend une string, donc je ne comprends pas d'où sort ce get du message d'erreur.
Merci de votre aide!
salut Simon,
Je n´ai pas le pc ce soir.
Mais le client est bien crée dans stripe alors ?
Je fais ça avec stripe.
checkout_data = {
"locale": "fr",
"line_items": line_items,
"mode": 'payment',
# voir ds la doc. On passe un dico avec une liste de pays autorisés
"shipping_address_collection": {"allowed_countries": ["FR", "BE"]},
# il faut une url absolue car je suis sur Stripe à ce moment-là
"success_url": request.build_absolute_uri(reverse('store:checkout-success')),
"cancel_url": 'http://127.0.0.1:8000',
}
# une condition pour savoir si on a déjà un stripe_id pour notre user
if request.user.stripe_id:
checkout_data["customer"] = request.user.stripe_id
else:
checkout_data["customer_email"] = request.user.email
# créer le client dans stripe la première fois
checkout_data["customer_creation"] = "always"
# tout ce que j'avais ici je l'ai passé à checkout_data en dictionnaire
# on va utiliser l'unpacking
session = stripe.checkout.Session.create(**checkout_data)
Salut Gab, quand je crée un utilisateur dans mon site, je lui crée automatiquement un stripe id grâce à un script dans le manager de mon modèle d'utilisateur:
```python
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, *kwargs):
if not email:
raise ValueError("email obligatoire.")
email = self.normalize_email(email)
user: AbstractUser = self.model(email=email, *kwargs)
user.set_password(password)
stripe_customer = stripe.Customer.create(email=email)
user.stripe_id = stripe_customer.id
user.save()
return user
def create_superuser(self, email, password, **kwargs):
kwargs["is_staff"] = True
kwargs["is_superuser"] = True
kwargs["is_active"] = True
return self.create_user(email, password, **kwargs)```
Donc oui le client est bien préalablement créé dans Stripe, mais pourtant ma vue plante dès que j'y rajoute la ligne customer=user.stripe_id (cf mon message précédent pour la vue complète). Si je ne mets pas cette ligne, j'arrive bien sur l'écran de paiement de Stripe. À toutes fins utiles, voici également mon modèle utilisateur:
```python
class Shopper(AbstractUser):
username = None
email = models.EmailField(max_length=240, unique=True)
stripe_id = models.CharField(max_length=90, blank=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = CustomUserManager()```
Je n'arrive pas à comprendre pourquoi ça coince...
Pour répondre à ta question Thibault: si je mets un print(user.stripe_id) au début du bloc try de ma vue stripe_checkout_session, le stripe-id s'affiche correctement dans le terminal.
Et Gab, j'ai aussi essayé avec ta structure, en modifiant ma vue comme ceci:
```python
def stripe_checkout_session(request: HttpRequest) -> HttpRequest | str:
"""Stripe checkout session for payments"""
user: Shopper = request.user # type: ignore
user_cart = user.cart
checkout_data = {
"locale": "fr",
"line_items": [
{"quantity": order.quantity,
"price": order.product.stripe_id}
for order in user_cart.orders.all()
],
"mode": 'payment',
"success_url": request.build_absolute_uri(reverse("checkout_success")),
"cancel_url": request.build_absolute_uri(reverse("cart")),
"automatic_tax": {'enabled': True},
"shipping_address_collection": {"allowed_countries": ["FR", "CH", "US", "CA"]}
}
if request.user.stripe_id:
checkout_data["customer"] = user.stripe_id
else:
checkout_data["customer_email"] = user.email
checkout_data["customer_creation"] = "always"
try:
print(user.stripe_id) # le stripe_id s'affiche correctement dans le terminal
checkout_session = stripe.checkout.Session.create(**checkout_data)
except Exception as e:
return str(e)
return redirect(checkout_session.url, code=303)```
Le problème reste le même:

(mais si je commente le bloc suivant, je n'ai plus cette erreur:
if request.user.stripe_id:
checkout_data["customer"] = user.stripe_id
else:
checkout_data["customer_email"] = user.email
checkout_data["customer_creation"] = "always"
)
C'est comme si la structure de donnée string ne convenait pas au paramètre customer...
Comme demandé par Gab, j'ai fait un repo, et je vous ai remis le problème dans le README. Merci de votre aide!
https://github.com/salsififi/Doc_Shop?tab=readme-ov-file
Oui, dans la méthode create_user de mon manager (cf quelques messages plus haut pour le détail du code de cette fonction).
Ok, essaye de faire comme ça plutot, ne créé pas de stripe id d'avance. Fait le au moment du paiement.
Du genre :
def create_checkout_session(request):
# récupère le panier
cart = request.user.cart
# compréhension de liste avec un dictionnaire (id + qté)
line_items = [{"price": order.product.stripe_id,
"quantity": order.quantity} for order in cart.orders.all()]
checkout_data = {
"locale": "fr",
"line_items": line_items,
"mode": 'payment',
# voir ds la doc. On passe un dico avec une liste de pays autorisés
"shipping_address_collection": {"allowed_countries": ["FR", "BE"]},
# il faut une url absolue car je suis sur Stripe à ce moment-là
"success_url": request.build_absolute_uri(reverse('store:checkout-success')),
"cancel_url": 'http://127.0.0.1:8000',
}
# une condition pour savoir si on a déjà un stripe_id pour notre user
if request.user.stripe_id:
checkout_data["customer"] = request.user.stripe_id
else:
checkout_data["customer_email"] = request.user.email
# créer le client dans stripe la première fois
checkout_data["customer_creation"] = "always"
# tout ce que j'avais ici je l'ai passé à checkout_data en dictionnaire
# on va utiliser l'unpacking
session = stripe.checkout.Session.create(**checkout_data)
return redirect(session.url, code=303)
# Puis le webhook
@csrf_exempt
def stripe_webhook(request):
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
endpoint_secret = env("endpoint_secret")
event = None
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return HttpResponse(status=400)
# on veut récupérer l'évènement checkout.session.completed, il s'agit d'un dico
if event['type'] == "checkout.session.completed":
# dans event on a un objet qui permet de récup mail user produits acheté etc ds data object
data = event['data']['object']
pprint(data)
try:
user = get_object_or_404(Shopper, email=data['customer_details']['email'])
# dans object (voir var data) on a l'email
except KeyError:
return HttpResponse("Invalid user email", status=404)
# deux fonctions du dessous
complete_order(data=data, user=user)
return HttpResponse(status=200)
# et cette petite fonction qui fait le boulot ^^
def complete_order(data, user):
user.stripe_id = data['customer']
user.cart.order_ok()
# faire un save pour le stripe_id
user.save()
# 200 pour indiquer que le paiement a été procéssé correctement
return HttpResponse(status=200)
Merci Gab, mais regarde ma vuestripe_checkout_session, j'ai fait exactement ce que tu dis!
J'ai le sentiment qu'on ne regarde pas au bon endroit. Si tu as bien un customer, ça devrait être bon, donc je pense que ce n'est pas le fait d'ajouter ou d'enlever la ligne customer qui fait planter le script. Probablement qu'en omettant cette information tu passes par une "route" différente du côté de Stripe qui ne provoque pas d'erreur.
J'ai le sentiment donc que le problème peut être ailleurs et il faut vérifier ça avant de tourner en rond sur le customer id.
Fait un print ou un debug de ton checkout_data pour vérifier que tout est bon : que tu as bien le order.product.stripe_id, le order.quantity, que les URL de redirection sont bonnes, etc.
Je t'assure que c'est bien le fait d'enlever ou d'ajouter la ligne qui fait marcher ou planter. En effet, quand je pase juste par customer_email = user.email, tout marche, c'est-à-dire que je peux effectuer le paiement, et que je retrouve celui-ci sur Stripe. Sauf que ça l'attribuait à un utilisateur "invité" (ce que signalait Christian au début de cette série de questions), c'est pour ça que j'ai voulu passer par customer. Mystère et triple chewing gum...
Je ne doute pas que ce soit cette ligne qui fasse planter ou non le script, ce dont je doute, c'est que le problème soit relié au customer_id.
C'est assez courant quand on est face à une erreur qui semble incompréhensible et c'est le genre d'erreur qui font tourner en rond parce qu'on ne cherche pas au bon endroit. Pour cette raison, il est préférable avant de s'obstiner de chercher un peu autour (vérifier les autres paramètres, par exemple est-ce que tu es en test mode, est-ce que le webhook est le bon, est-ce que les autres paramètres sont bons) afin de s'assurer que l'erreur n'est pas évidente et juste à côté.
Si après cette exploration autour de l'erreur on ne trouve rien, on peut se focaliser de nouveau sur le customer_id ;) Le but n'est pas de passer 1h sur le contexte environnant non plus, mais juste vérifier qu'il n'y a rien autour qui pourraient causer ce problème.
Imagine que ton produit est mal configuré, peut-être que sans donner un customer_id, dans Stripe il crée le customer et il lance des webhook ensuite qui crée ton produit mal configuré. Du coup tu ne vois pas l'erreur directement parce que le customer n'est pas encore créé. Maintenant quand tu rajoutes le customer_id, ça crée le produit tout de suite mais comme il est mal configuré, tu vois l'erreur directement. C'est hypothétique, mais c'est juste pour te montrer que dans ce cas, l'erreur est bien causée par le customer_id (et disparait donc quand on l'enlève), mais que la source de l'erreur se trouve ailleurs.
Ok, merci Thibault, je comprends ce que tu veux dire. Mais j'ai beau chercher "à côté", pour l'instant je ne trouve rien (je suis bien en mode test dans Stripe, le webhook me semble le bon., etc). Du coup, j'ai encore tendance à penser que le problème vient peut-être tout simplement de la structure de données que je passe au paramètre customer: en effet, j'avais eu exactement la même erreur quand j'avais passé à un autre paramètre une chaîne au lieu d'un dictionnaire (mais dans l'API de Stripe en l'occurrence, il est bien stipulé de passer une chaîne).Bon, je vais laisser reposer ça quelques jours, peut-être qu'en y retournant avec un oeil neuf et moins fatigué, je trouverai en 2 minutes ce qui coince. Allez, je fais un break, la sieste porte souvent conseil 😄!
Bingo! En mettant à jour avec la dernière version du module stripe (11.2.0, au lieu de la 11.1.1 que j'utilisais avant), ça marche parfaitement. Vu que j'avais installé il y a 2 semaines la 11.1.1 (qui était la dernière version à jour à l'époque), je n'aurais jamais imaginé que le problème pouvait venir de là. Bien vu, merci beaucoup Thibault!
Salut, vous allez rire (ou pas!), mais après 3 jours de bons et loyaux service de ma vue stripe_checkout_session suite à la mise à jour de la bibliothèque stripe, le problème est revenu (alors même que je n'ai pas retouché à cette vue). J'ai testé sur plisieurs versions de stripe, j'ai réinstallé la plus récente, cette fois même combat... Je n'écris pas cela pour avoir de l'aide (quoique je ne suis pas contre une "illumination" si quelqu'un pense à un truc comme Thibault a fait il y a quelques jours avec la version), mais juste pour informer les personnes qui suivront ce fil de questions qu'au final l'utilisation d'une version ancienne (de 1 mois seulement, mais bon...) n'expliquait semble-t-il pas tout. Un jour j'y arriverai 😜!
Re !
ça fonctionne chez moi je viens de tester : https://youtu.be/Yghy1MSBwug
Je précise bien que je ne créé pas le customer direct comme tu fais, je le fais au moment du premier paiement.
Tu avais raison Gabriel, le souci venait bien de là ! En fait j'avais transformé ma méthode stripe_checkout_session pour la faire coller à la tienne, mais je n'avais pas retiré ces 2 lignes dans la méthode create_user() de mon CustomUserManager:
stripe_customer = stripe.Customer.create(email=email)
user.stripe_id = stripe_customer.id
En les commentant, le problème ne se pose plus pour les nouveaux utilisateurs (il ne se pose que pour les anciens, dont le stripe_id a été généré de cette manière).
Je ne comprends pas pourquoi ces 2 lignes posent problème (dans l'API de Stripe il est bien indiqué pour l'objet Customer que id est une chaîne de caractères de type "cus_NffrFeUfNV2Hib"). Si jamais toi tu vois où est le bins, dis-moi, j'aime bien comprendre les choses jusqu'au bout!
En tout cas un grand bravo et merci à toi! (ainsi qu'à Thibault dont la patience a été mise également à rude épreuve 😅).
Génial si ça fonctionne du coup. Je me suis replongé dan Stripe que je n'ai pas fait depuis février pour un projet ça fait du bien aussi.
Alors oui avec leur api ça ne passait pas avec la façon cité ci-dessus...curieux, ça pourrait être sympa de parler avec l'équipe de dev ^^.
Sans rigoler, il m'arrive de contacter les personnes souvent comme ça ahah.
En tous cas, ouf si ça fonctionne !!
Inscris-toi
(c'est gratuit !)
Tu dois créer un compte pour participer aux discussions.
Créer un compte