Populate body level location in Invoice record from related Item Fulfillment.

A map reduce script for auto populate the body level location in the invoice record from the line one of related item fulfillment record’s line level location.

/**

 * @NApiVersion 2.1

 * @NScriptType MapReduceScript

 */

define([‘N/record’, ‘N/runtime’, ‘N/search’],

  /**

 * @param{record} record

 * @param{runtime} runtime

 * @param{search} search

 */

  (record, runtime, search) => {

    /**

     * @description Retrieves the location from the first line of the specified item fulfillment record.

     * @param {string} itemFulfillmentId – The internal ID of the item fulfillment record.

     * @returns {string|null} The internal ID of the location from the first line of the item fulfillment record, or null if not found.

     */

    const getItemFulfillmentLocation = (itemFulfillmentId) => {

      let location;

      let itemFulfillmentSearchObj = search.create({

        type: “itemfulfillment”,

        filters: [

          [“internalid”, “anyof”, itemFulfillmentId]

        ],

        columns: [

          search.createColumn({

            name: “internalid”,

            summary: “GROUP”,

            label: “Internal ID”

          }),

          search.createColumn({

            name: “location”,

            summary: “GROUP”,

            label: “Location”

          })

        ]

      });

      itemFulfillmentSearchObj.run().each(function (result) {

        location = result.getValue({

          name: “location”,

          summary: “GROUP”,

          label: “Location”

        });

        return false;

      });

      return location;

    };

    /**

     * @description Retrieves the internal ID of an invoice record given its document number.

     * @param {string} invoiceDocumentNumber – The document number of the invoice.

     * @returns {string|null} The internal ID of the invoice, or null if not found.

     */

    const getInvoiceInternalId = (invoiceDocumentNumber) => {

      let invoiceId;

      let invoiceSearchObj = search.create({

        type: “invoice”,

        filters: [

          [“tranid”, “is”, invoiceDocumentNumber]

        ],

        columns: [

          search.createColumn({

            name: “internalid”,

            label: “Internal ID”

          })

        ]

      });

      invoiceSearchObj.run().each(function (result) {

        invoiceId = result.getValue({

          name: “internalid”,

          label: “Internal ID”

        });

        return false;

      });

      return invoiceId;

    };

    /**

     * Defines the function that is executed at the beginning of the map/reduce process and generates the input data.

     * @param {Object} inputContext

     * @param {boolean} inputContext.isRestarted – Indicates whether the current invocation of this function is the first

     *   invocation (if true, the current invocation is not the first invocation and this function has been restarted)

     * @param {Object} inputContext.ObjectRef – Object that references the input data

     * @typedef {Object} ObjectRef

     * @property {string|number} ObjectRef.id – Internal ID of the record instance that contains the input data

     * @property {string} ObjectRef.type – Type of the record instance that contains the input data

     * @returns {Array|Object|Search|ObjectRef|File|Query} The input data to use in the map/reduce process

     * @since 2015.2

     */

    const getInputData = (inputContext) => {

      try {

        let searchResultCount, invoiceInternalId, invoiceRef, locationInvoice;

        var itemfulfillmentSearchObj = search.create({

          type: “itemfulfillment”,

          filters:

            [

                [“type”, “anyof”, “ItemShip”],

                “AND”,

                [“subsidiary”, “anyof”, “3”],

                “AND”,

                [“status”, “anyof”, “ItemShip:C”],

                “AND”,

                [“mainline”, “is”, “T”],

                “AND”,

                [“custbody_jj_ee_invoice_reference”, “noneof”, “@NONE@”],

                “AND”,

                [“internalid”, “is”, “48647”]

            ],

          columns:

            [

              search.createColumn({

                name: “internalid”,

                summary: “GROUP”,

                label: “Internal ID”

              }),

              search.createColumn({

                name: “custbody_jj_ee_invoice_reference”,

                summary: “MAX”,

                label: “Invoice ref #”

              }),

              search.createColumn({

                name: “location”,

                join: “CUSTBODY_JJ_EE_INVOICE_REFERENCE”,

                summary: “GROUP”,

                label: “Location”

              })

            ]

        });

        let itemFulfillmentResultArray = [];

        searchResultCount = itemfulfillmentSearchObj.runPaged().count;

        log.debug(“itemfulfillmentSearchObj result count”, searchResultCount);

        itemfulfillmentSearchObj.run().each(function (result) {

          invoiceInternalId = result.getValue({

            name: “internalid”,

            summary: “GROUP”,

            label: “Internal ID”

          });

          invoiceRef = result.getValue({

            name: “custbody_jj_ee_invoice_reference”,

            summary: “MAX”,

            label: “Invoice ref #”

          });

          locationInvoice = result.getValue({

            name: “location”,

            join: “CUSTBODY_JJ_EE_INVOICE_REFERENCE”,

            summary: “GROUP”,

            label: “Location”

          })

          if (!locationInvoice) {

            itemFulfillmentResultArray.push({

              itemFulfillmentId: invoiceInternalId,

              invoiceRef: invoiceRef

            });

          }

          return true;

        });

        log.debug(“itemFulfillmentResultArray”, itemFulfillmentResultArray)

        return itemFulfillmentResultArray;

      } catch (e) {

        log.error(‘Error in getInputData stage’, e);

      }

    }

    /**

     * Defines the function that is executed when the reduce entry point is triggered. This entry point is triggered

     * automatically when the associated map stage is complete. This function is applied to each group in the provided context.

     * @param {Object} reduceContext – Data collection containing the groups to process in the reduce stage. This parameter is

     *   provided automatically based on the results of the map stage.

     * @param {Iterator} reduceContext.errors – Serialized errors that were thrown during previous attempts to execute the

     *   reduce function on the current group

     * @param {number} reduceContext.executionNo – Number of times the reduce function has been executed on the current group

     * @param {boolean} reduceContext.isRestarted – Indicates whether the current invocation of this function is the first

     *   invocation (if true, the current invocation is not the first invocation and this function has been restarted)

     * @param {string} reduceContext.key – Key to be processed during the reduce stage

     * @param {List<String>} reduceContext.values – All values associated with a unique key that was passed to the reduce stage

     *   for processing

     * @since 2015.2

     */

    const reduce = (reduceContext) => {

      try {

        reduceContext.values.forEach(value => {

          let searchResult = JSON.parse(value);

          log.debug(“searchResult”, searchResult)

          let itemFulfillmentId = searchResult.itemFulfillmentId;

          log.debug(“itemFulfillmentId”, itemFulfillmentId)

          let invoiceNumber = searchResult.invoiceRef;

          log.debug(“invoiceNumber”, invoiceNumber)

          let location, invoiceId;

          let invoiceDocumentNumber = invoiceNumber.replace(“Invoice #”, “”);

          log.debug(“Clean Invoice Number”, invoiceDocumentNumber);

          if (itemFulfillmentId) {

            location = getItemFulfillmentLocation(itemFulfillmentId);

          }

          if (invoiceDocumentNumber) {

            invoiceId = getInvoiceInternalId(invoiceDocumentNumber);

          }

          if (invoiceId && location) {

          // Update the Invoice with the location

          record.submitFields({

            type: record.Type.INVOICE,

            id: invoiceId,

            values: {

              location: location

            },

            options: {

              enableSourcing: false,

              ignoreMandatoryFields: true

            }

          });

          log.debug(`Updated Invoice ${invoiceId} with location ${location}`);

          }

          else {

            log.error(`Missing data for updating Invoice ${invoiceId}`, {

              invoiceId: invoiceId,

              location: location

            });

          }

        });

      } catch (e) {

        log.error(‘Error in reduce stage’, e);

      }

    }

    return { getInputData, reduce }

  });

Leave a comment

Your email address will not be published. Required fields are marked *