In SuiteCommerce, SuiteCommerce MyAccount, and SuiteCommerce Advanced, there are some great new additions for developers in 2021.2 to help merchants realize their business goals and grow their web stores on NetSuite.

Modern development on SuiteCommerce focuses on the extensibility API and commerce extension framework, the best way of introducing custom code to web stores and customer portals hosted on NetSuite. These updates are included automatically in all SuiteCommerce and SuiteCommerce MyAccount instances, and all SuiteCommerce Advanced web stores built on or manually migrated to 2021.2 or newer.

In summary, the additions to the extensibility API are:

  • Cart.triggerAddToCartConfirmation()
  • Environment.defineSearchMasterOptions()
  • PDP.getPrice()
  • UserProfile.getCookieOptions() and UserProfile.setCookieOptions()
  • UserProfile.getCustomerSegments()

Note that not all extensibility API methods are available to MyAccount sites.

Trigger an Add-to-Cart Confirmation

Since its inception, the cart component has offered developers the ability to add an item to the cart without the user having to click the normal Add To Cart buttons. However, this always happened silently in the background, which may not suit all use cases.

As of 2021.2, developers can now use Cart.triggerAddToCartConfirmation() to trigger the site’s configured add-to-cart behavior, either by chaining it to the end of the addLine() request or whenever is appropriate for your customization; for example:

var Cart = container.getComponent('Cart');
var item = {
    line: {
        quantity: 1,
        item: {
            internalid: 8388
        }
    }
}
Cart.addLine(item).then(function () {Cart.triggerAddToCartConfirmation()});

Define Item Search API Master Options

Every web store has a configuration record that defines some options that are used every time a request is made to the item search API. These are generally quite simple and unchanging—for example, designating which field sets should be used for each of the types of item search that can happen on the site.

In SuiteCommerce Advanced, it has always been possible to override these settings manually. In this release, it is now possible to do this entirely with the extensibility API as we have added defineSearchMasterOptions() to the Environment component.

Changes made using this method can be used to override the settings in the configuration record, as well as make new ones beyond the scope of the configuration record.

Keep in mind that customizations made to the item search API’s master options can be quite powerful as they can affect all product data returned from the API. If you do make an advanced customization using it, make sure you thoroughly test it.

Prefiltering Search Results

One particular use case I think is interesting is the ability to automatically apply filters to search results.

In the past, we have been asked whether it was possible to have ‘invisible’ facets that always apply in the background. These would have the effect of prefiltering results, meaning that certain customers (or even all customers) always see a subset of items in certain situations.

To give an example, consider an auto part retailer. When a shopper visits, they might be looking just for products relevant to the car they drive. This means that they will want to filter products to show ones that can only be used with a particular make, model and year. It can be a lot of hard work to find relevant parts when the inventory could contain tens or even hundreds of thousands of possible items.

Knowing this, a developer could create a widget that shows when a user first visits asking them what car they are looking to buy parts for. After entering their choices, master item search API options could be set that automatically applies facets for the shopper’s make, model and year. You could even save these values a custom fields on the customer’s entity record, so that they are saved for the future!

As a contrived example, let’s assume I only want to show my customers red products (and then hide the color facet from them), I could write the following code in my extension:

var Environment = container.getComponent('Environment');
if (Environment) {
    Environment.defineSearchMasterOptions('Facets', function (searchApiMasterOptions) {
        // Only allows items that have red options to be returned
        searchApiMasterOptions.custitem31 = 'red';
        // Prevents the color facet from appearing in the UI
        searchApiMasterOptions['facet.exclude'] = 'custitem31';
        return searchApiMasterOptions
    });
}

Note some important things about this:

  • To ‘prefilter’ any results, the facet you are filtering with must be a valid facet as part of your site’s website setup record and search index. Invalid facets are ignored.
  • Facets can be preventing from appearing in the UI with facet.exclude—this can be used independently of any prefiltering you want (or do not want) to do. However, if you always want a facet to always be excluded, it is usually better to either remove it from your site’s website setup record or add it as an exclusion in the configuratipn record.
  • If you prefilter results but don’t exclude the facet, the facet and the pre-filtered option will show in the UI as an available, unapplied facet option that has no effect on the search results. For example, if you prefilter results by the color red, Red will still appears as a valid, unselected option in the Color facet, and toggling it on and off will have no effect.
  • If the filtering is based on user input, you should make it clear to the shopper that the filtering is happening and provide a way for them to undo it.
  • Filtering applies throughout the site—for example, not just search results pages but also commerce category pages.

Remember, if you want to dynamically show different groups of items to different groups of customers, consider using personalized catalog views instead.

Get Current Product Price

Another extensibility API method that has been available since the beginning has been the getItemInfo() on the PDP component. This method returns very detailed information about the product, including pricing, but it is difficult to work with if you need to know a very specific price—the one based on the shopper’s current selections. This price vary depending on:

  • Matrix item options, as different combinations can have different prices
  • Quantity, as prices could be subjected to volume pricing schedules quantity pricing schedules

To make it easier to work with, we have added a simple getPrice() method to the PDP component that returns an object of prices that take these realtime possibilities into account. The object contains both the ‘current’ price and the ‘comparison’ price, with both available as formatted and unformatted values.

In order to aid developers who are implementing services and features that rely on cookies, we have added two new methods to the UserProfile component: getCookieOptions() and setCookieOptions().

As you’ll be aware, many jurisdictions require that shoppers are allowed to express consent options regarding the use of their data, and this can include choosing to allow or deny the collection of data required to operate certain (usually third-party) services. In order to help merchants comply with so-called ‘cookie consent’ laws, these two methods can be used by developers implementing services that may require consent before they are enabled.

Get Customer Segments

Customer segments were introduced as part of the personalized catalog views functionality. They are half of the customer to inventory map that allow certain customers access to certain sections of your inventory.

In this release, we are introducing UserProfile.getCustomerSegments() that can be used to get the specific segments that a logged in user belongs to.

The general idea behind these is that you can pair custom functionality with your custom catalogs. For example, if you have a group of VIP customers who get to see VIP-only items, then you may also want to show additional messaging, features or options only for those customers.

In this code sample, we have set up a promise to trigger a callback (in this case, a simple console message) to do something after detecting that the user belongs to our VIP group, which, in this example, is denoted by the ID of ‘123’. If the user isn’t in the VIP group, nothing happens because the promise is never resolved.

var UserProfile = container.getComponent('UserProfile');
if (UserProfile) {
    var isVIP = jQuery.Deferred();
    isVIP.done(function () {console.log('Customer is VIP!')});

    UserProfile.getCustomerSegments().then(function (customerSegments) {
        for (i = 0; i < customerSegments.length; i++) {
            if (customerSegments[i].id == 123) {
                isVIP.resolve();
            }
        }
    });
}

In addition to the the custom customer segments that a site might have, we have also included all of the default segments a customer could be a member of (the IDs are in brackets):

  • All users (-1)
  • Logged out or anonymous (-2)
  • Logged in or recognized (-3)

This means that you can also introduce functionality based on simple characteristics, such as whether a user is logged in.

For your convenience, these values are available as a simple object via UserProfile.DEFAULT_SEGMENTS.

Finally, don’t forget that we also introduced a getCustomerSegments() method to the customer methods of the Commerce API in NetSuite 2021.1—this means that you should now be able to implement comprehensive customer-based business logic in both the front and backends of a site.