5 Practical SuiteScript 2.1 User Event Scripts with TypeScript

November 30, 2023 | 7 minute read
Mohammed Kassem
SuiteCloud Advocate
Text Size 100%:

Now that you have a solid project structure, let’s harness the full potential of SDF, SuiteScript 2.1, and TypeScript with practical examples. Within this guide, you'll be introduced to these five practical user event scripts written in SuiteScript 2.1 and TypeScript:

  1. Field Defaulting
  2. Record Validation
  3. Automated Field Updating
  4. Creating Related Records
  5. Sending Notifications

You’ll create and deploy these user event script customizations to your account to help kickstart your SuiteScript 2.1 and TypeScript journey. The logic in each example can easily be modified to execute on other record types such as Customers and Sales Orders. Additionally, each example showcases distinct entry points and user event types defined in TypeScript, presenting valuable learning opportunities. Our primary focus centers around dynamic Sales Order transactions, highlighting their practicality.

Click here for the complete project source code (GitHub)!

User Event Script Examples in TypeScript

You'll start with creating a record and form, and use server-side User Event scripts to customize record behavior. These scripts can be used to implement custom validation, enforce user-defined data integrity and business rules, and customize forms.

For each example below, you'll find two corresponding scripts: 

  1. A TypeScript file containing the User Event Script
  2. An XML object file to control the Deployment Script. 

Note: without the XML object, the user event script won’t run on your account. Any TypeScript file should be saved to the TypeScript folder, while the XML files to the Objects folder.

After each example, don't forget to run the tsc command to transpile the TypeScript code to JavaScript. Then, use the Command Palette (CMD + Shift + P) and the SuiteCloud: Deploy Project command to trigger project deployment to your NetSuite account. 

This is an excellent opportunity for you to practice pushing small, incremental changes to your account and making the most of SDF's efficiency. Without SDF, you'd have to upload the scripts and deployment scripts directly into the account every time you update a property configuration or file.

Field Defaulting

After you create the new record by executing the user event script, you can set default values for specific fields, making it easier to pre-populate data entries with default values. For instance, in the beforeLoad context, you can use a script to set a default value for a custom field. For example, when you create a new sales order in NetSuite, the memo field value can be automatically set to "setting default value for memo". This ensures a smoother data entry process and reduces manual input efforts.

/**
 * defaultFieldValues.ts

 * @NApiVersion 2.1
 * @NScriptType UserEventScript
*/

import {EntryPoints} from "N/types";
import log = require('N/log');

export function beforeLoad(context: EntryPoints.UserEvent.beforeLoadContext){
    log.debug({
        title: 'Before Load',
        details: `${context.type} ${context.newRecord.type} ${context.newRecord.id}`
    });

    if ([context.UserEventType.CREATE].includes(context.type)){
        context.newRecord.setValue({
            fieldId: 'memo',
            value: 'setting default value for memo'
        });
    }
}

In the script above, you have the flexibility to switch CREATE to EDIT to modify when the user event script should execute. Additionally, you can extend this list to accommodate other use cases that are tailored to your business needs. 

Now, let's move on to creating the Deployment Script in the Objects folder to activate the script. Simply create a new file in the Objects folder named customscript_default_field_values.xml and use the provided code below:

<usereventscript scriptid="customscript_default_field_values">
    
<name>Sales Order - Default Field Values Demo</name>
    <notifyowner>T</notifyowner>
    <scriptfile>[/SuiteScripts/defaultFieldValues.js]</scriptfile>
    <scriptdeployments>
        <scriptdeployment scriptid="customdeploy_default_field_values">
            <isdeployed>T</isdeployed>
            <loglevel>DEBUG</loglevel>
            <recordtype>SALESORDER</recordtype>
            <status>TESTING</status>
        </scriptdeployment>
    </scriptdeployments>
</usereventscript>

The customscript_default_field_values.xml file contains deployment details for the User Event Script defaultFieldValues.js. In this example, the script is deployed for Sales Order records with log level set to "DEBUG" and status set to "TESTING"

Observe that the isdeployed value within the <scriptdeployment> XML tag is set to "T", indicating that the deployment script is currently active. You have the flexibility to change this value to "F" directly from your IDE (VSCode) whenever you need to disable the script for testing or other purposes. This level of control allows you to manage your customizations efficiently and fine-tune their behavior as required during the development process.

This combination of TypeScript User Event Script and XML object file allows you to perform data validation on Sales Order records effectively, ensuring data accuracy and consistency within your NetSuite account. You can customize and extend this script to handle other validations or add additional entry points to suit your specific business requirements.

Please note that all the examples provided are currently tailored to Sales Order records. If you want to apply them to other record types, simply modify the recordtype XML tag in the deployment object file (XML) accordingly. For example, if you want to apply the same User Event Script to Customer records, you can change the recordtype value to "CUSTOMER" within the deployment object file.

Record Validation

You can also validate data when a record is created or edited. This helps prevent incorrect or inconsistent data from being saved in NetSuite. Specifically, this script will run before submitting an edit to the Sales Order record, throwing an error if the memo field is empty and prevents the record from being saved with empty memo field values.

/**
 * recordValidation.ts

 * @NApiVersion 2.1
 * @NScriptType UserEventScript
*/

import {EntryPoints} from "N/types";
import log = require('N/log');

export function beforeSubmit(context: EntryPoints.UserEvent.beforeSubmitContext){
    log.debug({
        title: 'Before Submit',
        details: `${context.type} ${context.newRecord.type} ${context.newRecord.id}`
    });
    if ([context.UserEventType.EDIT].includes(context.type)){
        const memoField = context.newRecord.getValue('otherrefnum');
        log.debug({
            title: 'otherrefnum',
            details: `${memoField}`
        })
        if (memoField == '')
            throw 'Memo Field cannot be empty.';
    }
}

And here is the customscript_record_manipulation.xml object file (deployment script, saved to Objects folder): 

<usereventscript scriptid="customscript_record_validation">
    
<name>Sales Order - Record Validaton Demo</name>
    <notifyowner>T</notifyowner>
    <scriptfile>[/SuiteScripts/recordValidation.js]</scriptfile>
    <scriptdeployments>
        <scriptdeployment scriptid="customdeploy_record_validation">
            <isdeployed>T</isdeployed>
            <loglevel>DEBUG</loglevel>
            <recordtype>SALESORDER</recordtype>
            <status>TESTING</status>
        </scriptdeployment>
    </scriptdeployments>
</usereventscript>

Automated Field Updating

User Event scripts can also update certain fields on a record based on changes to other fields, which can be useful in maintaining calculated fields or triggering workflows. In this example, when you create a record and submit it with a value, we will perform calculations on custom record 1 and then set the field value for record 2.

/**
 * fieldManipulation.ts

 * @NApiVersion 2.1
 * @NScriptType UserEventScript
*/

import {EntryPoints} from "N/types";
import log = require('N/log');
export function beforeSubmit(context: EntryPoints.UserEvent.beforeSubmitContext){
    log.debug({
        title: 'Before Submit',
        details: `${context.type} ${context.newRecord.type} ${context.newRecord.id}`
    });

    if ([context.UserEventType.CREATE].includes(context.type)){
        const orderNumber = context.newRecord.getValue('tranid') as number;
        let newValue = orderNumber * 2;
        context.newRecord.setValue('memo', newValue);
    }
}

And here is the customscript_field_manipulation.xml (saved to Objects folder):

<usereventscript scriptid="customscript_field_manipulation">
    
<name>Sales Order - Field Manipulation Demo</name>
    <notifyowner>T</notifyowner>
    <scriptfile>[/SuiteScripts/fieldManipulation.js]</scriptfile>
    <scriptdeployments>
        <scriptdeployment scriptid="customdeploy_field_manipulation">
            <isdeployed>T</isdeployed>
            <loglevel>DEBUG</loglevel>
            <recordtype>SALESORDER</recordtype>
            <status>TESTING</status>
        </scriptdeployment>
    </scriptdeployments>
</usereventscript>

Creating Related Records

When a Sales Order record is saved, a user event script could be used to automatically create related Tasks. In this example, on the creation of a new Sales Order, we will automatically generate a related Task with the title "Related Task" and associate it with the same company as the Sales Order. This automation streamlines the process of task creation and ensures that all relevant information is linked and easily accessible for efficient task management.

/**
 * createRelatedRecords.ts

 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */

import {EntryPoints} from "N/types";
import log = require('N/log');
import record = require('N/record')

export function afterSubmit(context: EntryPoints.UserEvent.afterSubmitContext){
    log.debug({
        title: 'After Submit',
        details: `${context.type} ${context.newRecord.type} ${context.newRecord.id}`
    });
    if ([context.UserEventType.CREATE].includes(context.type)){
        const newRecord = context.newRecord;
        const relatedRecord = record.create({
            type: record.Type.TASK,
            isDynamic: true
        });
        relatedRecord.setValue('title', 'Related Task');
        relatedRecord.setValue('company', newRecord.id);
        relatedRecord.save();
    }
}

customscript_create_related_records.xml:

<usereventscript scriptid="customscript_create_related_records">
    
<name>Sales Order - Related Records Demo</name>
    <notifyowner>T</notifyowner>
    <scriptfile>[/SuiteScripts/createRelatedRecords.js]</scriptfile>
    <scriptdeployments>
        <scriptdeployment scriptid="customdeploy_create_related_records">
            <isdeployed>T</isdeployed>
            <loglevel>DEBUG</loglevel>
            <recordtype>SALESORDER</recordtype>
            <status>TESTING</status>
        </scriptdeployment>
    </scriptdeployments>
</usereventscript>

Sending Notifications

To send email notifications or generate alerts based on specific changes to a record, you can utilize User Event scripts. In this example, you'll learn how to send an email using the email module after submitting a new sales record. This feature is useful for keeping stakeholders informed about important changes and actions within the system. To get started, create a new file named sendNotifications.ts in the TypeScripts folder and use the following code:

/**
 * sendNotifications.ts

 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */

import {EntryPoints} from "N/types";
import log = require('N/log');
import email = require('N/email')

export function afterSubmit(context: EntryPoints.UserEvent.afterSubmitContext){
    if ([context.UserEventType.CREATE].includes(context.type)){
        const newRecord = context.newRecord;
        email.send({
            author: -5, // -5 is the default sender ID for system notes
            recipients: 'hallafamerx3@gmail.com',
            subject: 'TEST - Record Created Notification',
            body: `Record ${newRecord.id} has been created.`
        });
    }
    log.debug({
        title: 'Email Sent',
        details: `${context.type} ${context.newRecord.type} ${context.newRecord.id}`
    });
}

In this User Event Script, the afterSubmit entry point is utilized to send an email notification after a new record is created. The script uses the email.send function from the "N/email" module to send the email. The recipient's email address is set as "email@example.com" but you can replace it with the desired recipient's address. The subject and body of the email are customized to include the ID of the newly created record.

To activate this script, create the corresponding XML object file customscript_send_notifications.xml in the Objects folder with the following content:

<usereventscript scriptid="customscript_send_notifications">
    
<name>Sales Order - Send Notifications Demo</name>
    <notifyowner>T</notifyowner>
    <scriptfile>[/SuiteScripts/sendNotifications.js]</scriptfile>
    <scriptdeployments>
        <scriptdeployment scriptid="customdeploy_send_notifications">
            <isdeployed>T</isdeployed>
            <loglevel>DEBUG</loglevel>
            <recordtype>SALESORDER</recordtype>
            <status>TESTING</status>
        </scriptdeployment>
    </scriptdeployments>
</usereventscript>

With this implementation, whenever a new Sales Order is created, the script will automatically send an email notification to the specified recipient (email@example.com) with the subject "TEST - Record Created Notification" and the body containing the ID of the newly created Sales Order.

Well done! Now that you've laid the groundwork, it's time to empower your NetSuite experience by utilizing SDF, SuiteScript 2.1, and TypeScript. These five user event scripts enable you to craft a finely-tuned system tailored precisely to your business processes, granting you full control over your NetSuite destiny. Test your comprehension and propel your journey to the next level by exploring other script types, such as client scripts.

Mohammed Kassem

SuiteCloud Advocate


Previous Post

Harnessing the Power of Test-Driven Development (TDD): A Suitelet Walkthrough

Mohammed Kassem | 5 min read

Next Post


23c JDBC seamless authentication with OCI IAM and Azure AD

Jean de Lavarene | 6 min read