Username
Username

Reputation: 3663

InvalidRequestError: This customer has no attached payment source

I've been following the Quickstart guides from Stripe.

https://stripe.com/docs/quickstart

https://stripe.com/docs/subscriptions/quickstart

This is what my form looks like:

<form id="register-form" method="post">
    {% csrf_token %}
    {% for field in registration_form %}
        <p>{{ field }}</p>
        {% if field.errors %}
            <p class="text-danger">{{ field.errors.as_text|cut:"* "|escape }}</p>
        {% endif %} 
    {% endfor %}
    {% if registration_form.non_field_errors %}
        <p class="text-danger">{{ registration_form.non_field_errors.as_text|cut:"* "|escape }}</p>
    {% endif %}
    <div id="stripe-wrapper">
        <p id="card-element"></p>
    </div>                  
    <p id="card-errors" role="alert"></p>
    <button id="register-btn" class="btn btn-primary" type="submit">Register</button>

    <script type="text/javascript">
        var displayError=   document.getElementById('card-errors');
        var stripe=         Stripe("pk_test_BjhejGz5DZNcSHUVaqoipMtF");
        var elements=       stripe.elements();

        var style=      {
            base: {
                fontSize: "1.1875rem",
                fontSmoothing: "always",
                fontWeight: "600"
            }
        };

        var card=   elements.create("card",{style:style});
        card.mount("#card-element");
        card.addEventListener('change', function(event) {

            if (event.error) {
                displayError.textContent = event.error.message;
            } else {
                displayError.textContent = '';
            }
        });

        var formID= "register-form";
        var form=   document.getElementById(formID);
        form.addEventListener("submit",function(event){
            event.preventDefault();

            stripe.createToken(card).then(function(result){
                if(result.error) {
                    displayError.textContent=   result.error.message;
                } else {
                    stripeTokenHandler(result.token, formID);
                }                               
            })
        });
        // tut https://stripe.com/docs/stripe-js/elements/quickstart#create-form
        function stripeTokenHandler(token, formID) {
            // Insert the token ID into the form so it gets submitted to the server
            var form = document.getElementById(formID);
            var hiddenInput = document.createElement('input');
            hiddenInput.setAttribute('type', 'hidden');
            hiddenInput.setAttribute('name', 'stripeToken');
            hiddenInput.setAttribute('value', token.id);
            form.appendChild(hiddenInput);
            // Submit the form
            form.submit();
        }
    </script>
</form>

Then my views.py has this:

if registration_form.is_valid():
    stripe.api_key= "sk_test_8rdFokhVsbsJJysHeKgyrMTc"
    stripeCustomer= stripe.Customer.create(
        email=request.POST["username"],
    )
    subscription=   stripe.Subscription.create(
        customer=stripeCustomer["id"],
        items=[{"plan":"plan_CLFfBrRAKl7TRt"}],
    )

This gives me an error:

Internal Server Error: /login-register/
Traceback (most recent call last):
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 42, in inner
    response = get_response(request)
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
    response = self._get_response(request)
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 178, in _get_response
    response = middleware_method(request, callback, callback_args, callback_kwargs)
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/mezzanine/pages/middleware.py", line 98, in process_view
    return view_func(request, *view_args, **view_kwargs)
  File "/home/myUserName/myDjangoProjectWithStripe/product_blog/theme/views.py", line 154, in login_register
    items=[{"plan":"plan_CLFfBrRAKl7TRt"}],
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/stripe/api_resources/subscription.py", line 33, in create
    return super(Subscription, cls).create(**params)
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/stripe/api_resources/abstract/createable_api_resource.py", line 17, in create
    response, api_key = requestor.request('post', url, params, headers)
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/stripe/api_requestor.py", line 153, in request
    resp = self.interpret_response(rbody, rcode, rheaders)
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/stripe/api_requestor.py", line 365, in interpret_response
    self.handle_error_response(rbody, rcode, resp.data, rheaders)
  File "/home/myUserName/myDjangoProjectWithStripe/local/lib/python2.7/site-packages/stripe/api_requestor.py", line 178, in handle_error_response
    raise err
InvalidRequestError: Request req_o39ceLlhtpJmmr: This customer has no attached payment source

How do I attach a payment source to the customer? Since I'm testing, I use the testing credit card, which has the number 4242 4242 4242 4242.

Upvotes: 7

Views: 17281

Answers (2)

Matthew Arkin
Matthew Arkin

Reputation: 4658

The error means what it says, the customer doesn't have an attached payment method/source. You are adding a stripeToken to your html form, but you aren't doing anything with it server side. You need to add the token to your customer (set source to the token when creating the customer) and then you'll be able to charge the customer, create subscriptions, etc.

Upvotes: 9

Rasovica
Rasovica

Reputation: 229

You need to add payment form to your registration, Assuming you have a /payment-form route, in your views.py add the following:

from yourapp import settings

def payment_form(request):
    context = { "stripe_key": settings.STRIPE_PUBLIC_KEY }
    return render(request, "yourtemplate.html", context)

In your template, copy and paste the form found under the checkout section of the stripe docs.

<form action="/checkout" method="POST">
<script src="https://checkout.stripe.com/checkout.js" class="stripe-button"
    data-key="stripe_key" # Make sure to wrap the variable name with double {}
    data-amount="2000"
    data-name="Your APp"
    data-description="Your Product"
    data-image="Link to your logo"
    data-currency="usd">
</script>
</form>

Notice we passed the stripe public_key to the data-key attribute, by default, it will be populated with your actual public key, but I just find it better to use the variable instead.

We also set the action attribute of the form to /checkout which we’ll create in the next step. This route will process the checkout logic.

What’s actually happening is this: When a user submits the form (ie: pays), their bank account information is sent to stripe for processing. If the payment is accepted, stripe will issue a POST request to the endpoint specified in the action attribute of the form. The idea is to then capture that token and use it to charge the user’s card.

Upvotes: -1

Related Questions