Taking a Stripe Payment Using SCA Compatible Stripe Payment Intents and Elements - Part 2

[THIS DOCUMENT IS WORK IN PROGRESS OVER THE NEXT FEW DAYS! :slight_smile: ]

Okay, we are are assuming here that you have followed part 1 of this tutorial - if not, then please follow the link at the end of this document and do that first.

On Error

Once you have mastered creating the Payment Intent and using it’s client_secret to complete a payment, you need to add more features to determine what to do upon success or failure of the payment request.

So you will recall the javascript code we had which is executed when the user hits [Pay Now]

// ===================== Pay Now Form Submission ===============================

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

form.addEventListener('submit', function (ev) {
    ev.preventDefault();
    stripe.confirmCardPayment(clientSecret, {   
        payment_method: {
            card: card,
            billing_details: {
                name: 'Jenny Rosen'
            }
        }
    }).then(function (result) {
        if (result.error) {
            // Show error to your customer (e.g., insufficient funds)
            console.log(result.error.message);
        } else {
            // The payment has been processed!
            if (result.paymentIntent.status === 'succeeded') {
                // Show a success message to your customer
                // There's a risk of the customer closing the window before callback
                // execution. Set up a webhook or plugin to listen for the
                // payment_intent.succeeded event that handles any business critical
                // post-payment actions.
            }
        }
    });
});

So we now need to add some code in these areas which the comments indicate are where the excution goes if the payment has errors, or succeeds.

The first thing to understand is that you can use the dmx.parse() function to execute Wappler functionality as well as return values. So for example, if you have a variable in your design called stripe_error_message, then you could assign a value to that with the javascript line:

dmx.parse("stripe_error_message.setValue('We have an error!');");

Things can get a bit challenging with all the quotes here! So we have to use double quotes around the entire value being passed to dmx.parse(), as it is a string. But then we also need to pass a string value within the .setValue(), so we use single quotes for that.

If you define such a variable, you can then use it to display an error message in your design, by putting a <p> tag just above the [Pay now] button and making its inner text equal to the value of the variable:

<p class="text_error" dmx-text="stripe_error_message.value"></p>

So our assignment to this variable in the javascript will now appear as a message in our design.

This example is a bit simple though, as it did not pass through the actual error message. This gets a bit more hair-raising with all the quotes and the javascript concatentation. The basic form is this:

dmx.parse('start_of_your_set_value' + result.error.message + 'end_of_your_set_value');

where the 'start_of_your_set_value' may be of the form:

'stripe_error_message.setValue("Sorry, there was an error processing your card payment: '

and the 'end_of_your_set_value' may be of the form:

' Please try again!");'

So putting it all together, you may end up with something like this:

dmx.parse('stripe_error_message.setValue("Sorry, there was an error processing your card payment: ' + result.error.message + ' Please try again!");'); 

Good luck with the quotes!

The other thing I found useful at this time was to remove this section of code from the stripe.js file and place it at the bottom of my html/php file, as I was guaranteed it would re-load each time I refreshed the page.

On Success

There are a variety of things you may want to do on success. My card payment is within a self contained booking form, so I want to show a modal indicating the payment has been successful, and when that modal is closed, I want to refresh the page.

Hence I can just put a dmx.parse() statement to show the modal within the success part of the javascript:

if (result.paymentIntent.status === 'succeeded')  {
  dmx.parse("m_payment_success.show();");
}

You will have your own design requirements you can place here!

Testing Different Scenarios

Here is a list of the test cards you can use to check out how your design handles different scenarios:

Card Works - USA        4242424242424242
UK Visa                 4000008260000000
Requires Authentication 4000002500003155
Stolen Card             4000000000009979
Insufficient Funds      4000000000009995
Processing Error        4000000000000119
Incorrect CVC           4000000000000127
Expired card            4000000000000069
Lost Card               4000000000009987
Card declined           4000000000000002
High Risk, blocked      4100000000000019
High Risk               4000000000004954
Elevated Risk           4000000000009235
CVC check fails         4000000000000101
Zip check unavailable   4000000000000044
Zip check fails         4000000000000010

Debouncing The Pay Now Button

(Details to follow…)

Window Closure During Payment

(Details to Follow)

Postal Codes

If you have used the 4242 4242 4242 4242 card number so far to check on success, you may have noticed that you are not able to enter a postal code other than in the five number USA format. Stripe will allow different postal codes depending on the origin of the card, and that 4242... card is considered to be based in the US. There are other test cards based on other countries… so for example, the test card 1234 is based in the UK.
The link below has more details…

https://stripe.com/docs/js/element/postal_code_formatting

==========================================
Link to Part 1 of this tutorial:

4 Likes

Bringing The Public Key From The Database

In the example code of Part 1 of this tutorial, the public key (beginning ‘pk_test’ or ‘pk_live’) was embedded into the javascript which we put into the file stripe.js.

It is quite possible you will want to bring that key from the database for different situations (test versus live mode) or different users if each of your users works with their own Stripe account.

Here is how to do this…

Step 1 - Update stripe.js

We now need to have some of the javscript actions taken when the public key is known, rather than on page load.

Here are the key lines from our stripe.js file (defined in part 1) that we will need to change:

// Set the 'stripe' variable based on the public key
var stripe = Stripe('pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');

// Create an instance of Elements.
var elements = stripe.elements();

// Create an instance of the card Element.
var card = elements.create('card', { style: style });

// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');

These four actions now need to take place within a function which we call from our app when the value of the public key (pk_test_xxxxx) is known.

For this to function correctly in jsvascript, we need to define the variables outside of the function, (e.g. directly within stripe.js), and then assign them within the function call. So our replacement code looks like this:

// Declare stripe, elements, card - replacements for previous variable declarations
var stripe;
var elements;
var card;

// Remove the card.mount line as card is not yet defined
// card.mount('#card-element');

// Additional function call to set stripe variables when public key is known
function set_stripe_pk(pk_key) {
    stripe = Stripe(pk_key);
    elements = stripe.elements();
    card = elements.create('card', { style: style });
    card.mount('#card-element');
}

Step 2 - Call The Function From Your App

So the second step is to call this set_stripe_pk function from within your app when the value of the public key is known. You will have your own logic to know that moment, and you can define a flow in Wappler to call this set_stripe_pk javascript function.

The code for this is below!