Add a New Module to the Checkout with the Extensibility API

Understanding the Checkout Wizard

If you want to make changes to your checkout, it’s good to try and figure out if it can be achieved through configuration (including the web site setup tool) and theming, as these will be the easiest and safest ways to make changes.

A screenshot of the NetSuite application, showing the configuration record page for an example site. Specifically, the Checkout tab is in focus.

The Wizard

In SC the majority of the modules associated with this begin with OrderWizard.
Within this wizard, we have three distinct containers to help organize the fields of the checkout:

  1. Step groups — in sum, all of the groups form the whole of the checkout, but individually they might be the shipping address form, payment form, or order review
  2. Steps — each group has at least step, but maybe more
  3. Modules — individual blocks of functionality that do specific things
An illustration breaking down the components of the Shipping Address Step Group. First you have two steps: Choose Existing Address Step and Add New Address Step. Next, each step is broken down into their many constituent modules.

I’ve mocked up the step group in the image above. The outer blue area envelopes everything and refers to the shipping address step group. Within that are the two individual steps highlighted in orange, showing the two possible steps the shopper could interact with. Finally, within each of those, are the individual modules that compose the steps, in white.

The Flow

One configurable setting is how the checkout flows. In terms of what we just talked about, this means changing what groups and steps are presented and in what order. By default, SuiteCommerce includes three flows:

  1. Standard
  2. Billing first
  3. One page checkout (OPC)

The Checkout Component

let’s take a look at the tools available to us via the extensibility API. As a reminder, we use JSDoc to generate documentation for the API

In particular, we have some very useful methods for logging steps and groups, including the currently active one.
Of particular interest for getting started are:

  • getStepsInfo()
  • getStepGroupsInfo()
  • getCurrentStep()

The first two each return an array of objects, detailing, in order, what the steps or groups are. The third essentially plucks the step info for the current step and returns that specifically. For example, if I run getCurrentStep() on the first page in my site’s checkout, I get this:

A screenshot of a browser's developer console, where the current checkout step has been logged to the console. The modules object has been expanded to show all the different modules active for the current step.

Let’s run through the values quickly:

  • modules — an array of objects, where each object is a module that has loaded into the current step
  • name — a descriptive name of the current step (sometimes it’s not set)
  • show_step — if the step will be shown in the page or not (ie due to configuration)
  • state — either present or future, indicates whether it is currently in use or if it will be used later
  • step_group_name — the name of the group to which the step belongs (a group of steps is shown if there is at least one step of the group that is visible)
  • url — the unique identifier for the step (we’ll need this later — also note how it appears in the address bar too)

Add a New Module to Checkout Step

The common customization we need to do here is custom transaction body field it is correctly points out that the correct way of implementing this functionality

Create and Set Up the Custom Transaction Body Field

In NetSuite go to Customization > Lists, Records & Fields > Transaction Body Fields > New and set it up as follows:

  • Label — Preferred Delivery Date
  • ID — _preferred_date
  • Type — Date
  • Store Value — (checked)
  • Applies To — Sale, Web Store
  • Access > Role — Customer Center, Edit
    When that’s configured, we need to surface it to the SuiteScript.
    Go to Setup > SuiteCommerce Advanced > Configuration and select your site and domain.
    In Advanced > Custom Fields, add custbody_preferred_date to the table and save.

Create a new extension

Create the Entry Point File

define('Example.PreferredDelivery.PreferredDelivery'
, [
    'Example.PreferredDelivery.PreferredDelivery.View'
  ]
,   function
  (
    PreferredDeliveryContainerView
  )
{
  'use strict';

  return  {
    mountToApp: function mountToApp (container)
    {
      var checkout = container.getComponent('Checkout');

      checkout.addModuleToStep(
      {
        step_url: 'opc' // if you're using a non-OPC checkout, then you will need to put the specific step URL in instead
      , module: {
          id: 'PreferredDeliveryView'
        , index: 6
        , classname: 'Example.PreferredDelivery.PreferredDelivery.View'
        }
      });

      checkout.addModuleToStep(
      {
        step_url: 'review'
      , module: {
          id: 'PreferredDeliveryView'
        , index: 99
        , classname: 'Example.PreferredDelivery.PreferredDelivery.View'
        }
      });
    }
  };
});

Create the View

define('Example.PreferredDelivery.PreferredDelivery.View'
, [
    'Wizard.Module'

  , 'example_preferreddelivery_preferreddelivery.tpl'
  ]
, function (
    WizardModule

  , example_preferreddelivery_preferreddelivery_tpl
  )
{
  'use strict';

  return WizardModule.extend({

    template: example_preferreddelivery_preferreddelivery_tpl

  , getContext: function getContext()
    {
      return {
        isReview: this.step.step_url == 'review'
      };
    }
  });
});

Create the Template

<h2 class="preferreddelivery-title">{{translate 'Preferred Delivery Date'}}</h2>
<div id="preferreddelivery-container" class="preferreddelivery-container">
    {{#if isReview}}
        {{#if model.options.custbody_preferred_date}}
            <p>{{model.options.custbody_preferred_date}}</p>
        {{else}}
            <p>{{translate 'No date selected'}}</p>
        {{/if}}
    {{else}}
        <input class="preferreddelivery-input" type="date" name="custbody_preferred_date" data-todayhighlight="true" value="{{model.options.custbody_preferred_date}}">
    {{/if}}
</div>

Add the Sass

.preferreddelivery-title {
    @extend .order-wizard-title;
}

.preferreddelivery-container {
    @extend .box-column;
}

.preferreddelivery-input {
    @extend .input-large;
}

Add a New Step Group and Step

In the above customization, we added the field to an existing step and step group. However, if your customization requires its own space then you can create your own step group and step to add it to.

define('Example.PreferredDelivery.PreferredDelivery', [
    'Example.PreferredDelivery.PreferredDelivery.View'
], function (
    PreferredDeliveryContainerView
){
    'use strict';

    return  {
        mountToApp: function mountToApp (container) {
            var checkout = container.getComponent('Checkout');

            checkout.addStepsGroup({group: {
                index: 3, 
                name: 'Preferred Delivery', 
                url: 'preferred-delivery' 
            }})

            .done(function () {
                checkout.addStep({step: {
                    group_name: 'Preferred Delivery', 
                    index: 3, // suggested match the step group index if you're adding them at the same time
                    isActive: function () {}, // yes, an empty function
                    name: 'Preferred Delivery', 
                    showStep: function () {return true}, // can obviously be more complicated than this
                    url: 'preferred-delivery/date' 
                }})

                .done(function () {
                    checkout.addModuleToStep({
                        step_url: 'preferred-delivery/date', 
                        module: { 
                            id: 'PreferredDeliveryView', 
                            index: 0, 
                            classname: 'Example.PreferredDelivery.PreferredDelivery.View', 
                            options: {container: '#wizard-step-content'}
                        }
                    })
                });
            });

            checkout.addModuleToStep({
                step_url: 'review',
                module: {
                    id: 'PreferredDeliveryView',
                    index: 99,
                    classname: 'Example.PreferredDelivery.PreferredDelivery.View'
                }
            });
        }
    };
});

Leave a comment

Your email address will not be published. Required fields are marked *