Create and Submit a Task with Dependent Scripts

The following sample creates a scheduled script to send an email to a user with search results from a CSV file. It then creates a map/reduce script to process the search results. Finally, an asynchronous search task and adds the scheduled script task and the map/reduce task to the search task as dependent scripts. The script is 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.1
 * @NScriptType ScheduledScript
 */
define(['N/file', 'N/log', 'N/email', 'N/runtime'], (file, log, email, runtime) => {
  function execute (context) {
    // Read a csv file and return number of lines minus the header row.       
    function numberOfRows (csvFileId) {
      const invoiceFile = file.load({
        id: csvFileId
      })
      const iterator = invoiceFile.lines.iterator()
      let noOfLines = 0
      // Skip the first line (header)
      iterator.each(() => { return false })
      iterator.each(() => {
        noOfLines++
        return true
      })
      return noOfLines
    }

    // Sends an email to the user under whom the script is run with the
    // async search result csv attached.
    function sendEmailWithAttachement (csvFileId) {
      const noOfRows = numberOfRows(csvFileId)
      const userId = runtime.getCurrentUser().id
      const fileObj = file.load({
        id: csvFileId
      })
      email.send({
        author: userId,
        recipients: userId,
        subject: 'Search completed',
        body: 'Csv file attached, ' + noOfRows + ' record(s) found.',
        attachments: [fileObj]
      })
    }

    const resFileId = runtime.getCurrentScript().getParameter({
      name: 'custscript_ss_as_srch_res'
    }) // HARDCODED: script record parameter id - async search result file
    if (!resFileId) {
      log.error('Could not obtain file content from the specified id.')
      return
    }
    log.debug({
      title: 'search - numberOfRows',
      details: numberOfRows(resFileId)
    })
    sendEmailWithAttachement(resFileId)
  }

  return {
    execute: execute
  }
}) 

        

Map/reduce script:

          /**
 * @NApiVersion 2.1
 * @NScriptType MapReduceScript
 * @NModuleScope SameAccount
 */
define(['N/runtime', 'N/file', 'N/log', 'N/email'], (runtime, file, log, email) => {
  function getInputData () {
    const completionScriptParameterName = 'custscript_mr_as_srch_res' // HARDCODED: script record parameter id - async search result file
    const resFileId = runtime.getCurrentScript().getParameter({
      name: completionScriptParameterName
    })
    if (!resFileId) {
      log.error({
        details: 'resFileId is not valid, please check the script parameter stored via completionScriptParameterName variable in getInputData().'
      })
    }
    return {
      type: 'file',
      id: resFileId
    }
  }
 
  function map (context) {
    const email = context.value.split(',')[1]
    if (email !== 'Email') {
      const splitEmail = email.split('@')
      context.write(splitEmail[splitEmail.length - 1], 1)
    }
  }
 
  function reduce (context) {
    context.write(context.key, context.values.length)
  }
 
  function summarize (summary) {
    const 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 })
    let contents = ''
    summary.output.iterator().each((key, value) => {
      contents += (key + ' ' + value + '\n')
      return true
    })
    const fileObj = file.create({
      name: 'domainCount.txt', // HARDCODED: file which will contain processed search results
      fileType: file.Type.PLAINTEXT,
      contents: contents
    })
    fileObj.folder = -15 // HARDCODED: SuiteScripts folder - location of the file above
    fileObj.save()
  }
 
  return {
    getInputData: getInputData,
    map: map,
    reduce: reduce,
    summarize: summarize
  }
}) 

        

Declaring script tasks:

          /**
 * @NApiVersion 2.1
 */
require(['N/task'], (task) => {
  const asyncSearchResultFile = 'SuiteScripts/ExportFile.csv'
 
  // Declare completion task
  const 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 }
  
  // Declare another completion task
  const 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 }
 
  // Declare search task
  const asyncTask = task.create({
    taskType: task.TaskType.SEARCH
  })
  asyncTask.savedSearchId = 'customsearch35'
  asyncTask.filePath = asyncSearchResultFile
 
  // Add inbound dependencies to the search task before it is submitted
  asyncTask.addInboundDependency(scheduledScript)
  asyncTask.addInboundDependency(mapReduceScript)
 
  const asyncTaskId = asyncTask.submit()
}) 

        

General Notices