Home > front end >  Stripe implementation in django not redirecting to success page
Stripe implementation in django not redirecting to success page

Time:11-19

I was trying to implement stripe in Django and everything worked fine until I tried to redirect the user to a success page after the payment. Can anybody have a look at my code and tell me what I am doing wrong?

views.py

@csrf_exempt
def create_checkout_session(request, id):
    request_data = json.loads(request.body)
    gig = get_object_or_404(Gig, pk=id)
    stripe.api_key = settings.STRIPE_SECRET_KEY
    checkout_session = stripe.checkout.Session.create(
        customer_email=request_data['email'],
        payment_method_types=['card'],
        line_items=[
            {
                'price_data': {
                    'currency': 'eur',
                    'product_data': {
                        'name': gig.seller,
                    },
                    'unit_amount': int(gig.price * 100),
                },
                'quantity': 1,
            }
        ],

        mode='payment',
        success_url='http://127.0.0.1:8000/checkout/success?session_id={CHECKOUT_SESSION_ID}',
        cancel_url='http://127.0.0.1:8000/checkout/failed/',
    )

    order = OrderDetail()
    order.customer_email = request_data['email']
    order.gig = gig
    order.stripe_payment_intent = checkout_session.payment_intent
    order.amount = int(gig.price * 100)
    order.save()
    
    # return JsonResponse({'data': checkout_session})
    return JsonResponse({'sessionId': checkout_session.id})


class PaymentSuccessView(TemplateView):
    template_name = "checkout/payment_success.html"

    def get(self, request, *args, **kwargs):
        session_id = request.GET.get('session_id')
        if session_id is None:
            return HttpResponse("failed")
        
        stripe.api_key = settings.STRIPE_SECRET_KEY
        session = stripe.checkout.Session.retrieve(session_id)
        
        order = get_object_or_404(OrderDetail, stripe_payment_intent=session.payment_intent)
        order.has_paid = True
        order.save()
        return render(request, self.template_name)

models.py

from django.db import models
from django.core import validators




class OrderDetail(models.Model):

    id = models.BigAutoField(
        primary_key=True
    )

    # You can change as a Foreign Key to the user model
    customer_email = models.EmailField(
        verbose_name='Customer Email'
    )

    gig = models.ForeignKey(
        to=Gig,
        verbose_name='Product',
        on_delete=models.PROTECT
    )

    amount = models.IntegerField(
        verbose_name='Amount'
    )

    stripe_payment_intent = models.CharField(
        max_length=200, null=True, blank=True
    )

    # This field can be changed as status
    has_paid = models.BooleanField(
        default=False,
        verbose_name='Payment Status'
    )

    created_on = models.DateTimeField(
        auto_now_add=True
    )

    updated_on = models.DateTimeField(
        auto_now_add=True
    )


class Gig(models.Model):
    id = models.BigAutoField(
        primary_key=True
    )

    gigger = models.ForeignKey(
        Mentors, 
        on_delete=models.CASCADE,
        related_name="seller")
    
    description = models.TextField(
        blank=True,
        max_length=800,
        verbose_name='Description'
    )

    price = models.DecimalField(
        verbose_name='Price',
        decimal_places=2,
        max_digits=6,
    )


    def __str__(self):
       return f"{self.gigger}, ${self.price}, id:{self.id}"


class Comments:
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="Commentor")
    comment = models.TextField(blank=True)
    stars = models.PositiveSmallIntegerField()

product.html

{% extends 'web/layout.html' %}

{% block body %}
<h1 >Product Detail</h1>
<div >

    <div >
        <div >
            <h2>Product Detail</h2>
        </div>
        <div >
            <div >
                <div >
                    <img src="https://dummyimage.com/150x150.gif?text={{ object.name }}" alt="">
                </div>
                <div >
                    <h1>Name: {{ object.seller.mentor.username }}</h1>
                    <p>Description: {{ object.description }}</p>
                    <p>Price: {{ object.price }}</p>

                    <div >
                        <label for="email">Email: </label>
                        <input type="email" name="email" id="email"  placeholder="{{object.gigger.mentor.email}}">
                        <small>Please enter your email address</small>
                    </div>
                </div>
            </div>
        </div>
        <div >
            <button  id="checkout-button">Checkout</button>
        </div>
    </div>
</div>

<script src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
    // Create an instance of the Stripe object with your publishable API key
    var stripe = Stripe('{{ stripe_publishable_key }}');
    var checkoutButton = document.getElementById('checkout-button');

    checkoutButton.addEventListener('click', function () {

        var email = document.getElementById('email').value;
        if (email.length == 0) {
            alert("Please enter your email address.");
            return;
        }

        // Create a new Checkout Session using the server-side endpoint you
        // created in step 3.
        fetch("http://127.0.0.1:8000/checkout/api/checkout-session/{{ object.id }}/", {
            method: 'POST',
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(
                { email: email }
            )
        })
            .then(response => response.json())
            .then(function (session) {
                return stripe.redirectToCheckout({ sessionId: session.sessionId });
            })
            .then(function (result) {
                // If `redirectToCheckout` fails due to a browser or network
                // error, you should display the localized error message to your
                // customer using `error.message`.
                if (result.error) {
                    alert(result.error.message);
                }
            })
            .catch(function (error) {
                console.error('Error:', error);
            });
    });
</script>
{% endblock %}

After placing an order, when I go in the 'order details' object and see the 'stripe_payment_intend' key is always empty, it doesn't get saved. What else could I try to get each different order?

CodePudding user response:

The issue is that the point when you create the Checkout Session and set the order data is disconnected from the point at which you render your success page with the PaymentSuccessView class. Just because those two pieces of code are in the same file does not mean the state will be maintained between different requests.

What you can do instead is add the order information to the Checkout Session using metadata. Then when you retrieve the Checkout Session on your success page you can read the metadata from the Checkout Session to get the associated information.

  • Related