Netsuite Blog


Net Sweet!

A few years ago, I was introduced to Netsuite, a cloud-based ERP system. This new system was going to replace the existing Oracle EBS applications that was the backbone of a retail-based business focused on the consumer electronics industry. The organization decided to implement Netsuite using its own resources. As a result, I was part of a team of developers tasked with transitioning all existing business processes from Oracle EBS/ERP to Netsuite.

Prior to Netsuite, I had experience with several noteworthy ERP systems. None of them however, were cloud-based.

  • INFOR's Syteline was the very first ERP system I developed applications for. It was a Windows desktop-based system that required on-premise systems to run and support it. The application environment was form-based and with a SQL server back-end database.
  • EPICOR Vantage was the second ERP system that I developed applications for. The development environment was VB.Net for the application layer and Postgress 4GL for the database layer.
Netsuite finally introduced development to the cloud with its own version for code development called SuiteScript. Using Javascript technology, code development involved a basic knowledge of Javascript and understanding the exposed objects and properties for customizing and building business applications. Deploying code involved uploading the scripts to the Netsuite file cabinet, creating script records and deployment records using different SuiteScript types.

The biggest advantage of Netsuite, and any cloud-based system, is the convenience of working anywhere you have an internet connection to log into the Netsuite system. In terms of infrastructure, the whole environment is provisioned for your organization and none of it is on-premise. In terms of application development, the whole environment is cloud-based and you could technically develop using a browser-based IDE or use Visual Studio Code app, WebStorm or Eclipse IDEs.

I will be covering several techniques for code development and customizing Netsuite in this blog. Yes there will be actual working code that has been tested and running in a production environment that may be using undocumented features of NetSuite which may or may not break depending on when NetSuite updates the internal workings of their system. At this point we are not worried about that possibility because in reality, only 20% of the 80% of our worries ever come to pass (if at all).

So stay tuned for more because we are, after all, interested in finding real world solutions to real world problems!

Netsuite Blog


Sweet Scripting

SuiteScript -- what the hell is that?

Scripting?! Isn't that a step backward you might say. How does that hold up or compare to actual compiled code?

Well let me tell you that working with SuiteScript in Netsuite is relatively easy to get used to once you understand the basic concepts of scripting using SuiteScript. I mean who wouldn't want to be free from having to install all the bloated development tools code just to output "Hello World!" to a web page?

SuiteScript consists of several script types for every type of development situation you might need to build your applications with.

  • User Events

    This is the script to use if you need to fire events triggered on forms by user interaction with the user interface or automated processes.
    Sample Code from NetSuite Help

  • Portlets

    This is the script to use if you want to customize user dashboards and/or provide quick links to anything.
    Sample Code from NetSuite Help

  • Suitelets

    This is the script to use if you need to build your own custom forms. For web developers, the paradigm is similar to web forms that accept GET and POST requests and return web responses that you can evaluate.
    Sample Code from NetSuite Help

  • Scheduled Scripts

    This is the script to use if you need to process records and schedule automated processes.
    Sample Code from NetSuite Help

  • Map/Reduce Scripts

    Recently introduced in version 2.0 of SuiteScript, these types of scripts are the preferred type because of the imposition of usage governance limits or to put it simply, preventing code from hogging cloud-based resources using parallel processing and better allocation of processor queues for automated processing.
    Sample Code from NetSuite Help

  • Client Scripts

    All types of scripts execute server-side except for this type. If you want to run client-side code, this is your only bet.
    Sample Code from NetSuite Help

  • RESTlets

    If you need to integrate external applications with Netsuite, RESTlets are the best way to do that. Suitelets are also a good candidate because like RESTlets, they accept GET and POST requests that you can process server-side. Think of RESTlets as your very own custom APIs into Netsuite.
    Sample Code from NetSuite Help

SuiteScript is not the only way to create applications in NetSuite. If you want to communicate directly with the NetSuite API because your business requirements need to take a different approach, SuiteTalk is another way of manipulating data outside of the NetSuite user interface. But that's another topic on its own for a future blog post.
Netsuite Blog


Batch Processing

Use Case: You need to update Netsuite records using data from an external source with the data exceeding more than one page of NetSuite records (1000 records per page).

In order to update Netsuite records, you will need to use the internalid property to gain access to the record via script. If you need to match up more than 1000 records of external data with NetSuite records, you will need a way to process batches of 1000 records.

Here's an overview of the steps:

  • Collect the external data that contains a matching value for the Netsuite records you need to work with. This can be a custom field or a native Netsuite field that uniquely identifies the matching Netsuite record with the external data source. (e.g. UPC->upccode field in Netsuite).
  • Loop through the external data source field and assign them to a string variable stringing them together as comma delimited.
  • Pass the string to a function that builds the data object via another function that splits the data into a maximum of 1000 rows for each batch.

You can achieve this functionality with only three functions.

Note that code is in simple, basic, and easy-to-understand form, style and syntax for the purpose of making it easy to adapt for your environment.
Click for code view

Netsuite Blog



Use case: You just created a very nice custom form using a Suitelet script and you want to incorporate a saved search into this form. Displaying the saved search inside the Suitelet form presents a few challenges.

The first problem that you will encounter when trying to display a saved search using an iframe on a Suitelet form are the default Netsuite native controls because they're part of the Netsuite interface and iframes by default display the whole page and not just parts of it.

The best way to handle this is to use the DOM. Using client-side Javascript, you can hide those default Netsuite native controls. With this technique, you can use saved searches in an iframe on any Suitelet form.

You can achieve this functionality with a few lines of code.

Note that code is in simple, basic, and easy-to-understand form, style and syntax for the purpose of making it easy to adapt for your environment.
Click for code view
Netsuite Blog


Side-by-Side Datagrids

Use case: Form sublists on Suitelets are a great way to display datagrids of data but how do you display them side-by-side?

Sublists are a great way of displaying data on a datagrid on Suitelet forms. Unfortunately, sublists can only be displayed either one at a time on subtabs or one on top of another on field groups or even on subtabs. If you want to display lists side-by-side on a datagrid layout, you will need to use some other technique such as utilizing datagrids from Datatables. In this example, we will combine data sources from a dynamically-generated search and a CSV file upload from the NetSuite file cabinet. Regardless of the how you source the data, you will learn how to populate an HTML page with data from NetSuite and a file-based source to display a side-by-side datagrid on a custom NetSuite Suitelet form.

Here's an overview:

  • Download the javascript and css style sheet from Datatables.
  • Create the HTML template for displaying side-by-side datagrids.
  • Create a Suitelet form and add an iframe that references the HTML template from the NetSuite file cabinet.

You can achieve this functionality with a combination of SuiteScript and Datatables code.

Note that code is in simple, basic, and easy-to-understand form, style and syntax for the purpose of making it easy to adapt for your environment.
Click for code view
Netsuite Blog


Sweet World Of Wizards

Use case: You need a wizard-type user interface that can keep track of each process step.

If you've ever needed to import CSV data into Netsuite you would have used the Import Wizard. This is called an Assistant.

Netsuite's term for these types of wizards is an Assistant. Assistants are a type of form created on Suitelet scripts. They allow the user to move through every step of the process. Using assistants allow you to control and validate each step before moving to the next step of the process.

Code coming soon!
Netsuite Blog


Buttoned Up!

Use case: Custom buttons that fire to execute custom client-side functions are possible in Netsuite.

Form buttons in Netsuite are created and handled using any of the following constructs:

  • form.addSubmitButton
    This is the default and oft-used method for creating a button that submits data to the form. You can trap for this button using the context.request.parameters.submitter syntax on a POST call.
  • form.addButton
    This is one way of firing a client-side function referenced by the form.clientScriptModulePath syntax.
  • form.addResetButton
    This button resets the values on the form. It doesn't refresh the page.
  • sublist.addRefreshButton
    This button is created on the sublist and refreshes the sublist. You don't need to write a function to make this work. You just need to define the button.
  • sublist.addMarkAllButtons
    This button adds a Mark All and Unmark All button to handle checkbox interaction (toggle checked and unchecked) to the sublist.

You don't need to be limited to these types of button declarations. You can create your own custom buttons with custom functions fired from client-side scripts that takes your Suitelets to the next level.

Code coming soon!
Netsuite Blog


I REST my (use) case

Use case: You need to pull data from Netsuite with an external application but without using a 3rd party application or outside vendor.

You were just informed of the need to pull data from Netsuite to be able to analyze the data outside of Netsuite.

The easiest way to do that is to create a saved search and using the native NetSuite export functionality available via the toolbars, you can export data that way but that's native NetSuite functionality which is not the subject of this topic. We're more concerned about the technique for allowing an external application to communicate with NetSuite to retrieve records via automation. The only way to extract data without the use of 3rd party applications and plug-ins is by using a SuiteScript script type called RESTlets. RESTlets listen for GET and/or POST calls. RESTlets have external urls that you can use as endpoints for your external application.

The steps needed to achieve this are:

  • RESTlet
    Create a RESTlet and define the functions that will evaluate the parameters to pass on to either the GET or POST calls.
  • Authenticate
    Using OAuth 1.0 authentication methods, call the RESTlet using the RESTlet url.
  • Function call
    Pass the parameters to the function that will retrieve the data and return it in either CSV, JSON, or XML format.

Code coming soon!
Netsuite Blog


Back Door Access

Use case: You need to provide temporary access to some users but you don't want to buy additional licenses for NetSuite and Office 365.

You have new users coming onboard that need to view information from your NetSuite implementation but that usually requires buying additional licenses for NetSuite so that they can login and if you're also subscribed to Office 365, you will also need to provision licenses for them as well. But you don't want to spend the money for consuming another NetSuite license for just providing temporary access to NetSuite. What do you do? Do you bite the bullet and buy an additional NetSuite license? Do you take away someone else's login or allow multiple people to use the same login credentials thereby losing the ability to track potential changes to data?

There's a better way but it requires some technical know-how and that's one of the reasons you're reading this right? So sit tight and listen up and I'll show you how you can leverage the power of Suitelets in NetSuite to solve this issue.

The steps needed to achieve this are:

  • Suitelet
    Create a Suitelet and define what data you want to display to the user and any additional logic you will need for the functionality desired. This is the same approach for any solution requiring data to be displayed to the user.
  • Configure the Suitelet
    First, define your Suitelet script parameters. There are five (5) that I recommend for this to work.
    • Environment - values would be PRODUCTION or SANDBOX. This is to check if your script is running in the correct environment. This is especially helpful when you refresh SANDBOX with PRODUCTION ensuring that scripts that only need to run in PRODUCTION won't automagically run in SANDBOX.
    • Username - this is part of the mechanism of controls that you will need to implement to ensure that only valid users have access to NetSuite data provided by your Suitelet's logic.
      NOTE: You can control what these "made up" values are and the code will check for valid entries by comparing them with the "made up" values you configure for these parameters.
    • Password - this is the second part of the mechanism for controlling access to the data.
    • Enabled - this is a checkbox that allows you to disable or enable the Suitelet. It's another mechanism for security controls.
    • End Date - this is an automated way of disabling the Suitelet's functionality by providing an end date.
    Second, check the Available without Login checkbox and make sure that it is running as Administrator. Available without login creates an external URL that you will pass on to your temporary access users. This will be the user interface that they will use to view NetSuite data.
  • Design the User Interface
    Finally, you're ready to design the user interface. My approach is to use one (1) submit button whose label I change depending on the functionality I want to trap for when the user triggers the POST event on the Suitelet.
In conclusion, this solution opens up so many possibilities for providing access to NetSuite data as well as the flexibility of designing your own solutions. In terms of cost benefit, you will need to determine whether it's cheaper to buy an additional NetSuite license including an Office 365 license (if you use Office 365 for e-mail addresses) versus the cost of paying an out-sourced developer or engaging your employed development team to write the functionality you desire for your specific situation.

Code coming soon!
Netsuite Blog


Good Old HTML Voodoo

Use case: You need better control over your Netsuite form layouts.

Netsuite's form generation mechanism isn't well suited to handling complicated layouts. A good example of this is when you have a two-column layout and underneath it is a three-column layout or vice-versa. With good old plain HTML and some CSS formatting, you can easily achieve this. One of the ways to marry HTML pages with Netsuite's Suitelets is to use iframes but that's so very 90s. Good old plain HTML to the rescue! Yes it is possible to craft your user interface using HTML pages and call them from a Suitelet so that you can control styling and formatting. It is faster, lightweight, and affords you more creative control. With this approach, you are not bound by Netsuite's method of generating form controls which, if you've ever right-clicked on a page and selected Inspect, will find that every single form control (i.e. textbox) is laden with client-side javascript that is designed to handle every event that the form control might encounter even if you don't need that form control to be wired for those events. This adds a ton of unnecessary code to each Netsuite Suitelet which translates to increased load times and we all know that we suffer from short attention span syndrome!

So how do you exactly manage this "voodoo"? Here's an overview of what you will need...

  • Netsuite Suitelet
  • HTML header page
  • HTML footer page
  • HTML content pages
  • Javascript files
  • CSS files

You will start off by crafting your Netsuite Suitelet in such a manner that it will be able to handle the GET and POST requests and process them and load up your HTML pages. At a minimum you will need at least three (3) HTML pages. A header, footer, and content page. These HTML pages as well as the Javascript and CSS files will need to be saved to the Netsuite File Cabinet and they also need to be referenced either by their file ids or URL links.

Additionally, you can include the following components to spice up your HTML pages.
  • DataTables from to handle data grids
  • SweetAlert from for popups

The best part is that you are not going to be limited by Netsuite's mechanism because the Suitelet's role at this point is to simply render your HTML pages as well as calling your data layer functions to pull data from Netsuite. After that, the sky is the limit. The caveat though is that you will need to be able to build some of the functionality that comes with Netsuite's form handling capabilities like wiring up events for your HTML page controls.

Email me for more information if you're interested in this approach!

Code coming soon!
Netsuite Blog


The Address Book

Use case: We needed to pass a unique ID associated with an address to an external system.

Addreses in Netsuite are stored and maintained in an address book. Entity records like Customers, Vendors, and Employees will have addresses in this address book. Transaction records like Sales Orders will also store and maintain addresses in this address book. However, when you create a CUSTOM address on the transaction record, each CUSTOM address generates a unique id for each CUSTOM address you create for the transaction record. This is by design since the transaction address works for one-off situations. Netsuite doesn't check for duplicate addresses and this presented a problem in our need to pass a unique ID to send to an external system.

In terms of manual data entry, a simple requirement to not create CUSTOM addresses works well to mitigate this issue. Instead of creating a CUSTOM address, users should just select an existing address from the address dropdown lists. But if you have an external system that automates the creation of sales orders and it is unable to look up customer ship to and bill to addresses from the customer address book, this presents a challenge.

To solve this, we took the following steps:

  • Compare the address text created by the automation with the customer address book.
  • If the address doesn't exist in the customer address book, create it.
  • Retrieve the address id of this newly-created address.
  • Use this address id on the transaction record.
  • Send this address id to the external system.

The address comparison logic requires that country and zip code be sent because these are the first two values that will be used to compare given the fact that these are exact values. Once the incoming address passes these two tests, the next comparison stage can be undertaken.

The next stage involves comparing the concatenated street and city values and using a scoring system to determine the percentage match. The following are the important steps involved in ensuring a good matching logic.
  • Removing all spaces and extra characters like carriage returns and new lines.
  • Using only the street and city to compare.

The reason why it's important to use only the street and city is to increase the percentage of matching values. Adding more values like Address2 will further lessen the percentage of matching values.

Email me for more information if you're interested in this approach!

Get in Touch