Developer forum

Forum » Ecommerce - Standard features » Stripe CheckoutHandler Integration

Stripe CheckoutHandler Integration

Joseph Vause
Reply

Hi,

I am currently trying to implement stripe as an inline payment option for our client, we are working on DynamicWeb 10.4.1.

I have followed the instructions given here: https://doc.dynamicweb.com/forum/dynamicweb-10/dynamicweb-10/post-error-template-from-payment-provider 
to allow me to select the Post and Error templates and have their counterparts created in the Design section of the Assets View.

I have configured stripe to use Test Mode and also set it to inline mode. 

I have added the tag to my PaymentUser.cshtml template like this:

<div class="grid gap-0 h-100">
    <div class="cart g-col-12 g-col-lg-8 p-3 p-lg-4 pe-xl-5 ps-xl-6 ps-xxl-8 order-last order-lg-first@(theme)">
        <form name="ordersubmit" id="ordersubmit" method="post" autocomplete="off" style="max-width: 65rem; margin-left: auto;">
 
            @Include("Helpers/Logo.cshtml")
 
            @Include("Helpers/StepsBreadcrumbs.cshtml")
 
            @Include("Helpers/Errors.cshtml")
 
            @Include("Shared/Helpers/StepSummary_v2.cshtml")
 
            <div class="mt-4">
 
                <h3 class="fs-6 fw-normal mb-0">@Translate("Select payment")</h3>
                <p class="fs-8 mb-3">@Translate("All transactions are encrypted")</p>

 

<!-- Render the Stripe Post Template -->
              @GetString("Ecom:Cart.PaymentInlineForm")
 
            </div>
 
            @Include("Helpers/OrderReference.cshtml")
 
            @Include("Helpers/OrderComment.cshtml")
 
            @Include("Helpers/StepsNavigation.cshtml")
 
            <input type="hidden" id="CurrentStep">
        </form>
    </div>
 
    @Include("Helpers/SummarySidebar.cshtml")
 
</div>
 
<script>
    function submitForm() {
        document.querySelector("#CurrentStep").name = "@GetString("CartV2.CurrentStepButtonName")";
        swift.PageUpdater.Update(document.querySelector("#ordersubmit"));
    }
</script>

This correctly renders the card element input when Stripe is the chosen payment method.

The next step here is understanding what should be in the post template that is being rendered. The documentation around this for both DW9 and DW10 mentions nothing more than that they need to be selected, but gives no help on how to wire up the templates or what should be inside them. This would be a huge help for myself and the next person that attempts this.

I have attempted to implement the post template from the information i have gained from my previous knowledge of implementing Stripe manually on different websites and what the StripeCheckoutHandler code is doing along with the documentation from Stripe, but i am still missing what i hope, is the final piece of the puzzle.

When i have implemented Stripe in the past for other clients, you would ordinarily create a 'PaymentElement' object (see: https://docs.stripe.com/payments/quickstart), and then do a call to the server to get a ClientSecret from the Stripe .NET Library by creating a paymentIntent. From looking at the checkout handler, this does not appear to be supported, and instead you are stuck using the older 'Card' element, which instead, will generate a token on form submission that you then post back to the CheckoutHandler as a hidden form field, this in turn will then create the PaymentIntent internally and handle it all server-side. The other issue with this, is that Stripe no longer advocate using it, so they do not provide documenation on setting this up anymore. This is the only reference they provide to the card element that i can find: https://docs.stripe.com/js/element/other_element

I have attempted to set this up anyway, but i am at a loss on how to correctly post this back to the checkout handler as i currently just get redirected back to the start of the checkout flow on form submission after filling out the card details. 

Here is my current Post Template, which uses a Stripe Card element:

@inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>>
 
    <script src="https://js.stripe.com/v3/"></script>
 
<h2>Card</h2>
 
    <div id="card-element">
        <!-- Stripe card element will be inserted here. -->
    </div>


 
<script type="text/javascript">
        const stripe = Stripe('@GetString("Stripe.publishablekey")');
       
const options = {
  hidePostalCode: true,
 disableLink: true
};
    let elements = stripe.elements();
        // Setting up Stripe's Card Element
        let card = elements.create("card", options);
        card.mount('#card-element');
       
 
        let form = document.getElementById('ordersubmit');
        form.addEventListener('submit', function(event) {
        event.preventDefault();
       
        // Creates a token
        stripe.createToken(card).then(function(result) {
            if (result.error) {
                // Inform the user if there was an error
                let errorElement = document.getElementById('card-errors');
                errorElement.textContent = result.error.message;
            } else {
                // Send the created token to your server
                stripeTokenHandler(result.token);
            }
        });
    });
 
    function stripeTokenHandler(token) {
        // Insert the token ID into the form so it gets submitted to the server
        let form = document.getElementById('ordersubmit');
        let hiddenInput = document.createElement('input');
        hiddenInput.setAttribute('type', 'hidden');
        hiddenInput.setAttribute('name', 'stripeToken');
        hiddenInput.setAttribute('value', token.id);
        form.appendChild(hiddenInput);
 
        // A Guess from looking at the StripeCheckoutHandler code that it expects a hidden element with the name 'action' and a value of 'Approve' to be sent in the form submission
        let actionInput = document.createElement('input');
        actionInput.setAttribute('type', 'hidden');
        actionInput.setAttribute('name', 'action');
        actionInput.setAttribute('value', 'Approve');
        form.appendChild(actionInput);
 
        // A Guess from looking at the StripeCheckoutHandler code that it expects a hidden element with the name 'OrderIdRequestName' and a value of <Current Order Id> to be sent in the form submission
        let orderIdInput = document.createElement('input');
        orderIdInput.setAttribute('type', 'hidden');
        orderIdInput.setAttribute('name', 'OrderIdRequestName');
        orderIdInput.setAttribute('value', '@GetString("Ecom:Order.ID")');
        form.appendChild(orderIdInput);
       
       
        // Submit the form
        form.submit();
    }
       
    </script>  

My Understanding, from looking at the StripeCheckoutHandler code, is that i want to hit a method to process the token and do the work server-side,
which i then expect will return back to the front end with a status of Authorised, Declined or Requires_attention etc.
 
In the event i get an Authorised result i want to convert the cart to an order and redirect to the Receipt Step
In the event i get a Declined result i want to render the Error Template with the stripe error message
In the event i get a Requires_Attention result i want to initiate the 3DS2 Challenge flow to enable them to confirm payment on their mobile banking app.
 
This is the method in the checkoutHandler, that i think i need to hit:
 
/// <summary>
        /// <para>Function that is called from CartV2 when OrderIdRequestName is in the Request.</para>
        /// <para>Implement this method to receive redirects from CartV2</para>
        /// </summary>
        /// <param name="order">The order with order ID equal to the request OrderIdRequestName</param>
        /// <returns>Returns the output to the module.</returns>
        /// <remarks>
        /// <para>The most common use of this method is to receive callbacks and redirect urls from a gateway.</para>
        /// <para>
        /// To enable the Redirect method to be called on a callback parse an url with the current page id and the order id
        /// in the query string to the gateway as the
        /// callback url. The order id must be stored in a query string variable named with the return value of the
        /// property OrderIdRequestName of the CheckoutHandler base
        /// class.
        /// </para>
        /// <para></para>
        /// <para>
        /// Return a <see cref="T:Dynamicweb.Frontend.OutputResult" /> to control the flow of checkout, be that content or redirection.
        /// </para>
        /// </remarks>
        public virtual OutputResult HandleRequest(Order order)
        {
//...
        }
 
 
Would anyone be able to give me some guidance on what it is that i am missing to enable me to accept a payment using Stripe, as i have spent quite alot of time
already on this and have no more ideas on what to do next.
 
Also, once i get this working, i have a requirement to also implement Google/Apple Pay and Paypal through stripe as seperate payment methods
(other instances of the StripeCheckoutHandler with different Post Templates is my current thinking),
However, Wallets and Paypal do not appear to be supported with a Card element according to: https://docs.stripe.com/payments/payment-card-element-comparison
 
Can someone confirm if this is the case, or if i need to use a different element such as the 'paymentRequestButton'?
 
Finally, as this site is in the UK, it will be mandatory to enable 3ds2 security on any transactions, which i am also not so certain is possible with
the current code in the StripeCheckoutHandler. This would be good to know now, so if i have to write my own handler i can start than sooner rather than later, although its really not
and ideal scenario.
 
Any help would really be appeciated!
 
Kind Regards,
 
Joe

Replies

 
Stanislav Smetanin Dynamicweb Employee
Stanislav Smetanin
Reply
This post has been marked as an answer

Hi Joseph,

Looks like your main problem is that you don't have our templates for some reason.

With Stripe 10.3.0 you should have the templates after restarting your site, but you probably need to create the folders for these File paths:

 "/Files/Templates/eCom7/CheckoutHandler/Stripe/Error/checkouthandler_error.html"
 "/Files/Templates/eCom7/CheckoutHandler/Stripe/Post/Post_custom.html"
 "/Files/Templates/eCom7/CheckoutHandler/Stripe/Post/Post_simple.html"

I also added these templates to attachments of this message.

For inline mode please use Post_simple.html template. For payment without inline mode, use Post_custom.html.

See the video: https://www.screencast.com/t/DRxx2JfF3

There is bug which our QA have found, that some times the Cart is not transformed to Order for inline mode of Stripe provider, but it will be fixed ASAP: https://dev.azure.com/dynamicwebsoftware/Dynamicweb/_workitems/edit/20374

Next part, is that our Stripe provider supports only cards for current moment. Sorry about that, but this is all what we have right now, probably we will implement supporting for other payment methods in the future.

----------

About how all of this works. We don't use Stripe .NET Library, we use our own code.

We get the stripeToken, stripeEmail from the stripe js-form, and then create the PaymentIntent based on them.

For saved cards, we use SetupIntent to save payment method information, and then use PaymentIntent to process a payment.

-------

About 3ds security. You mean cards like this, right? https://docs.stripe.com/testing#authentication-and-setup

We support redirection, so if you need to pass through security checks, you will be redirected to the needed page, then redirected back to provider, which then does payment operation. You don't need to implement anything manually for this, it works "from the box". You can see it in the video: https://app.screencast.com/7YDrOhZI4Zf3S

If you have some other questions about how provider works, we could discuss it, but if you have an access to our code (I assume you have, based on your message), then you probably need to say what you don't understand, and I will help you. As I said before, right now we support only part of Stripe options, but if something is needed, we could consider adding it to our provider in the future. But this is not something I can decide on my own :) Please ask our PMs to add a task to implement a feature, if needed.

Kind regards.

Votes for this answer: 1
 
Joseph Vause
Reply

Hi Stanislav,

Thanks for the prompt reply!

I have just tested out the templates provided and they work perfectly, thanks so much for guiding me to these as i would have struggled to get this working otherwise. 

It may be worth adding these templates you have attached to the documentation as this would have saved alot of time, It doesn't say in the docs that these should already exist or where to get them if like me, they are not installed when adding the StripeCheckoutHandler App automatically.

https://doc.dynamicweb.com/documentation-9/ecommerce/payment/stripe-checkout

https://doc.dynamicweb.dev/documentation/implementing/ssr/commerce/payment-providers/Stripe.html?q=Stripe

Being able to make a payment is enough for now, with regards to using wallet providers and PayPal i will have to come up with an alternative solution. 

Have a great day!

Kind Regards,

Joe

 

You must be logged in to post in the forum