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.