0
votes

Using Django 1.9 & Stripe 1.35.0. I'm trying out Stripe in a project (stripe.js, NOT 'checkout'), however Stripe won't return a token. I've checked my STRIPE_SECRET_KEY & STRIPE_PUBLISHABLE_KEY to make sure they match. I've basically copied the HTML from the Stripe website directly along with the relevant javascript (https://stripe.com/docs/custom-form).

In my view when I use request.POST['stripeToken'] I get a MultiValueDictKeyError "stripeToken". If I use request.POST.get('stripeToken') I get the error InvalidRequestError at /orders/checkout Request req_8ecvcXQcwmM1lk: Must provide source or customer. In other words, it's not providing the token to create the customer (or Charge).

Obviously I'm doing something wrong, however I can't find it. I've looked at what examples I can find (most are several yrs old) and the docs. Any help is appreciated. .Thanks.

#views.checkout
def checkout(request):
    publishable_key = settings.STRIPE_PUBLISHABLE_KEY
    if request.method == "POST":
        stripe.api_key = settings.STRIPE_SECRET_KEY
        token = request.POST.get('stripeToken')
        #token = request.POST['stripeToken']
        print token
        customer = stripe.Customer.create(description='test', source=token)
        print customer
        stripe.Charge.create(amount=500, currency='usd', source=token, description='test')

        return redirect('orders:thanks.html')        
    context = {'publishable_key': publishable_key}
    return render(request, 'orders/checkout.html', context)


#checkout.html
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">

    Stripe.setPublishableKey('{{ publishable_key }}');
function stripeResponseHandler(status, response) {
  // Grab the form:
  var $form = $('#payment-form');

  if (response.error) { // Problem!

// Show the errors on the form:
$form.find('.payment-errors').text(response.error.message);
$form.find('.submit').prop('disabled', false); // Re-enable submission

  } else { // Token was created!

    // Get the token ID:
    var token = response.id;

    // Insert the token ID into the form so it gets submitted to the server:
    $form.append($('<input type="hidden" name="stripeToken">').val(token));

    // Submit the form:
    $form.get(0).submit();
  }
};

    $(function() {
  var $form = $('#payment-form');
  $form.submit(function(event) {
    // Disable the submit button to prevent repeated clicks:
    $form.find('.submit').prop('disabled', true);

    // Request a token from Stripe:
    Stripe.card.createToken($form, stripeResponseHandler);

    // Prevent the form from being submitted:
    return false;
  });
});


</script>

{% endblock %}

 {% block content %}
<h3 class="text-center">Credit Card Payment</h3>
<div class="container">
<div class="row">
    <form method="post" action="." id="checkout-form">
        {% csrf_token %}


        <div class="form-group">
          <label class="control-label" for="card">Card</label>
          <div class="controls">
              <input type="text" id="card" class="form-control"      data-stripe="number" />
          </div>
        </div>
        <div class="form-group">
            <label class="control-label" for="">Expiration (MM/YYYY)</label>
            <div class="row">
                <div class="col-xs-2">
                    <input type="text" size="2" data-stripe="exp-month"     class="form-control" />
                </div>
                <div class="col-xs-2">
                    <input type="text" size="4" data-stripe="exp-year"     class="form-control" />
               </div>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label" for="cvc">CVC</label>
            <div class="controls">
                <input type="text" id="cvc" size="4" class="form-control" data-stripe="cvc" />
            </div>
        </div>
        <div class="form-group">
            <div class="controls">
                <input type="submit" value="Checkout" class="btn  btn-primary" />
            </div>
        </div>
    </form>
</div>
</div>

{% endblock %}


And in settings.py
    # Stripe Settings:
    STRIPE_SECRET_KEY = 'sk_test_XVDF17ppRvcOciF1xjQryhDX'
    STRIPE_PUBLISHABLE_KEY = 'pk_test_RQjZcRmXjpVHfZv5x4KlI6wT'
1
Your JS code looks for #payment-form, but your HTML form has id="checkout-form". - Daniel Roseman
Thanks Daniel, I had forgotten to change that back. However, it doesn't correct the problem. Still no token. - Chris Kavanagh
Can you put in some debugging or breakpoints? For example, is your submit function being called? Is the responseHandler called? Which branch of the if block does it go into? Does it create the stripeToken input? - Daniel Roseman
Here's some screen shots. I'm not sure how else to do it. . .pasteboard.co/1Ktu8ukk.png - Chris Kavanagh
Hang on, getting the rest. - Chris Kavanagh

1 Answers

0
votes

You need to pass the Customer id to the Charge endpoint, instead of the stripeToken:

    customer = stripe.Customer.create(description='test', source=token)
    stripe.Charge.create(customer=customer.id, amount=500, currency='usd', description='test')

More here: Saving credit card details for later

Also, you should use Ajax or a better method than this to send the stripeToken to your application:

// Get the token ID:
var token = response.id;

// Insert the token ID into the form so it gets submitted to the server:
$form.append($('<input type="hidden" name="stripeToken">').val(token));

// Submit the form:
$form.get(0).submit();

This will send all CC informations to your server. You should something like:

// Get the token ID:
var token = response.id;

$.ajax({
    url: '/api/charge-customer',
    type: 'POST',
    data: {stripeToken: token},
    success: function (data) {
        Alert("You have been charged.");
    },
    error: function (data) {
        Alert("Server Error.");
    }
});