1

I am creating a new subscription in Stripe, using Laravel 6 and Cashier 10.7, but the default card is not storing in the Stripe customer profile. The subscription is creating fine and no errors, but the card is not storing.

My payment page controller looks like this

    public function payment() {
    $user = Auth::user();

    if ($user->stripe_id == null) {
        $user->createAsStripeCustomer();
    }

    return view('auth.payment', [
        'intent'  => $user->createSetupIntent()
    ]);
}

my payment blade like this

    @extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-12 col-md-6 mt-5 mb-2">

            @if (session('status'))
                <div class="alert alert-success" role="alert">
                    {{ session('status') }}
                </div>
            @endif

            @if ($errors->any())
                <div class="alert alert-danger">
                    <strong>Whoops!</strong> There was a problem.
                    <ul>
                        @foreach ($errors->all() as $error)
                        <li>{{ $error }}</li>
                        @endforeach
                    </ul>
                </div>
            @endif

            <div class="h2 text-center">
                {{ __('Please enter your card details') }}
            </div>

            <div class="card">
                <div class="card-body">
                    <form method="post" action="{{ route('startSubscription') }}" id="payment-form">
                        @csrf

                        <div class="group">
                            <label class="stripe-label">
                                <span class="mr-1 p-2">{{ __('Cardholder Name') }}</span>
                                <input id="card-holder-name" class="field" placeholder="Jordan Jones" />
                            </label>
                        </div>

                        <!-- Stripe Elements Placeholder -->
                        <div class="group">
                          <label class="stripe-label">
                            <span class="mr-1 p-2">{{ __('Card') }}</span>
                            <div id="card-element" class="field p-3"></div>
                          </label>
                        </div>

                        <!-- Used to display form errors. -->
                        <div id="card-errors" role="alert"></div>
                        <button id="card-button" class="btn btn-lg btn-block btn-success" data-secret="{{ $intent->client_secret }}">
                            <i class="fas fa-credit-card mr-1"></i>{{ __('Add Payment Method') }}
                        </button>
                    </form>
                </div>
            </div>

        </div>
    </div>
</div>
@endsection

@section('javascript')
    <script>
        const stripe = Stripe('pk_********');
        const elements = stripe.elements();
        const cardElement = elements.create('card', {hidePostalCode: true});

        cardElement.mount('#card-element');

        const cardHolderName = document.getElementById('card-holder-name');
        const cardButton = document.getElementById('card-button');
        const clientSecret = cardButton.dataset.secret;

        // Handle form submission.
        var form = document.getElementById('payment-form');

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

           stripe.handleCardSetup(clientSecret, cardElement).then(function(result) {
               if (result.error) {
                   var errorElement = document.getElementById('card-errors');
                   errorElement.textContent = result.error.message;
               } else {
                   stripePaymentHandler(result.setupIntent);
               }
           });
        });

        // Submit the form with the token ID.
        function stripePaymentHandler(setupIntent) {
        // Insert the token ID into the form so it gets submitted to the server
        var form = document.getElementById('payment-form');
        var hiddenInput = document.createElement('input');
        hiddenInput.setAttribute('type', 'hidden');
        hiddenInput.setAttribute('name', 'stripePaymentMethod');
        hiddenInput.setAttribute('value', setupIntent.payment_method);
        form.appendChild(hiddenInput);

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

    </script>
@endsection

and my create subscription controller like this

public function subscriptionPayment(Request $request) {
    $user = Auth::user();
    $paymentMethod = $request->stripePaymentMethod;

    try {
            $newSubscription = $user->newSubscription('Author', 'plan_HGvJkewD0eaX5Y')->trialDays(60)->create($paymentMethod, ['email' => $user->email]);

    } catch ( IncompletePayment $exception ){
        return redirect()->route(
            'payment',
            [$exception->payment->id, 'redirect' => route('home')]
        );
    }

    return redirect()->route('home')
    ->with('status', 'Great! Your payment has been processed and your subscription is now active.');
}

I have tried including

if ($user->hasPaymentMethod()) {
                    $user->updateDefaultPaymentMethod($paymentMethod);
                } else {
                    $user->addPaymentMethod($paymentMethod);
                }

but this throws and error and I'm not sure I should need it anyway.

Any pointers would be great. Thanks.

Shizzen83
  • 3,325
  • 3
  • 12
  • 32
Dan E
  • 167
  • 1
  • 11
  • can you expand on what "the card is not storing." means? What are you looking at what do you see versus what you expect to see? – karllekko May 18 '20 at 12:17
  • The card details aren't attached to the customer in Stripe, or the User table locally. – Dan E May 18 '20 at 12:50
  • I've never used Lavarel, but their docs indicate it's not expected that the SetupIntent adds the card to the customer: https://laravel.com/docs/7.x/billing#storing-payment-methods and that you'd have to add it manually : https://laravel.com/docs/7.x/billing#adding-payment-methods – karllekko May 18 '20 at 14:01
  • It's a little odd because on the Stripe side, if you include the customer ID when creating the SetupIntent, the resulting card gets automatically added to the customer(https://stripe.com/docs/api/setup_intents/create#create_setup_intent-customer) but I think Lavarel's implementation was written before that was the case and doesn't pass the ID, so you'd add the card manually. – karllekko May 18 '20 at 14:03

0 Answers0