N/task Module Script Samples

The following script samples demonstrate how to use the features of the N/task module:

Create and Submit a Map/Reduce Script Task

The following sample submits a map/reduce script task for processing. Before you use this sample, you must create a map/reduce script file, upload the file to your NetSuite account, and create a script record and script deployment record for it. For help working with map/reduce scripts, see SuiteScript 2.x Map/Reduce Script Type. You must also edit the sample and replace all hard-coded IDs with values that are valid in your NetSuite account.

Note:

This sample script uses the require function so that you can copy it into the SuiteScript Debugger and test it. You must use the define function in an entry point script (the script you attach to a script record and deploy). For more information, see SuiteScript 2.x Script Basics and SuiteScript 2.x Script Types.

Important:

This sample uses SuiteScript 2.1. For more information, see SuiteScript 2.1.

            /**
 * @NApiVersion 2.1
 */
require(['N/task', 'N/runtime', 'N/email'], (task, runtime, email) => {
    // Store the script ID of the script to submit
    //
    // Update the following statement so it uses the script ID
    // of the map/reduce script record you want to submit
    const mapReduceScriptId = 'customscript_test_mapreduce_script';
 
    // Create a map/reduce task
    //
    // Update the deploymentId parameter to use the script ID of
    // the deployment record for your map/reduce script
    let mrTask = task.create({
        taskType: task.TaskType.MAP_REDUCE,
        scriptId: mapReduceScriptId,
        deploymentId: 'customdeploy_test_mapreduce_script'
    });
 
    // Submit the map/reduce task
    let mrTaskId = mrTask.submit();
 
    // Check the status of the task, and send an email if the
    // task has a status of FAILED
    //
    // Update the authorId value with the internal ID of the user
    // who is the email sender. Update the recipientEmail value
    // with the email address of the recipient.
    let taskStatus = task.checkStatus(mrTaskId);
    if (taskStatus.status === 'FAILED') {
        const authorId = -5;
        const recipientEmail = 'notify@myCompany.com';
        email.send({
            author: authorId,
            recipients: recipientEmail,
            subject: 'Failure executing map/reduce job!',
            body: 'Map reduce task: ' + mapReduceScriptId + ' has failed.'
        });
    }
}); 

          

Create and Submit an Asynchronous Search Task and Export the Results into a CSV File

The following sample creates an asynchronous search task to execute a saved search and export the results of the search into a CSV file stored in the File Cabinet. After the search task is submitted, the sample retrieves the task status using the task ID. Some of the values in this sample are placeholders. Before using this sample, replace all hard-coded values, such as IDs and file paths, with valid values from your NetSuite account. If you run a script with an invalid value, the system may throw an error.

Note:

This sample script uses the require function so that you can copy it into the SuiteScript Debugger and test it. You must use the define function in an entry point script (the script you attach to a script record and deploy). For more information, see SuiteScript 2.x Script Basics and SuiteScript 2.x Script Types.

Important:

This sample uses SuiteScript 2.1. For more information, see SuiteScript 2.1.

            /**
 * @NApiVersion 2.1
 */
require(['N/task'], task => {
    // Do one of the following:
    //
    // - Create a saved search and capture its ID. To do this, you can use
    //   the following code snippet (replacing the type, id, filters, and
    //   columns values as appropriate):
    //
    //   let mySearch = search.create({
    //       type: search.Type.SALES_ORDER,
    //       id: 'customsearch_my_search',
    //       filters: [...],
    //       columns: [...]
    //   });
    //   mySearch.save();
    //   let savedSearchId = mySearch.searchId;
    //
    // - Use the ID of an existing saved search. This is the approach that
    //   this script sample uses. Update the following statement with the
    //   internal ID of the search you want to use.
    const savedSearchId = 669;
 
    // Create the search task
    let myTask = task.create({
        taskType: task.TaskType.SEARCH
    });
    myTask.savedSearchId = savedSearchId;
 
    // Specify the ID of the file that search results will be exported into
    //
    // Update the following statement so it uses the internal ID of the file
    // you want to use
    myTask.fileId = 448;
 
    // Submit the search task
    let myTaskId = myTask.submit();
 
    // Retrieve the status of the search task
    let taskStatus = task.checkStatus({
        taskId: myTaskId
    });
 
    // Optionally, add logic that executes when the task is complete
    if (taskStatus.status === task.TaskStatus.COMPLETE) {
        // Add any code that is appropriate. For example, if this script created
        // a saved search, you may want to delete it.
    }
}); 

          

Create and Submit a Task with Dependent Scripts

The following sample creates a scheduled script task and a map/reduce script task. It then creates an asynchronous search task and adds the scheduled script task and the map/reduce script task to the search task as dependent scripts. These scripts are processed when the search task is complete. For more information, see SuiteCloud Processors.

This sample refers to two script parameters: custscript_ss_as_srch_res for the scheduled script, and custscript_mr_as_srch_res for the map/reduce script. These parameters are used to pass the location of the CSV file to the dependent scripts, which is shown in the second and third code samples below. Before using this sample, create these parameters in the script record. For more information, see Creating Script Parameters.

Note:

This sample script uses the require function so that you can copy it into the SuiteScript Debugger and test it. You must use the define function in an entry point script (the script you attach to a script record and deploy). For more information, see SuiteScript 2.x Script Basics and SuiteScript 2.x Script Types.

            /**
 * @NApiVersion 2.x
 */

require(['N/task'], function(task) {
    // Specify a file for the search results
    var asyncSearchResultFile = 'SuiteScripts/ExportFile.csv';

    // Create a scheduled script task
    var scheduledScript = task.create({
        taskType: task.TaskType.SCHEDULED_SCRIPT
    });
    scheduledScript.scriptId = 'customscript_as_ftr_ss';
    scheduledScript.deploymentId = 'customdeploy_ss_dpl';
    scheduledScript.params = {
        'custscript_ss_as_srch_res' : asyncSearchResultFile
    };

    // Create a map/reduce script task
    var mapReduceScript = task.create({
        taskType: task.TaskType.MAP_REDUCE
    });
    mapReduceScript.scriptId = 'customscript_as_ftr_mr';
    mapReduceScript.deploymentId = 'customdeploy_mr_dpl';
    mapReduceScript.params = {
        'custscript_mr_as_srch_res' : asyncSearchResultFile
    };

    // Create the search task
    var asyncTask = task.create({
        taskType: task.TaskType.SEARCH
    };
    asyncTask.savedSearchId = 'customsearch35';
    asyncTask.filePath = asyncSearchResultFile;

    // Add dependent scripts to the search task before it is submitted
    asyncTask.addInboundDependency(scheduledScript);
    asyncTask.addInboundDependency(mapReduceScript);

    // Submit the search task
    var asyncTaskId = asyncTask.submit();
}); 

          

To read the contents of the search results file in a dependent scheduled script, consider the following script sample:

            /**
 * @NApiVersion 2.x
 * @NScriptType ScheduledScript
 */
define(['N/file', 'N/log', 'N/email', 'N/runtime'], function(file, log, email, runtime) {
    // Load the search results file and send an email with the file attached and
    // the number of rows in the file

    function execute(context) {
        // Read a CSV file and return the number of rows minus the header row
        function numberOfRows(csvFileId) {
            var invoiceFile = file.load({
                id: csvFileId
            });
            var iterator = invoiceFile.lines.iterator();
            var noOfLines = 0;

            // Skip the first row (the header row)
            iterator.each(function() {
                return false;
            });

            // Process the rest of the rows
            iterator.each(function() {
                noOfLines++;
                return true;
            });

            return noOfLines;
        }

        // Send an email to the user who ran the script, and attach the
        // CSV file with the search results
        function sendEmailWithAttachment(csvFileId) {
            var noOfRows = numberOfRows(csvFileId);
            var userId = runtime.getCurrentUser().id;
            var fileObj = file.load({
                id: csvFileId
            });

            email.send({
                author: userId,
                recipients: userId,
                subject: 'Search completed',
                body: 'CSV file attached, ' + noOfRows + ' record(s) found.',
                attachments: [fileObj]
            });
        }

        // Retrieve the ID of the search results file
        //
        // Update the name parameter to use the script ID of the original
        // search task
        var resFileId = runtime.getCurrentScript().getParameter({
            name: 'custscript_ss_as_srch_res'
        });

        if (!resFileId) {
            log.error('Could not obtain file content from the specified ID.');
            return;
        }

        log.debug({
            title: 'search - numberOfRows',
            details: numberOfRows(resFileId)
        });
        sendEmailWithAttachment(resFileId);
    }

    return {
        execute: execute
    };
}); 

          

To read the contents of the search results file in a dependent map/reduce script, consider the following script sample:

            /**
 * @NApiVersion 2.x
 * @NScriptType MapReduceScript
 * @NModuleScope SameAccount
 */
define(['N/runtime', 'N/file', 'N/log', 'N/email'], function(runtime, file, log, email) {
    // Load the search results file, count the number of letters in the file, and
    // store this count in another file

    function getInputData() {
        // Retrieve the ID of the search results file
        //
        // Update the completionScriptParameterName value to use the script
        // ID of the original search task
        var completionScriptParameterName = 'custscript_mr_as_srch_res';
        var resFileId = runtime.getCurrentScript().getParameter({
            name: completionScriptParameterName
        });

        if (!resFileId) {
            log.error({
                details: 'resFileId is not valid. Please check the script parameter stored in the completionScriptParameterName variable in getInputData().'
            });
        }

        return {
            type: 'file',
            id: resFileId
        };
    }

    function map(context) {
        var email = context.value.split(',')[1];
        if ("Email" !== email) {
            var splitEmail = email.split('@');
            context.write(splitEmail[splitEmail.length-1], 1);
        }
    }

    function reduce(context) {
        context.write(context.key, context.values.length);
    }

    function summarize(summary) {
        var type = summary.toString();
        log.audit({title: type + ' Usage Consumed ', details: summary.usage});
        log.audit({title: type + ' Concurrency Number ', details: summary.concurrency});
        log.audit({title: type + ' Number of Yields ', details: summary.yields});

        var contents = '';
        summary.output.iterator().each(function(key, value) {
            contents += (key + ' ' + value + '\n');
            return true;
        });

        // Create the output file
        //
        // Update the name parameter to use the file name of the output file
        var fileObj = file.create({
            name: 'domainCount.txt',
            fileType: file.Type.PLAINTEXT,
            contents: contents
        });

        // Specify the folder location of the output file, and save the file
        //
        // Update the fileObj.folder property with the ID of the folder in
        // the file cabinet that contains the output file
        fileObj.folder = -15;
        fileObj.save();
    }

    return {
        getInputData: getInputData,
        map: map,
        reduce: reduce,
        summarize: summarize
    };
}); 

          

Submit a Record Action Task and Check Status

The following sample shows how to submit a record action task and then check its status. For details about record action tasks, see task.RecordActionTask and task.RecordActionTaskStatus.

Note:

This sample script uses the require function so that you can copy it into the SuiteScript Debugger and test it. You must use the define function in an entry point script (the script you attach to a script record and deploy). For more information, see SuiteScript 2.x Script Basics and SuiteScript 2.x Script Types.

            /**
 * @NApiVersion 2.x
 */

require(['N/task'], function(task) {
    var recordActionTask = task.create({
        taskType: task.TaskType.RECORD_ACTION
    });
    recordActionTask.recordType = 'timebill';
    recordActionTask.action = 'approve';
    recordActionTask.params = [
        {recordId: 1, note: 'This is a note for 1'},
        {recordId: 5, note: 'This is a note for 5'},
        {recordId: 23, note: 'This is a note for 23'}
    ];

    var handle = recordActionTask.submit();

    var res = task.checkStatus({
        taskId: handle
    });   // Returns a RecordActionTaskStatus object
    log.debug('Initial status: ' + res.status);
}); 

          

General Notices