Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to integrate Stripe payments gateway with Django Oscar?

I am trying to integrate the Stripe payment gateway to Django oscar for an e-commerce site which sells physical goods like groceries online.I use python 3.6.3, Django 2.0, Django-oscar 1.6, stripe 1.82.2.

Method 1:

So I followed this link in django-oscar groups:

https://groups.google.com/forum/#!searchin/django-oscar/handle_payment$20override%7Csort:date/django-oscar/Cr8sBI0GBu0/PHRdXX2uFQAJ

I have signed up for a stripe account and used my publishable key and test key to configure stripe.The problem is, when I try to pay using the button provided with label "Pay with Card",it collects my card information and then when I click the button, it shows "Some money will be debited from the card" like in this image: Image of Preview page

Then after I click the place order button,it shows me this: Image of confirmation page

Though I have paid using my card. I guess oscar doesn't seem to know that the payment has been done through stripe already?But I'm not sure how to solve this.

Method 2: I tried to use dj-stripe,found here:

https://github.com/dj-stripe/dj-stripe

But I read the whole documentation on https://dj-stripe.readthedocs.io/en/stable-1.0/ , it seems like I can use it only for products that need subscriptions, mine don't require subscribing and the docs for dj-stripe aren't fully complete.

I tried with the official django-oscar repo, the link is here: https://github.com/django-oscar/django-oscar-stripe , this repository is like five years old and I don't think it would be compatible to use with my version of Django oscar.

Method 3: I tried using the stripe.js and elements and created my form to accept cards:

< script src = "https://js.stripe.com/v3/" > < /script> <
  script >
  var stripe = Stripe('your_stripe_publishable_key');
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
var style = {
  base: {
    color: '#32325d',
    lineHeight: '18px',
    fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
    fontSmoothing: 'antialiased',
    fontSize: '20px',
    '::placeholder': {
      color: '#aab7c4'
    }
  },
  invalid: {
    color: '#fa755a',
    iconColor: '#fa755a'
  }
};

// Create an instance of the card Element.
var card = elements.create('card', {
  style: style
});

// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
card.addEventListener('change', function(event) {
  var displayError = document.getElementById('card-errors');
  if (event.error) {
    displayError.textContent = event.error.message;
  } else {
    displayError.textContent = '';
  }
});

// Create a source or display an error when the form is submitted.
var form = document.getElementById('payment-form');

form.addEventListener('submit', function(event) {
  event.preventDefault();

  stripe.createSource(card).then(function(result) {
    if (result.error) {
      // Inform the user if there was an error
      var errorElement = document.getElementById('card-errors');
      errorElement.textContent = result.error.message;
    } else {
      // Send the source to your server
      stripeSourceHandler(result.source);
    }
  });
});

function stripeSourceHandler(source) {
  // Insert the source ID into the form so it gets submitted to the server
  var form = document.getElementById('payment-form');
  var hiddenInput = document.createElement('input');
  var hiddenAmount = document.createElement('input');

  hiddenInput.setAttribute('type', 'hidden');
  hiddenInput.setAttribute('name', 'stripeSource');
  hiddenInput.setAttribute('value', source.id);
  form.appendChild(hiddenInput);

  hiddenAmount.setAttribute('type', 'hidden');
  hiddenAmount.setAttribute('name', 'amt');
  hiddenAmount.setAttribute('value', '{{ order_total.incl_tax|safe }}');
  form.appendChild(hiddenAmount);

  // Submit the form
  form.submit();
}

<
/script>
<form action="/charge/" method="post" id="payment-form">
  {% csrf_token % }
  <div class="form-row">
    <label for="card-element">
                Credit or debit card
            </label>
    <div id="card-element">
      <!-- A Stripe Element will be inserted here. -->
    </div>

    <!-- Used to display Element errors. -->
    <div id="card-errors" role="alert"></div>
  </div>
  <br>
  <!--<hr>-->
  <button class="btn btn-primary">Pay Now</button>
</form>

And in my python views.py file I create a stripe charge and also sources.

@csrf_exempt
def stripe_payment(request):
    user = request.user
    source_id = request.POST.get("stripeSource", None)

    amount = request.POST.get("amt", None)
    stripe.api_key = "your_test_key"
    customer = stripe.Customer.create(
        email=email,
        source=source_id,
    )
    # print("Customer ID: ", customer['id'])
    amt = float(amount) * 100
    # print("Amount:", int(amt))
    int_amt = int(amt)
    charge = stripe.Charge.create(
        amount=int_amt,
        currency='cad',
        customer=customer['id'],
        source=source_id,
    ) 

    return HttpResponseRedirect("/checkout/preview/")

Then I created a webhook in the stripe dashboard and linked it to my local url , every-time there is a response from stripe being sent through the web-hook, this url is hit.

@csrf_exempt
def demo_checkout(request):

    # Retrieve the request's body and parse it as JSON:
    event_json = json.dumps(json.loads(request.body), indent=4)
    # event_json = json.loads(request.body)

    # Do something with event_json
    print("Json event:", event_json)

    return HttpResponse(status=200)

As of now, I can track the various events or logs from my dashboard and the events like creating a customer, making a charge and the web-hook sending a response is working fine,but I can't figure out how can I complete the payment such that Django-oscar can also know that the payment is done and it doesn't show "No payment was required": Thank you page

I have tried all these methods,but it still doesn't work.I am open to using any other method which is suggested or an improvement to what I have done in any of the methods explained so far.I am new to django-oscar and an answer with some code and some explanation would be helpful.

like image 875
Sammy J Avatar asked Jul 09 '18 10:07

Sammy J


People also ask

How do you integrate Stripe payment gateway in Python?

Create a new Django Project and add required pages to accept payments or sell products. Install stripe package using pip install stripe. Configure stripe checkout. Accept payments.

Is stripe easy to integrate?

Integrate Stripe with Your Website Once you have a Stripe account ready, it is quite straightforward to link it to your website. However, you need to have the WooCommerce plugin installed on your WordPress. The plugin is free, and easy to use.


2 Answers

I have found a way to integrate Stripe with Django Oscar, this is one of the easy ways to do it.

  1. Create a stripe account first from here:https://stripe.com/, you will get a publishable key and a secret key, you can view them after logging in into the stripe dashboard under Developers > API keys.

  2. In your django oscar code side. Fork the checkout app from oscar, add it to the INSTALLED_APPS+=get_core_apps(['checkout']).To know how to fork an app you can follow this link from the docs:https://django-oscar.readthedocs.io/en/latest/topics/customisation.html#fork-oscar-app

  3. Create a file called facade.py under checkout, copy the keys from your dashboard into the settings.py file and do the other changes as suggested in this link: Stripe payment gateway integration on the django oscar groups, it just happens to be titled wrong.Just follow this whole page and it's done.

like image 107
Sammy J Avatar answered Oct 12 '22 01:10

Sammy J


When you check the logs in your Stripe Dashboard ("Developer > Logs" section) do you see requests for the creation of the Token, Customer and Charges? Were these requests successful? Do you see any errors?

In relation to Django Oscar, I'm not familiar with it so not sure if the below would help.

But I had a look at the Django Oscar code and it seems that the "No payment was required" message is shown by the thank_you template when the Order record doesn't have any sources added to it (i.e order.sources.all returning empty):

https://github.com/django-oscar/django-oscar/blob/master/src/oscar/templates/oscar/checkout/thank_you.html#L94

So it could be that in your handle_payment code you may be not properly adding the source record to the current Order record as suggested in this recipe or the email thread you listed.

For debugging this further, I would suggest to:

  • Check the logs in your Stripe dashboard to see if you are correctly creating the Charge.

  • query the Source model and check if any records are associated with the particular order ID

  • add some additional debug (log/print) statements to your code in handle_payment to check if it gets called and if it creates the Source record as it should be:

    http://django-oscar.readthedocs.io/en/releases-1.1/howto/how_to_integrate_payment.html#integration-into-checkout

like image 21
psmvac Avatar answered Oct 12 '22 01:10

psmvac