Home Anatomy of SuiteScript: Script Deconstruction
Post
Cancel

Anatomy of SuiteScript: Script Deconstruction

Introduction

This is the first post in the Anatomy of Suitescript Series. We will be looking at a blank script and explaining how the different parts of the script work.

We will be using a user event script as an example, but these concepts will not be specific to user event scripts.

Example Script

This is the contents of a user event script generated by NetSuite using the VSCode extension and SDF.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */
define(['N/api', 'N/record', 'N/runtime'],

    (api, record, runtime) => {
        /**
         * Defines the function definition that is executed before record is loaded.
         * @param {Object} scriptContext
         * @param {Record} scriptContext.newRecord - New record
         * @param {string} scriptContext.type - Trigger type; use values from the context.UserEventType enum
         * @param {Form} scriptContext.form - Current form
         * @param {ServletRequest} scriptContext.request - HTTP request information sent from the browser for a client action only.
         * @since 2015.2
         */
        const beforeLoad = (scriptContext) => {

        }

        /**
         * Defines the function definition that is executed before record is submitted.
         * @param {Object} scriptContext
         * @param {Record} scriptContext.newRecord - New record
         * @param {Record} scriptContext.oldRecord - Old record
         * @param {string} scriptContext.type - Trigger type; use values from the context.UserEventType enum
         * @since 2015.2
         */
        const beforeSubmit = (scriptContext) => {

        }

        /**
         * Defines the function definition that is executed after record is submitted.
         * @param {Object} scriptContext
         * @param {Record} scriptContext.newRecord - New record
         * @param {Record} scriptContext.oldRecord - Old record
         * @param {string} scriptContext.type - Trigger type; use values from the context.UserEventType enum
         * @since 2015.2
         */
        const afterSubmit = (scriptContext) => {

        }

        return {beforeLoad, beforeSubmit, afterSubmit}

    });


Notice the first comment block at the top of the script. This is a special comment block that is used to specify different properties of the script. The first property is @NApiVersion 2.1 which specifies the version of the NetSuite API that we are using. The second property is @NScriptType UserEventScript which specifies the type of script that we are writing.

Let’s compress this script to see what the individual parts are.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
define(['N/api', 'N/record', 'N/runtime'],

    (api, record, runtime) => {

        const beforeLoad = (scriptContext) => { }
        const beforeSubmit = (scriptContext) => { }
        const afterSubmit = (scriptContext) => { }

        return {beforeLoad, beforeSubmit, afterSubmit}

    }

);

As you see we have one top level function define which takes two arguments. The first argument is an array of modules that we are importing:

1
['N/api', 'N/record', 'N/runtime']

The second argument is a function that returns an object with the functions that we want to export:

1
2
3
4
(api, record, runtime) => {
  ...function definitions...
    return {beforeLoad, beforeSubmit, afterSubmit}
}

This function takes arguments that correspond to the modules that we imported. If we want to use the module N/runtime we can use the argument runtime in our function:

1
2
3
const beforeLoad = (scriptContext) => {
  const currentuser = runtime.getCurrentUser();
}

Note that the name runtime is arbitrary, we could have a script as follows:

1
2
3
4
5
6
7
8
define(['N/runtime'],

    (myRuntime) => {
        const beforeLoad = (scriptContext) => {
          const currentuser = myRuntime.getCurrentUser();
        }
        return {beforeLoad}
    });

Nevertheless, it is common to use the same name as the module name.

Now let’s take a look at the three functions that have been defined, namely beforeLoad, beforeSubmit and afterSubmit.

These functions are special in the sense that they are called by NetSuite when certain events occur. The function afterSubmit is called after a record has been submitted. Whenever a record is submitted, NetSuite will look at the object you exported and look for a function with the name afterSubmit. A different event will call beforeLoad and a different event will call beforeSubmit.

These special functions are sometimes referred to as entry points.

Entry points often have a parameter conventionally called scriptContext or context. When NetSuite calls the function, it will pass an object to the function containing various information related to the event that occurred.

Let’s take a look at the jsdoc that NetSuite has generated for us for the function afterSubmit:

1
2
3
4
5
6
7
8
        /**
         * Defines the function definition that is executed after record is submitted.
         * @param {Object} scriptContext
         * @param {Record} scriptContext.newRecord - New record
         * @param {Record} scriptContext.oldRecord - Old record
         * @param {string} scriptContext.type - Trigger type; use values from the context.UserEventType enum
         * @since 2015.2
         */

There is just one parameter scriptContext, but this is an object that can contain multiple properties. In this case, the object has three properties: newRecord, oldRecord and type.

Suppose we wanted to check if a specific field has changed in the record.

We can write something like:

1
2
3
4
5
6
7
8
9
   function afterSubmit(scriptContext) {
     const newRecord = scriptContext.newRecord;
     const oldRecord = scriptContext.oldRecord;
     const fieldChanged = newRecord.getValue('location') !== oldRecord.getValue('location');
     if(fieldChanged) {
      // do something
     }
   }

Some entry points are meant to return a value. None in a user event script, but client scripts have a few entry points that can return a value. Let’s look at an example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * @NApiVersion 2.1
 * @NScriptType ClientScript
 */

define([]){

    const pageInit = (context)  => { }

    const saveRecord = (context) => {
      if(Math.random() > 0.5){
        return true;
      } else {
        return false;
      }
    }

    return {pageInit, saveRecord}
}

Don’t worry about the pageInit function, we will look at it in a later chapter.

The function saveRecord is an entry point that is called when the user clicks the save button. If the result of Math.random() is greater than 0.5, then the function will return true and the record will be saved. If the result of Math.random() is less than 0.5, then the function will return false and the record will not be saved.

Do not deploy this script in production if you want to remain employed.

Conclusion

In this chapter we have looked at the basic structure of a script.

As far as deployment is concerned the docs are pretty clear

The next post we will start discussing individual scripts, starting with the User Event Script.

This post is licensed under CC BY 4.0 by the author.

Anatomy of SuiteScript: Introduction

Anatomy of SuiteScript: User Event