2

I am using stripe to add the Payment request button(Apple, Google, Pay Now) by following the documentation https://stripe.com/docs/stripe-js/elements/payment-request-button which is working fine but I need to add the shipping address and when I add

requestShipping: true,

It shows up the shipping address dialogue but keeps processing... and never complete the payment but if I remove

requestShipping: true,

Then works fine

enter image description here

Here is my full source code

JS Code

<script src="https://js.stripe.com/v3/"></script>
{{-- //stripe pay button --}}
<script type="text/javascript">

    var clientSecret = "{{ $payment_intent_client_secret }}";
    var total_amount = parseFloat({
    {
        $total
    }
});

var stripe = Stripe("{{ env('STRIPE_KEY') }}", {
    apiVersion: "2020-08-27",
});

var paymentRequest = stripe.paymentRequest({
    country: 'US',
    currency: 'usd',
    total: {
        label: 'Total',
        amount: total_amount,
    },
    requestPayerName: true,
    requestPayerEmail: true,
    requestShipping: true,
});

var elements = stripe.elements();
var prButton = elements.create('paymentRequestButton', {
    paymentRequest: paymentRequest,
});

// Check the availability of the Payment Request API first.
paymentRequest.canMakePayment().then(function(result) {
    if (result) {
        prButton.mount('#payment-request-button');
    } else {
        // document.getElementById('payment-request-button').style.display = 'none';
    }
});

paymentRequest.on('paymentmethod', function(ev) {
    // Confirm the PaymentIntent without handling potential next actions (yet).
    stripe.confirmCardPayment(
        clientSecret, {
            payment_method: ev.paymentMethod.id
        }, {
            handleActions: false
        }
    ).then(function(confirmResult) {

        if (confirmResult.error) {
            ev.complete('fail');
        } else {

            // Report to the browser that the confirmation was successful
            ev.complete('success');

            if (confirmResult.paymentIntent.status === "requires_action") {

                stripe.confirmCardPayment(clientSecret).then(function(result) {

                    if (result.error) {
                        alert('payment failed, try again');

                    } else {
                        // The payment has succeeded.
                        window.location.href = "{{ route('checkout.thankyou') }}";
                    }
                });
            } else {
                // The payment has succeeded.
                window.location.href = "{{ route('checkout.thankyou') }}";
            }
        }
    });

});


//shippingaddresschange event
paymentRequest.on('shippingaddresschange', function(ev) {
  if (ev.shippingAddress.country !== 'US') {
    ev.updateWith({status: 'invalid_shipping_address'});
  } else {
    // Perform server-side request to fetch shipping options
    fetch('/calculateShipping', {
      data: JSON.stringify({
        shippingAddress: ev.shippingAddress
      })
    }).then(function(response) {
      return response.json();
    }).then(function(result) {
      ev.updateWith({
        status: 'success',
        shippingOptions: result.supportedShippingOptions,
      });
    });
  }
});

</script>

PHP Code which Return clientSecret

\Stripe\Stripe::setApiKey(env('STRIPE_SECRET'));
$payment_intent = \Stripe\PaymentIntent::create([
  'amount' => 1 * 100,
  'currency' => 'usd'
]);
$payment_intent_client_secret=$payment_intent->client_secret;


  

shipping address code

 //shipping address sample
 $data=['shippingAddress'=>'shipping address here'];
 return json_encode($data);

Thanks for helping.

2 Answers2

1

You are fetching calculateShipping from your backend and expecting supportedShippingOptions in its response. However you only return a simple hashmap: ['shippingAddress'=>'shipping address here'].

    fetch('/calculateShipping', {
      data: JSON.stringify({
        shippingAddress: ev.shippingAddress
      })
    }).then(function(response) {
      return response.json();
    }).then(function(result) {
      ev.updateWith({
        status: 'success',
        shippingOptions: result.supportedShippingOptions,
      })
    //shipping address sample
    $data=['shippingAddress'=>'shipping address here'];
    return json_encode($data);

It's most likely your js is errored processing this response. But the best way to diagnose is confirm on browser console.

orakaro
  • 1,468
  • 1
  • 9
  • 9
0

For other people running into this issue, to request shipping, you will also have to add shippingOptions to your payment request:

const paymentRequest = stripe.paymentRequest({
    country: "US",
    currency: "usd",
    total: { label, amount },
    requestPayerName: true,
    requestPayerEmail: true,
    requestShipping: true,
    shippingOptions: [
        {
            id: "free-shipping",
            label: "Free shipping",
            detail: "Some details",
            amount: 0,
        },
    ],
});
Johnny Kontrolletti
  • 727
  • 1
  • 10
  • 22