A_K
A_K

Reputation: 912

Django: After Successful Payment Via PayPal how to redirect user to order completed page

I am setting a PayPal payment for my E-commerce project and everything is working fine except that after the payment is executed and the PayPal windows is closed, the website page remains open and the items remain in the cart.

I have set the stripe payment to redirect to a page called "order completed" with some order reference code, which I am trying to implement to PayPal payment option.

Here is the views.html:

def payment_complete(request):
    body = json.loads(request.body)
    order = Order.objects.get(
        user=request.user, ordered=False, id=body['orderID'])
    payment = Payment(
        user=request.user,
        stripe_charge_id=body['payID'],
        amount=order.grand_total()
    )
    payment.save()

    # assign the payment to order
    order.payment = payment
    order.ordered = True
    order.ref_code = create_ref_code()
    order.save()
    messages.success(request, "Your Order was Successful ! ")
    # Email when order is made
    template = render_to_string("payment_confirmation_email.html", {'first_name': request.user.first_name,
                                                                    'last_name': request.user.last_name,
                                                                    'order': order})

    msg = EmailMessage('Thanks for Purchasing', template,
                       settings.EMAIL_HOST_USER, [request.user.email])
    msg.content_subtype = "html"  # Main content is now text/html
    msg.fail_silently = False
    msg.send()

    # End of the email send
    return render(request, "order_completed.html", {'order': order})


class PaymentView(View):
    def get(self, *args, **kwargs):
        # order
        order = Order.objects.get(user=self.request.user, ordered=False)
        if order.billing_address:
            context = {
                'order': order,
                'DISPLAY_COUPON_FORM': False
            }
            return render(self.request, "payment.html", context)
        else:
            messages.warning(
                self.request, "You have not added a billing address")
            return redirect("core:checkout")

    # `source` is obtained with Stripe.js; see https://stripe.com/docs/payments/accept-a-payment-charges#web-create
    # -token
    def post(self, *args, **kwargs):
        order = Order.objects.get(user=self.request.user, ordered=False)
        token = self.request.POST.get('stripeToken')
        amount = int(order.grand_total() * 100)

        try:
            charge = stripe.Charge.create(
                amount=amount,  # cents
                currency="usd",
                source=token,
            )
            # create payment
            payment = Payment()
            payment.stripe_charge_id = charge['id']
            payment.user = self.request.user
            payment.amount = order.grand_total()
            payment.save()

            # assign the payment to the order

            order_items = order.items.all()
            order_items.update(ordered=True)
            for item in order_items:
                item.save()

            order.ordered = True
            order.payment = payment
            order.ref_code = create_ref_code()
            order.save()

            messages.success(self.request, "Your Order was Successful ! ")
            # Email when order is made
            template = render_to_string("payment_confirmation_email.html", {'first_name': self.request.user.first_name,
                                                                            'last_name': self.request.user.last_name,
                                                                            'order': order})

            msg = EmailMessage('Thanks for Purchasing', template,
                               settings.EMAIL_HOST_USER, [self.request.user.email])
            msg.content_subtype = "html"  # Main content is now text/html
            msg.fail_silently = False
            msg.send()

            # End of the email send
            return render(self.request, "order_completed.html", {'order': order})

here is the PayPal script:

  <!--Paypal Script-->
  <script>
    // Render the PayPal button into #paypal-button-container
    function getCookie(name) {
      var cookieValue = null;
      if (document.cookie && document.cookie !== "") {
        var cookies = document.cookie.split(";");
        for (var i = 0; i < cookies.length; i++) {
          var cookie = cookies[i].trim();
          // Does this cookie string begin with the name we want?
          if (cookie.substring(0, name.length + 1) === name + "=") {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
            break;
          }
        }
      }
      return cookieValue;
    }

    var csrftoken = getCookie("csrftoken");
    var orderID = "{{order.id}}";
    var amount = "{{order.grand_total|floatformat:2}}";
    var url = "{% url 'core:payment_complete' %}";

    paypal.Buttons({
      style: {
        color: "blue",
        shape: "pill",
        label: "pay",
        height: 40,
      },
        // Set up the transaction
        createOrder: function(data, actions) {
            return actions.order.create({
                purchase_units: [{
                    amount: {
                        value: amount,
                    }
                }]
            });
        },

        // Finalize the transaction
        onApprove: function(data, actions) {
            return actions.order.capture().then(function(details) {
                console.log(details);
                sendData();
                function sendData() {
                  fetch(url, {
                    method: "POST",
                    headers: {
                      "Content-type": "application/json",
                      "X-CSRFToken": csrftoken,
                    },
                    body: JSON.stringify({ orderID: orderID, payID: details.id }),
                  });
                }
                // Show a success message to the buyer
                alert('Transaction completed by ' + details.payer.name.given_name + '!');
            });
        }


    }).render('#paypal-button-container');
  </script>
  <!--Paypal Script-->

Upvotes: 0

Views: 1201

Answers (2)

Devendra
Devendra

Reputation: 73

Paypal client-side integration using Django: To handle your situation, create a new view in your view.py Your JS request is processed and then redirected, but not your browser window! You need your js code to listen for a response and then trigger a redirect.

urls.py

urlpatterns = [
    path('paypal-payment/', views.paypal_payment, name="paypal_payment"),
    path('order-complete/', views.order_complete, name="order_complete"),
]

views.py:

from django.http import JsonResponse

def payment_process(request):
    body = json.loads(request.body)
    order = Order.objects.get(user=request.user, ordered=False, id=body['orderID'])

    # create the payment
    payment = Payment()
    payment.stripe_charge_id = body['payID']
    payment.user = request.user
    payment.amount = order.get_total()
    payment.save()

    # assign the payment to the order
    order_items = order.items.all()
    order_items.update(ordered=True)
    for item in order_items:
        item.save()

    order.ordered = True
    order.payment = payment
    order.save()

    # your other logic goes here

    return JsonResponse('Payment submitted..', safe=False)

def order_complete(request):
    messages.success(request, "Your order was successful!")
    return render(request, 'order_complete.html') # you can pass any context as needed
  

And in you PayPal script

<!--Paypal Script-->
<
script >
  // Render the PayPal button into #paypal-button-container
  function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== "") {
      var cookies = document.cookie.split(";");
      for (var i = 0; i < cookies.length; i++) {
        var cookie = cookies[i].trim();
        // Does this cookie string begin with the name we want?
        if (cookie.substring(0, name.length + 1) === name + "=") {
          cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
          break;
        }
      }
    }
    return cookieValue;
  }

var csrftoken = getCookie("csrftoken");
var orderID = "{{order.id}}";
var amount = "{{order.grand_total|floatformat:2}}";
var url = "{% url 'core:paypal_payment' %}";

paypal.Buttons({
  style: {
    color: "blue",
    shape: "pill",
    label: "pay",
    height: 40,
  },
  // Set up the transaction
  createOrder: function(data, actions) {
    return actions.order.create({
      purchase_units: [{
        amount: {
          value: amount,
        }
      }]
    });
  },

  // Finalize the transaction
  onApprove: function(data, actions) {
    return actions.order.capture().then(function(details) {
        console.log(details);
        sendData();

        function sendData() {
          fetch(url, {
              method: "POST",
              headers: {
                "Content-type": "application/json",
                "X-CSRFToken": csrftoken,
              },
              body: JSON.stringify({
                orderID: orderID,
                payID: details.id
              }),
            })
            .then((response) => response.json())
            .then((data) => {
              console.log('Success:', data); // Just for testing, you can delete
              alert('Transaction completed'); // Just for testing, you can delete
              window.location.href = "{% url 'products:order_complete' %}"
            });
        }
      }
      // Show a success message to the buyer
      alert('Transaction completed by ' + details.payer.name.given_name + '!'); // Just for testing, you can delete
    });
}


}).render('#paypal-button-container'); <
/script>
<!--Paypal Script-->

Upvotes: 2

Daniel
Daniel

Reputation: 3527

In this example we use ajax to send a post request to the django backend when a user clicks the 'submit' button.

urls.py:

urlpatterns = [
    ...
    path('process_payment', views.process_payment, name='process_payment'),
    ...
]

views.py:

from django.http import HttpResponse
import json    

def process_payment(request): 
   
    # unpack request:
    field1 = request.POST['field1']

    # other logic, send email, etc.:
    ...

    # pack context:
    context = json.dumps({
        'payment_success' : True # true or false
    })

    return HttpResponse(context)

In paypal.js (your js script):

// this buttons executes when the user presses the 'submit' button:
function process_payment() {
    $.ajax({
        url : 'process_payment',
        data : {
            csrfmiddlewaretoken: 'the_csrf_token',
            field1 : 'field1_data', // pass other fields as needed
            ...
        },
        success: payment_success_function,
    });
} $('#submit-button-id').click(payment_success);

// this function executes when a response is received from the backend:
payment_method_success(response) {

    // unpack response (context) from views.py:
    var payment_success = response.payment_success;

    if (payment_success) window.location('the_new_url');
    else alert('Something went wrong with your payment!');

}

Upvotes: 0

Related Questions