In NetSuite development, there are a few common scripting patterns to master. One of these patterns is a kind of automation that connects both the client side and a server side. Today we will be looking at a Client Script calling a Suitelet.

In the previous NetSuite development blog post, we explained a method to organize NetSuite scripts with intentionality. In this post, we would like to cover a specific use case of that organization paradigm.

This pattern, from a User Event Script (on a custom button), we call a Client Script, which in turn calls a Suitelet. From that Suitelet, we return a result and respond accordingly. (For the sake of simplicity, we will not use library modules for the following SuiteScript examples.)

Some Things to Note

  1. When calling a Suitelet from a Client Script, you must decide the behavior you’d like to see. If you want to show a message on the same page, then you should use a https.get() function call. If you want the user to be redirected to a form or PDF created by the Suitelet, use the window.open() function.
  2. While a Client Script that runs on a record should have the @NSScriptType ClientScript JSDoc tag, a Client Script that is referenced by a server-side script and that doesn’t run on pageInit, fieldChange, or any of the other Client Script triggers should not have that tag, and the Client Script should simply be uploaded to the SuiteScripts folder in the File Cabinet.

Code Samples

Sample User Event Script

The User Event script to add the button is pretty simple. Notice that when passing values as parameters to the client script function (in the functionName variable), each value must be surrounded by quotation marks.

define([], function () {
    /**
     * Adds button and defines the function that should be called in the associated Client script.
     * 
     * Deploy To: Invoices
     * @NApiVersion 2.x
     * @NScriptType UserEventScript
     * @author Stephen Lemp (SuiteRep)
     */
    var exports = {};


    /**
     * @function beforeLoad Function to be executed after record is submitted to server.
     * @governance 0
     * 
     * @param {Object} context 
     * @param {Record} context.newRecord  The new record.
     * @param {serverWidget.Form} context.form The current form.
     * @param {String} context.type The type of operation invoked by the event.
     * @param {http.ServerRequest} context.request The HTTP request information sent by the browser. 
     *                     If the event was triggered by a server action, this value is not present.
     * 
     * @return {void}
     * @since 2015.2
     */
    function beforeLoad(context) {
        if (context.type !== context.UserEventType.VIEW) { return; }
        var invoiceNumber = context.newRecord.getValue('tranid');
        var div_id = context.newRecord.getValue('department');
        var invoice_id = context.newRecord.id;

        try {
            context.form.addButton({
                id: 'custpage_btn_confirmsendemail',
                label: 'Email Invoice',
                functionName: 'confirmSendEmail("' + invoiceNumber + '","' + invoice_id + '","' + div_id + '")'
            });
            context.form.clientScriptModulePath = 'SuiteScripts/sr_cli_inv_emailinvoice_confirmation.js';
        } catch (error) {
            log.error('error', error);
        }
    }

    exports.beforeLoad = beforeLoad;
    return exports;
});

Sample Client Script

Here’s an example of a Client Script that prompts a Confirm box before actually sending an email.

define(['N/url', 'N/https', 'N/ui/dialog', 'N/ui/message'], function (url, https, dialog, msg) {
    /**
     * @description Client Script to confirm the sending of an email and then to send it.
     * 
     * @NApiVersion 2.x
     * @author Stephen Lemp (SuiteRep)
     */
    var exports = {};

    function confirmSendEmail(invoice_number, invoice_id, div_id) {
        var options = {
            title: "Confirm to Email the Customer",
            message: "Are you sure you would like to email this invoice?"
        };

        function success(result) {
            if (result == true) {
                //call suitelet
                var suiteletURL = url.resolveScript({
                    scriptId: 'customscript_sr_sut_emailinvoice',
                    deploymentId: 'customdeploy_sr_sut_emailinvoice',
                    returnExternalUrl: false,
                    params: {
                        'invoice_id': invoice_id,
                    }
                });

                // Calling the Suitelet like this does not open a new page, but it does allow you to 
                // receive back a response from the Suitelet and perform logic based on the response 
                // in this Client Script. The logic here is performed in the showSuccess function.
                https.get.promise({
                    url: suiteletURL
                }).then(function (response) {
                    showSuccess(invoice_id)
                }).catch(function (reason) {
                    log.error("failed to send email", reason)
                    showError(reason);
                });
                // If the suitelet generates a PDF or form that should appear for the user, use window.open()
                window.open(suiteletURL);
                // To open SuiteLet in same tab, use location.href
                location.href = suiteletURL;
                // To open SuiteLet in same tab without popup to confirm, add "window.onbeforeunload = null;":
                window.onbeforeunload = null;
                location.href = suiteletURL;
            }
            return result;
        }

        function showSuccess(invoice_id) {
            var confirmMsg = msg.create({
                title: "Email Sent",
                message: "An email has been sent to customer.",
                type: msg.Type.CONFIRMATION
            });
            confirmMsg.show({
                duration: 5000 // will disappear after 5s
            });

        }

        function failure(reason) {
            showError(reason);
        }

        function showError(message) {
            var confirmMsg = msg.create({
                title: "Email Failure",
                message: "Email Failed For Reason: " + message,
                type: msg.Type.WARNING
            });
            confirmMsg.show({
                duration: 30000 // will disappear after 30s
            });
        }

        dialog.confirm(options).then(success).catch(failure);
    }

    exports.confirmSendEmail = confirmSendEmail;
    return exports;
});

Sample Suitelet Script

The above Client Script calling a Suitelet. 

define(['N/record', 'N/email', 'N/render', 'N/runtime'],
    function (record, email, render, runtime) {
        /**
         * @description This Suitelet takes the internal ID of an invoice and emails a copy of it to the 
         *              customer defined on the Invoice
         * @NApiVersion 2.x
         * @NScriptType Suitelet
         * @author Stephen Lemp (SuiteRep LLC)
         */
        var exports = {};
        var INVOICE_EMAIL_TEMPLATE_ID = 2;

        /**
         * @function onRequest Definition of the Suitelet script trigger point.
         * @governance XXX
         * 
         * @param {Object} params
         * @param {http.ServerRequest} params.request The incoming request.
         * @param {http.ServerResponse} params.response The Suitelet response.
         *
         * @return {void}
         * @since 2015.2
         */
        function onRequest(context) {
            if (context.request.method === 'GET') {
                var current_user = runtime.getCurrentUser();
                var invoice_id = parseInt(context.request.parameters.invoice_id);

                if (!invoice_id) {
                    log.error("No Invoice ID passed to SuiteLet")
                    return false;
                }
                
                var rec = record.load({
                    type: record.Type.INVOICE,
                    id: invoice_id
                });

                var customer = rec.getValue('entity');
                var invoicePDF = render.transaction({
                    entityId: invoice_id,
                    printMode: render.PrintMode.PDF
                });

                var mergeResult = render.mergeEmail({
                    templateId: INVOICE_EMAIL_TEMPLATE_ID,
                    recipient: customer,
                    transactionId: invoice_id,
                });

                email.send({
                    author: current_user,
                    recipients: customer,
                    subject: mergeResult.subject,
                    body: mergeResult.body,
                    attachments: [invoicePDF],
                    relatedRecords: {
                        transactionId: invoice_id
                    }
                });
                context.response.write(shippingcost)
                return;
            } 
        }
        exports.onRequest = onRequest;
        return exports;
    });

Conclusion

Sometimes we need to utilize multiple script types to get the job done. We hope these script examples will help give you extra tools as you learn to code in NetSuite effectively. Subscribe to our email list to stay up to date on our latest posts!