Map reduce script to re-sync orders with time out errors

The client would like to sync orders with a time-out error. We identify orders with time-out errors using a custom field in the item fulfillment record.

/**

 * @NApiVersion 2.1

 * @NScriptType MapReduceScript

 */

/*************************************************************************************

 ***********

 *

 * XSEED Education Pte Ltd​-IND-NS

 *

 * XSEED-534: E-shipz integration

 *

 *

 *************************************************************************************

 ***********

 *

 * Author: Jobin and Jismi IT Services LLP

 *

 * Date Created : 15-August-2023

 *

 * Description: This script is used to integrate order details to Eshipz portal and Output to be pushed back to Netsuite Item fulfillment(Orders in which time out error occured).

 *

 * REVISION HISTORY

 *

 * @version 1.0 XSEED-534: 15-August-2023: Created the initial build by JJ0177

 *

 *

 *************************************************************************************

 **********/

define([‘N/search’, ‘N/email’, ‘N/render’, ‘N/https’, ‘N/url’, ‘N/format’, ‘N/record’],

    (search, email, render, https, url, format, record) => {

        /**

         * Function to check whether the field has an empty value or not.

         * @param {parameter} parameter – fieldValue

         * @returns {boolean} true – if the value is not empty

         * @returns {boolean} false – if the value is empty

         */

        function checkForParameter(parameter) {

            try {

                if (parameter != “” && parameter != null && parameter != undefined && parameter != “null” && parameter != “undefined” && parameter != ” “ && parameter != false && parameter != && parameter != ‘ ‘) {

                    return true;

                } else {

                    return false;

                }

            }

            catch (e) {

                log.debug({

                    title: “Error @ empty check Function: “, details: e.name + ‘ : ‘ + e.message

                });

            }

        }

        /**

      * Function to fetch the carton internal id

      * @param {number} id -internal id of item fulfillment record

      * @returns {object} object containing carton id

      */

        function fetchCartonId(id) {

            try {

                let itemfulfillmentSearchObj = search.create({

                    type: “itemfulfillment”,

                    filters:

                        [

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

                            “AND”,

                            [“internalid”, “anyof”, id],

                            “AND”,

                            [“cogs”, “is”, “F”],

                            “AND”,

                            [“shipping”, “is”, “F”],

                        ],

                    columns:

                        [

                            search.createColumn({

                                name: “internalid”,

                                join: “CUSTRECORD_IF_CARTON_LINK”,

                                label: “Internal ID”

                            })

                        ]

                });

                let searchResultCount = itemfulfillmentSearchObj.runPaged().count;

                let cartonIdSpecificObj = [];

                if (searchResultCount > 0) {

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

                        let cartonsId = result.getValue({

                            name: “internalid”,

                            join: “CUSTRECORD_IF_CARTON_LINK”,

                            label: “Internal ID”

                        });

                        cartonIdSpecificObj.push(cartonsId)

                        return true;

                    });

                }

                return cartonIdSpecificObj;

            } catch (error) {

                log.error(“error@fetchCartonId”, error)

            }

        }

     /**

      * Function to fetch the carton internal id

      * @param {object} responseBody -response body

      *  @param {object} ifRec -item fulfillment record

      * @returns {object} object containing carton id

      */

        function processResponse(responseBody, ifRec) {

            try {

                let url = “https://track.eshipz.com/track?awb=”;

                let parentAwb = responseBody[0].label_meta.awb

                let trackingUrl = url + parentAwb

                let slugDetail = responseBody[0].slug;

                let labelUrl = responseBody[0].label_meta.url;

                let childwaybill = responseBody[0].label_meta.package_numbers

                record.submitFields({

                    type: record.Type.ITEM_FULFILLMENT,

                    id: ifRec.id,

                    values: {

                        custbody_if_parent_waybill_no: parentAwb,

                        custbody_courier_detail: slugDetail,

                        custbody_tracking_website: trackingUrl,

                        custbody_jj_is_synced_xseed534: true,

                        custbody_jj_master_label: labelUrl,

                        shipstatus: “C”,

                        custbody_integration_error:

                    },

                    options: {

                        enableSourcing: false,

                        ignoreMandatoryFields: true

                    }

                });

             

                if (checkForParameter(childwaybill)) {

                    let ifId=ifRec.id

                    let cartonId = fetchCartonId(ifId)

                    log.debug(“cartonId”,cartonId)

                    let remainingPackageSeries = [];

                    if (checkForParameter(cartonId)) {

                        for (let i = 0; i < childwaybill.length; i++) {

                            if (i < cartonId.length) {

                               // const id = cartonId[i];

                              const id = cartonId[i % cartonId.length];

                              log.debug(“id”,id)

                                let otherId = record.submitFields({

                                    type: ‘customrecord_carton_details’,

                                    id: id,

                                    values: {

                                        ‘custrecord_if_child_waybill_no’: childwaybill[i]

                                    }

                                });

                            } else {

                                remainingPackageSeries.push(childwaybill[i]);          

                            }

                        }

                    }

                    else {

                        remainingPackageSeries = childwaybill;

                    }

                    log.debug(“remainingPackageSeries”,remainingPackageSeries)

                    let newArray = remainingPackageSeries.join(‘,’);

                    log.debug(“newArray”,newArray)

                    record.submitFields({

                        type: record.Type.ITEM_FULFILLMENT,

                        id: ifRec.id,

                        values: {

                            ‘custbody_jj_package_series’: newArray,

                        },

                        options: {

                            enableSourcing: false,

                            ignoreMandatoryFields: true

                        }

                    });

                }

            } catch (error) {

                log.debug(“error@processResponse”, error)

            }

        }

        /**

         * 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 timeOutSpecificArray = [];

                var itemfulfillmentSearchObj = search.create({

                    type: “itemfulfillment”,

                    filters:

                        [

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

                            “AND”,

                            [“custbody_jj_is_timeout_occured”, “is”, “T”],

                            “AND”,

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

                            “AND”,

                            [“custbody_jj_is_synced_xseed534”, “is”, “F”]

                        ],

                    columns:

                        [

                            search.createColumn({ name: “tranid”, label: “Document Number” }),

                            search.createColumn({ name: “internalid”, label: “Internal ID” }),

                            search.createColumn({name: “custbody_jj_ezhipz_ref_num”, label: “E-shipz Reference Number”})

                        ]

                });

                let searchResultCount = itemfulfillmentSearchObj.runPaged().count;

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

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

                    let timeOutSpecificObj = {};

                    timeOutSpecificObj.timeOutSpecificObjDocNum = result.getValue({ name: “tranid”, label: “Document Number” });

                    timeOutSpecificObj.timeOutSpecificObjInternalId = result.getValue({ name: “internalid”, label: “Internal ID” });

                    timeOutSpecificObj.timeOutRefNum=result.getValue({name: “custbody_jj_ezhipz_ref_num”, label: “E-shipz Reference Number”})

                    timeOutSpecificArray.push(timeOutSpecificObj);

                    return true;

                });

                return timeOutSpecificArray;

            } catch (error) {

                log.debug(“error @getInput”, error);

                return [];

            }

        }

        /**

         * 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

         *   or processing

         * @since 2015.2

         */

        const reduce = (reduceContext) => {

            try {

                let dataObj = JSON.parse(reduceContext.values);

                let ifDocNum = dataObj.timeOutSpecificObjDocNum;

                let ifInternalId = dataObj.timeOutSpecificObjInternalId;

                let ifRefNum=dataObj.timeOutRefNum;

                log.debug(“ifDocNum”,ifDocNum)

                let getUrl = ‘https://app.eshipz.com/proconnect/api/v1/get-shipments?db_filters={“customer_referenc”:”‘ + ifRefNum + ‘”}’;

                let accessHeaders = {

                    ‘X-API-TOKEN’: ‘6362545a0afce014f8be7549’,

                    ‘Content-Type’: ‘application/json’,

                };

                let responses = https.get({

                    url: getUrl,

                    headers: accessHeaders,

                });

                log.debug(“responses”,responses)

                if (responses.code == 200) {

                    let responseBody = JSON.parse(responses.body)

                    log.debug(“responseBody.length”,responseBody.length)

                    let ifrecord = record.load({

                        type: record.Type.ITEM_FULFILLMENT,

                        id: ifInternalId,

                        isDynamic: true,

                    });

                    if(responseBody.length==0){

                        record.submitFields({

                            type: record.Type.ITEM_FULFILLMENT,

                            id: ifrecord.id,

                            values: {

                                ‘custbody_integration_error’: “Time out error occured due to large quantity is trying to sync with E-shipz”,

                                ‘shipstatus’: “B”

                            },

                            options: {

                                enableSourcing: false,

                                ignoreMandatoryFields: true

                            }

                        });

                    }

                 else if (checkForParameter(responseBody)) {

                    processResponse(responseBody, ifrecord);

                }

                   

                }

               else

                    if (responseBody.code != 200) {

                        let bodyObject = JSON.parse(responses.body);

                        let detailsArray = bodyObject.meta.details;

                        record.submitFields({

                            type: record.Type.ITEM_FULFILLMENT,

                            id: ifRec.id,

                            values: {

                                ‘custbody_integration_error’: detailsArray[2],

                                ‘shipstatus’: “B”

                            },

                            options: {

                                enableSourcing: false,

                                ignoreMandatoryFields: true

                            }

                        });

                    }

                 

            } catch (error) {

                log.error(“error @reduce”, error);

            }

        }

        return { getInputData, reduce }

    });

Leave a comment

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