How to integrate Stripe payments gateway with Django Oscar?
Asked Answered
P

3

7

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.

Pasadena answered 9/7, 2018 at 10:33 Comment(1)
Related #33239155Jago
P
6

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.

Pasadena answered 15/7, 2018 at 12:24 Comment(0)
J
2

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:

Jetpropelled answered 9/7, 2018 at 13:39 Comment(0)
S
0

The easiest way to do it currently with the latest API in 2023 is to use https://github.com/st8st8/django-oscar-stripe-sca

Follow these steps.

  1. pip install django-oscar-stripe-sca
  2. Fork Checkout from django by first creating a folder called apps in the same structure as your manage.py folder and then run python manage.py oscar_fork_app checkout apps
  3. In apps/checkout/apps.py paste the code from here https://github.com/st8st8/django-oscar-stripe-sca/blob/master/sandbox/apps/checkout/apps.py
  4. in apps/checkout/views.py paste the code from here https://github.com/st8st8/django-oscar-stripe-sca/blob/master/sandbox/apps/checkout/views.py
  5. Create a templates/checkout folder in the same level as your settings
  6. In templates/checkout/payment_details.html paste the code from here sandbox/templates/checkout/payment_details.html
  7. In templates/checkout/preview.html paste the code from here sandbox/templates/checkout/preview.html
  8. In settings.py add 'oscar_stripe_sca' to your installed apps
  9. In settings.py replace 'oscar.apps.checkout.apps.CheckoutConfig' with 'apps.checkout.apps.StripeSCASandboxCheckoutConfig' in installed apps
  10. Add this to the bottom of settings.py
  11. List item
# =================
# Stripe settings
# =================
STRIPE_COMPRESS_TO_ONE_LINE_ITEM = False
STRIPE_USE_PRICES_API = True

# Override these three.  I suggest creating a file called "settings_local.py", and adding the settings there.
# This file is .gitignore-d so this will avoid your stripe keys going into git.
STRIPE_PUBLISHABLE_KEY = "YOUR-STRIPE-PUBLISHABLE-KEY"
STRIPE_SECRET_KEY = "YOUR-STRIPE-SECRET-KEY"
STRIPE_RETURN_URL_BASE = "https://www.example.com/"

# If you don't want to use a settings_local.py, comment or remove this line.
from settings_local import *

STRIPE_PAYMENT_SUCCESS_URL = "{0}{1}".format(STRIPE_RETURN_URL_BASE, "/checkout/preview-stripe/{0}/")
STRIPE_PAYMENT_CANCEL_URL = "{0}{1}".format(STRIPE_RETURN_URL_BASE, "/checkout/stripe-payment-cancel/{0}/")
  1. Sign up to stripe and add your stripe variables to your env
Stroup answered 8/6 at 14:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.