Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
342 views
in Technique[技术] by (71.8m points)

How to change make changes to my 'Order' in Django after receiving payment by Stripe Checkout Session?

I am making an e-commerce website by Django and want to use Stripe Checkout Session for receiving online payments.

I followed https://stripe.com/docs/api/checkout/sessions for creating checkout sessions and https://stripe.com/docs/webhooks/build for creating the webhooks.

I could receive payments smoothly, but I want to change the 'order' to 'complete = True' right after payments are received. However, the request of view 'stripe_webhook' does not have attribute of user, so I can't call 'request.user' to get the corresponding 'order'. How could I solve this issue? Thanks so much.

models.py

class Order(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    date_created = models.DateTimeField(auto_now_add=True, null = True, blank = True)
    date_completed = models.DateTimeField(null = True, blank = True)
    complete = models.BooleanField(default=False)
    transaction_id = models.CharField(max_length=100, null=True)

    def __str__(self):
        return f'{self.user.username} {self.date_created}'

views.py

@login_required
def stripe_payment(request):
    return render(request, 'stripe_payment.html', {})


@csrf_exempt
def stripe_config(request):
    if request.method == 'GET':
        stripe_config = {'publicKey': settings.STRIPE_PUBLISHABLE_KEY}
        return JsonResponse(stripe_config, safe=False)


@csrf_exempt
def stripe_create_checkout_session(request):
    if request.method == 'GET':
        domain_url = 'http://localhost:8000/'
        stripe.api_key = settings.STRIPE_SECRET_KEY
        order = Order.objects.get(user = request.user, complete = False)
        total = int(order.get_cart_items_total) * 100

        try:
            checkout_session = stripe.checkout.Session.create(
                success_url = domain_url + 'success?session_id={CHECKOUT_SESSION_ID}',
                cancel_url = domain_url + 'cancelled/',
                payment_method_types = ['card'],
                mode = 'payment',
                line_items = [
                    {
                        'name': ' ',
                        'quantity': 1,
                        'currency': 'usd',
                        'amount': total,
                    }
                ]
            )
            return JsonResponse({'sessionId': checkout_session['id']})

        except Exception as e:
            return JsonResponse({'error': str(e)})


@csrf_exempt
def stripe_webhook(request):
    stripe.api_key = settings.STRIPE_SECRET_KEY
    endpoint_secret = settings.STRIPE_ENDPOINT_SECRET
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    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)

    # Handle the checkout.session.completed event
    if event['type'] == 'checkout.session.completed':
        print("Payment was successful.")

        #request of this view does not have any user attribute
        order = Order.objects.get(user = request.user, complete = False)
        transaction_id = datetime.now().timestamp()
        order.complete = True
        order.transaction_id = transaction_id
        order.date_completed = datetime.now()
        order.save()
        print("Order was successfully updated and saved.")

    return HttpResponse(status=200)



def payment_success(request):
    return render(request, 'success.html', {})


def payment_cancel(request):
    return render(request, 'cancelled.html', {})

stripe.js

fetch("/stripe_config/")
.then((result) => { return result.json(); })
.then((data) => {
    // Initialize Stripe.js
    const stripe = Stripe(data.publicKey);

    // Event handler
    document.querySelector("#submitBtn").addEventListener("click", () => {
    // Get Checkout Session ID
    fetch("/stripe_create_checkout_session/")
    .then((result) => { return result.json(); })
    .then((data) => {
        console.log(data);
        // Redirect to Stripe Checkout
        return stripe.redirectToCheckout({sessionId: data.sessionId})
    })
    .then((res) => {
        console.log(res);
    });
    });
});

urls.py from django.urls import path from .views import *

urlpatterns = [  
    path('stripe_payment/', stripe_payment, name = 'stripe_payment'),
    path('stripe_config/', stripe_config, name = 'stripe_config'),
    path('stripe_create_checkout_session/', stripe_create_checkout_session, name = 'stripe_create_checkout_session'),
    path('webhook/', stripe_webhook),
    path('success/', payment_success, name = 'payment_success'),
    path('cancelled/', payment_cancel, name = 'payment_cancel'),

]

stripe_payment.html

{% extends 'base.html' %}
{% load static %}

{% block head_title %}Django + Stripe Checkout{% endblock %}


{% block extra_head %}
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/bulma.min.css">
    <script src="https://js.stripe.com/v3/"></script>
    <script src="{% static 'js/stripe.js' %}"></script>
    <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
{% endblock %}


{% block content %}
<!--Main layout-->
    <main>
        <section class="section">
        <div class="container">
            <button class="button is-primary" id="submitBtn">Purchase!</button>
        </div>
        </section>
    </main>
<!--Main layout-->
{% endblock content %}
question from:https://stackoverflow.com/questions/65932993/how-to-change-make-changes-to-my-order-in-django-after-receiving-payment-by-st

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Stripe webhook Events have a data.object property which represents the object the event is about.

In the case of a checkout.session.completed event, data.object would describe a Checkout Session object, which contains a reference to the ID of the customer that was created.

The webhook event won't have the request.user property since the call comes from Stripe and not from your client. You'd want to instead either collect the Stripe customer ID or the Checkout Session ID and map that to a user in your own database.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...