2

I created a website with a subscription. I don't know why i don't have the good price in my 3D Secure confirmation. The confirmation display: 0$ and when you pay. You are charged successfully of 20$. Here is my controller :

public function create_checkout_session(Request $request)
{
    $this->validate($request, [
        'plan' => 'required'
    ]);

    if($request->plan !== config('app.football_price_id')) // Football
    {
        return redirect()->route('homepage');
    }

    $data = [
        'intent' => auth()->user()->createSetupIntent()
    ];

    return view('subscription.payment')->with($data);
}

Here is the view

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Payer mon abonnement</div>
                <div class="card-body">
                    <div class="text-center">
                        <img src="{{ asset('/img/secure-payment.jpg') }}" style="height: 100px;">
                    </div>
                    <form id="payment-form" action="{{ route('subscription_payments_store') }}" method="post" class="mt-4">
                        @csrf
                        <input type="hidden" name="plan" id="plan" value="{{ request('plan') }}">
                        <div class="form-group">
                            <label for="">Nom complet</label>
                            <input type="text" name="name" id="card-holder-name" class="form-control" value="" placeholder="Nom complet sur la carte">
                        </div>
                        <div class="form-group">
                            <label for="">Informations de votre carte bancaires</label>
                            <div id="card-element"></div>
                        </div>

                        <button type="submit" class="btn btn-primary w-100" id="card-button" data-secret="{{ $intent->client_secret }}">Payer</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

<script src="https://js.stripe.com/v3/"></script>
<script>
    const stripe = Stripe('{{ config('cashier.key') }}')

    const elements = stripe.elements()
    const cardElement = elements.create('card', {
        hidePostalCode: true
    })

    cardElement.mount('#card-element')

    const form = document.getElementById('payment-form')
    const cardBtn = document.getElementById('card-button')
    const cardHolderName = document.getElementById('card-holder-name')

    form.addEventListener('submit', async (e) => {
        e.preventDefault()

        cardBtn.disabled = true
        const { setupIntent, error } = await stripe.confirmCardSetup(
            cardBtn.dataset.secret, {
                payment_method: {
                    card: cardElement,
                    billing_details: {
                        name: cardHolderName.value
                    }
                }
            }
        )

        if(error) {
            cardBtn.disable = false
        } else {
            let token = document.createElement('input')

            token.setAttribute('type', 'hidden')
            token.setAttribute('name', 'token')
            token.setAttribute('value', setupIntent.payment_method)

            form.appendChild(token)
            form.submit();
        }
    })
</script>
@endsection

If someone have an idea about the problem.

config('app.football_price_id') is equal to the stripe product ID

Here is a screenshot of the 3D Secure: http://image.noelshack.com/fichiers/2021/11/6/1616246407-capture.png

Thank's to taking time to read this and maybe help me

F. Vandroy
  • 122
  • 2
  • 15

2 Answers2

0

Did you accidentally configured trial in your subscription? It would help to show your Product, Price and Subscription objects. I don't see anything out of the ordinary in your code.

Edit: I see that you're using stripe.confirmCardSetup. This is wrong and you should be using stripe.confirmCardPayment instead. The former is used to set up new card for future reuse.

Zhi Kai
  • 1,549
  • 1
  • 13
  • 31
  • I don't have anythings else in my code. I created the product directly on Stripe and i don't have trial period, the price is 20$, all is good. The only problem is that the 3D Secure show 0$ but successfully take the 20$. So it's really sure there is no trial i think. Why should i use confirmCardPayment ? – F. Vandroy Mar 20 '21 at 12:18
  • Are you trying to set up a card for future payment, or making a one-time payment? Use confirmCardSetup for the former, and confirmCardPayment for the latter. As for the value in 3 DS, it should correspond to the amount set in your PaymentIntent. – Zhi Kai Mar 20 '21 at 13:09
  • You set up your card for the subscription. If you want to change it in future, i got a customer portal using stripe – F. Vandroy Mar 20 '21 at 13:11
  • I don't use PaymentIntent only createSetupIntent – F. Vandroy Mar 20 '21 at 13:12
  • Can you attach a screenshot of the payment details and the 3DS prompt in your question? – Zhi Kai Mar 20 '21 at 13:14
  • I added a screenshot link to the main question. http://image.noelshack.com/fichiers/2021/11/6/1616246407-capture.png – F. Vandroy Mar 20 '21 at 13:17
  • Okay, assuming that the payment indeed deducted $20, you have to contact your bank regarding this. The authorisation page shown in the modal isn't controlled by Stripe. – Zhi Kai Mar 20 '21 at 13:27
  • I tested with 2 differents bank. Same problem – F. Vandroy Mar 20 '21 at 14:19
  • Any luck with this? – Robert Apr 04 '22 at 22:03
0

When you create a SetupIntent, Stripe first save the card. To do so, they make a first call to the bank, with an amount of 0. So the amount you want to collect is not used at this step, but correctly used in the next steps.

If you don't need to re-use the card, just use a PaymentIntent instead of a SetupIntent, and everything should work fine.

Mohand
  • 19
  • 3