Search code examples
javascriptphplaravelstripe-paymentslaravel-cashier

Laravel Cashier - "This customer has no attached payment source or default payment method."


I'm using Laravel 5.8 version and Cashier version 10.7.1

I want to start and charge the user subscription monthly fee when they registered.

So I write into RegisterController.php

public function register(Request $request)
    {
        $this->validator($request->all())->validate();


        DB::beginTransaction();

        event(new Registered($user = $this->create($request->all())));
        
        try {
            $newSubscription = $user->newSubscription('Standard Plan', 'price_1HJmedAuGtYRVrPxN9PNSPKi')->create($request->payment_method, ['email' => $user->email]);
        } catch ( IncompletePayment $exception ){
            DB::rollback();
            return redirect()->back()->with(['error_message' => $exception->getMessage()]);
        }

        DB::commit();

        $this->guard()->login($user);

        return $this->registered($request, $user)
                        ?: redirect($this->redirectPath());
    }

also I add into register.blade.php file:

<div class="flex flex-wrap mb-6">
                            <label for="card-element" class="block text-gray-700 text-sm font-bold mb-2">
                                Credit Card Info
                            </label>
                            <div id="card-element" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"></div>
                            <div id="card-errors" class="text-red-400 text-bold mt-2 text-sm font-medium"></div>
                        </div>

and:

<script src="https://js.stripe.com/v3/"></script>

    <script>
        const stripe = Stripe('pk_test_somekeysomekeyasdasd');
        console.log(stripe);
        const elements = stripe.elements();
        const cardElement = elements.create('card');
        cardElement.mount('#card-element');
        const cardHolderName = document.getElementById('name');
        const cardButton = document.getElementById('card-button');
        const clientSecret = cardButton.dataset.secret;
        let validCard = false;
        const cardError = document.getElementById('card-errors');
        cardElement.addEventListener('change', function(event) {
            
            if (event.error) {
                validCard = false;
                cardError.textContent = event.error.message;
            } else {
                validCard = true;
                cardError.textContent = '';
            }
        });
        var form = document.getElementById('signup-form');
        form.addEventListener('submit', async (e) => {
            event.preventDefault();
            const { paymentMethod, error } = await stripe.createPaymentMethod(
                'card', cardElement, {
                    billing_details: { name: cardHolderName.value }
                }
            );
            if (error) {
                // Display "error.message" to the user...
                console.log(error);
            } else {
                // The card has been verified successfully...
                var hiddenInput = document.createElement('input');
                hiddenInput.setAttribute('type', 'hidden');
                hiddenInput.setAttribute('name', 'payment_method');
                hiddenInput.setAttribute('value', paymentMethod.id);
                form.appendChild(hiddenInput);
                // Submit the form
                form.submit();
            }
        });
    
    </script>

When I try to register new user and make a test charge using CC details 4242 4242 4242 4242 I got error:

Stripe \ Exception \ InvalidRequestException This customer has no attached payment source or default payment method.

What is the problem? How I can fix it?


Solution

  • After you've created the Payment Method, you need to attach it to a Customer:

    $stripe->paymentMethods->attach(
      'pm_123',
      ['customer' => 'cus_abc']
    );