Available To Sell (ATS) Calculator

Jira Code: BPL-6, BPL-7

Dependency : moment.js

This will calculate the ATS (Available to Sell) quantity of items by considering all the Sales Order, Purchase Order, Current Inventory Quantity at each location for each bucket period.
Bucket Period is considered as the time between each successive Purchase Order.
ATS is similar to NetSuite ‘Available To Promise’ feature.
There is a Suitelet form which can be used to check the item ATS details for each item.

The Scheduled Script is used to calculate the ATS value for all the items under consideration.

There is a custom record which will store the BrandScope Credentials and Endpoints. This custom records will also store the Item Fields Names, Sales Order and Purchase Order Date fields which should be taken into consideration for the ATS Calculation.

There are custom records which will store the location and brand of items that should be taken under consideration for the scheduler.

The scheduler will calculate the ATS quantity for each item and store this in a custom record and after every item is processed it will be sent to BrandScope.

BPL-7 JJ BrandScope Logic.js (Custom Module)

/**
 * @NApiVersion 2.x
 * @NModuleScope SameAccount
 */
/*******************************************************************************
 * * Jobin & Jismi IT Services | BrandScope | Logic *
 * **************************************************************************
 *
 * Author: Jobin & Jismi IT Services LLP
 *
 * Date Created : 22-March-2019
 *
 * Created By: Manu Antony, Jobin & Jismi IT Services LLP
 *
 * REVISION HISTORY
 *
 *
 ******************************************************************************/
"use strict";
var BRANDSCOPE_SETUP = {
  brandscope_fields: {
    atstoken: "",
    atsendpoint: "",
    nsemployee: "-5"
  },
  item_fields: {
    sku: "internalid",
    color: "internalid",
    size: "internalid",
    brand: "internalid"
  },
  salesorder_fields: {
    date: "trandate"
  },
  purchaseorder_fields: {
    date: "duedate"
  },
  date_format: {
    ns_format: "",
    required_format: "DD/MM/YYYY"
  }
};

var PATH = {
  basePath: "/SuiteScripts/JJ BrandScope Dependencies/",
  suiteBundlePath: "/SuiteBundles/Bundle 274844/JJ BrandScope Dependencies/"
};
define(["N/search", 'N/config', "N/util", "N/log", './moment'],
  function (search, config, util, log, moment) {
    //Defining logger, to know log comes from this module
    var LOG = {
      debug: function (title, details) {
        log.debug("MODULE (BPL-7 JJ BrandScope Logic) : " + title, details);
      },
      error: function (title, details) {
        log.error("MODULE (BPL-7 JJ BrandScope Logic) : " + title, details);
      }
    };

    //To check whether a value exists in parameter
    function checkForParameter(parameter, parameterName) {
      if (parameter !== null && parameter !== undefined && parameter !== false && parameter !== "null" && parameter !== "undefined" && parameter !== "false" && parameter !== "" && parameter !== " ")
        return true;
      if (parameterName)
        LOG.debug("Empty Value found", "Empty Value for parameter " + parameterName);
      return false;
    }

    //To assign a default value if the it is empty
    function assignDefaultValue(value, defaultValue) {
      if (checkForParameter(value)) return value;
      return defaultValue;
    }

    //To reject predefined set of values
    function rejectThisValues(value) {
      var rejectObj = {
        null: true,
        undefined: true,
        NaN: true,
        0: true,
        false: true,
        "": true
      };
      return rejectObj[value] ? false : true;
    }

    //Common Try-Catch function
    function applyTryCatch(DATA_OBJ, NAME) {
      function tryCatch(myfunction, key) {
        return function () {
          try {
            return myfunction.apply(this, arguments);
          } catch (e) {
            LOG.error("error in " + key, e);
            return false;
          }
        };
      }
      for (var key in DATA_OBJ) {
        if (typeof DATA_OBJ[key] === "function") {
          DATA_OBJ[key] = tryCatch(DATA_OBJ[key], NAME + "." + key);
        }
      }
    }

    //Date Manipulation Logic using the functions from third party library moment.js
    var dateLogic = {
      isBetween: function (startDate, endDate, compareDate, type, edgecase) {
        /* edgecase are :
          '()' - default exclusive
          '(]' - right inclusive
          '[)' - left inclusive
          '[]' - all inclusive 
          */
        edgecase = assignDefaultValue(edgecase, "()").toString().trim();
        type = assignDefaultValue(type, "days").toString().trim();
        //If no CompareDate is given
        if (!checkForParameter(compareDate)) return false;
        //If no startDate or endDate are given
        if (!checkForParameter(startDate) && !checkForParameter(endDate))
          return false;
        startDate = startDate ? dateLogic.formatDateAsMoment(startDate) : false;
        endDate = endDate ? dateLogic.formatDateAsMoment(endDate) : false;
        compareDate = dateLogic.formatDateAsMoment(compareDate);
        //If there is StartDate but no EndDate is given
        if (checkForParameter(startDate) && !checkForParameter(endDate)) {
          if (edgecase === "[]" || edgecase === "[)")
            if (compareDate.isSame(startDate)) return true;
          if (compareDate.isAfter(startDate)) return true;
          return false;
        }
        //If there is EndDate but no StartDate is given
        if (!checkForParameter(startDate) && checkForParameter(endDate)) {
          if (edgecase === "[]" || edgecase === "(]")
            if (compareDate.isSame(endDate)) return true;
          if (compareDate.isBefore(endDate)) return true;
          return false;
        }

        return compareDate.isBetween(startDate, endDate, type, edgecase);
      },
      formatDateAsMoment: function (date) {
        //returns date as moment object
        return moment(date, BRANDSCOPE_SETUP.date_format.ns_format);
      },
      formatDate: function (date, type) {
        //returns date as specified string format
        return moment(date, BRANDSCOPE_SETUP.date_format.ns_format).format(type ? type : BRANDSCOPE_SETUP.date_format.ns_format);
      }
    };
    applyTryCatch(dateLogic, "dateLogic");

    //dataSets from saved Saved Search and formating Saved Search response
    var dataSets = {
      formatSavedSearch: function (savedSearchObj, savedSearchName, mergeObj, sendAsObjectIfSingleResult, prioritizeSingleValue) {
        //formating saved search result

        //Creating Column Names
        var columns = savedSearchObj.columns;
        var columnsData = {};
        columns.forEach(function (result, counter) {
          columnsData[result.label] = result;
        });
        //Paginating Results
        var searchPageRanges;
        try {
          searchPageRanges = savedSearchObj.runPaged({
            pageSize: 1000
          });
        } catch (err) {
          return mergeObj ? mergeObj : [];
        }
        if (searchPageRanges.pageRanges.length < 1)
          return mergeObj ? mergeObj : [];

        //Fetching Row Data
        var rowData = [],
          tempRow = {};
        for (var pageIndex = 0; pageIndex < searchPageRanges.pageRanges.length; pageIndex++)
          searchPageRanges.fetch({
            index: pageIndex
          }).data
          .forEach(function (result) {
            tempRow = undefined;
            tempRow = {};
            if (prioritizeSingleValue)
              for (var key in columnsData)
                tempRow[key] = result.getText(columnsData[key]) ? result.getText(columnsData[key]) : result.getValue(columnsData[key]);
            else
              for (var key in columnsData)
                tempRow[key] = {
                  value: result.getValue(columnsData[key]),
                  text: result.getText(columnsData[key])
                };
            if (mergeObj)
              if (util.isObject(mergeObj)) Object.assign(tempRow, mergeObj);
            rowData.push(tempRow);
          });
        if (sendAsObjectIfSingleResult)
          if (rowData.length === 1) return rowData[0];
        return rowData;
      },
      brandScopeSetup: function () {
        //searching BrandScope Setup
        var brandScopeSetupSearch = search.create({
          type: "customrecord_jj_bpl2_cust_brandsetup",
          filters: [
            ["isinactive", "is", "F"]
          ],
          columns: [
            search.createColumn({
              name: "custrecord_jj_bpl2_ats_token",
              label: "custrecord_jj_bpl2_ats_token" //"ATS TOKEN"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_ata_endpoint",
              label: "custrecord_jj_bpl2_ata_endpoint" // "ATS ENDPOINT"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_email_sender",
              label: "custrecord_jj_bpl2_email_sender" // "EMAIL SENDER(EMPLOYEE)"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_integration_field_id",
              label: "custrecord_jj_bpl2_integration_field_id" // "INTEGRATION FIELD ID"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_item_color_fieldid",
              label: "custrecord_jj_bpl2_item_color_fieldid" // "ITEM COLOUR FIELD ID"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_item_size_fieldid",
              label: "custrecord_jj_bpl2_item_size_fieldid" // "ITEM SIZE FIELD ID"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_item_brand_fieldid",
              label: "custrecord_jj_bpl2_item_brand_fieldid" // "ITEM BRAND FIELD ID"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_expected_ship_date",
              label: "custrecord_jj_bpl2_expected_ship_date" // "EXPECTED SHIP DATE FIELD ID"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_expectd_rec_ship_date",
              label: "custrecord_jj_bpl2_expectd_rec_ship_date" // "EXPECTED RECEIVED SHIP DATE FIELD ID"
            })
          ]
        });
        var searchResultCount = brandScopeSetupSearch.runPaged().count;
        LOG.debug("brandScopeSetupSearch result count", searchResultCount);
        return dataSets.formatSavedSearch(brandScopeSetupSearch, "brandScopeSetupSearch");
      },
      brandScopeLocation: function () {
        //searching BrandScope Location
        var brandScopeLocationSearch = search.create({
          type: "customrecord_jj_bpl2_brandscope_location",
          filters: [
            ["isinactive", "is", "F"]
          ],
          columns: [
            search.createColumn({
              name: "custrecord_jj_bpl2_location",
              sort: search.Sort.ASC,
              label: "Location"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_abbreviations",
              label: "Abbreviations"
            })
          ]
        });
        var searchResultCount = brandScopeLocationSearch.runPaged().count;
        LOG.debug("brandScopeLocationSearch result count", searchResultCount);
        return dataSets.formatSavedSearch(brandScopeLocationSearch, "brandScopeLocationSearch");
      },
      brandScopeBrand: function () {
        //searching BrandScope Brand
        var brandScopeBrandSearch = search.create({
          type: "customrecord_jj_bpl2_custbrandid",
          filters: [
            ["isinactive", "is", "F"]
          ],
          columns: [
            search.createColumn({
              name: "custrecord_jj_bpl2_brandlocation",
              sort: search.Sort.ASC,
              label: "Location"
            }),
            search.createColumn({
              name: "custrecord_jj_bpl2_brand",
              label: "Brand"
            })
          ]
        });
        var searchResultCount = brandScopeBrandSearch.runPaged().count;
        LOG.debug("brandScopeBrandSearch result count", searchResultCount);
        return dataSets.formatSavedSearch(brandScopeBrandSearch, "brandScopeBrandSearch");
      },
      brandScopeSchedulerDataSet: function () {
        //searching BrandScope Scheduler DateSet
        var brandScopeSchedulerDataSetSearch = search.create({
          type: "customrecord_jj_bpl7_brandscope_schedule",
          filters: [],
          columns: [
            search.createColumn({
              name: "internalid",
              sort: search.Sort.ASC,
              label: "Internal ID"
            }),
            search.createColumn({
              name: "custrecord_bpl7_scheduler_item",
              label: "Item"
            }),
            search.createColumn({
              name: "custrecord_bpl7_scheduler_data",
              label: "Data"
            })
          ]
        });
        var searchResultCount = brandScopeSchedulerDataSetSearch.runPaged().count;
        LOG.debug("brandScopeSchedulerDataSetSearch result count", searchResultCount);
        return dataSets.formatSavedSearch(brandScopeSchedulerDataSetSearch, "brandScopeSchedulerDataSetSearch");
      },
      approvedItems: function (INVENTORY_LOCATION, BRANDS) {
        //searching Items by Inventory Location and Brand
        var approvedItemsSearch = search.create({
          type: "item",
          filters: [
            ["custitem_jj_includebrandscope", "is", "T"], //Include In Brandscope Sync
            "AND",
            ["inventorylocation", "anyof", INVENTORY_LOCATION], //Inventory Location
            "AND",
            [BRANDSCOPE_SETUP.item_fields.brand, "anyof", BRANDS], //Brandfield from BranScope Setup
            "AND",
            ["isinactive", "is", "F"] //Inactive
          ],
          columns: [
            search.createColumn({
              name: "internalid",
              sort: search.Sort.ASC,
              label: "Internal ID"
            }),
            search.createColumn({
              name: "itemid",
              label: "Name"
            }),
            search.createColumn({
              name: "inventorylocation",
              label: "Inventory Location"
            }),
            search.createColumn({
              name: "formulatext",
              formula: "'ATS'",
              label: "Type"
            }),
            search.createColumn({
              name: "formulatext",
              formula: "'NetSuite'",
              label: "SourceSystem"
            }),
            search.createColumn({
              name: BRANDSCOPE_SETUP.item_fields.brand,
              label: "Brand"
            }),
            search.createColumn({
              name: BRANDSCOPE_SETUP.item_fields.sku,
              label: "Integration_ID"
            }),
            search.createColumn({
              name: "upccode",
              label: "Barcode"
            }),
            search.createColumn({
              name: "itemid",
              label: "ProductName"
            }),
            search.createColumn({
              name: BRANDSCOPE_SETUP.item_fields.color,
              label: "Color"
            }),
            search.createColumn({
              name: BRANDSCOPE_SETUP.item_fields.size,
              label: "Size"
            })
          ]
        });
        var searchResultCount = approvedItemsSearch.runPaged().count;
        LOG.debug("approvedItemsSearch result count", searchResultCount);
        return dataSets.formatSavedSearch(approvedItemsSearch, "approvedItemsSearch");
      },
      item: function (ITEM_ID, LOCATION_ID, dataObj) {
        //searching Items by Item Id and Inventory Location
        var itemSearchObj = search.create({
          type: "item",
          filters: [
            ["internalid", "is", ITEM_ID.toString().trim()],
            "AND",
            ["inventorylocation", "anyof", LOCATION_ID.toString().trim()]
          ],
          columns: [
            search.createColumn({
              name: "internalid",
              sort: search.Sort.ASC,
              label: "_internalid"
            }),
            search.createColumn({
              name: "itemid",
              label: "_itemid"
            }),
            search.createColumn({
              name: "displayname",
              label: "_displayname"
            }),
            search.createColumn({
              name: "upccode",
              label: "_itemfield"
            }),
            search.createColumn({
              name: BRANDSCOPE_SETUP.item_fields.sku,
              label: "_sku"
            }),
            search.createColumn({
              name: BRANDSCOPE_SETUP.item_fields.color,
              label: "_color"
            }),
            search.createColumn({
              name: BRANDSCOPE_SETUP.item_fields.size,
              label: "_size"
            }),
            search.createColumn({
              name: BRANDSCOPE_SETUP.item_fields.brand,
              label: "_brand"
            }),
            search.createColumn({
              name: "inventorylocation",
              label: "_locationfield"
            }),
            search.createColumn({
              name: "location",
              label: "_location"
            }),
            search.createColumn({
              name: "locationquantityavailable",
              label: "_totalqtyavailable"
            }),
            search.createColumn({
              name: "locationquantitybackordered",
              label: "_totalqtybackordered"
            }),
            search.createColumn({
              name: "locationquantitycommitted",
              label: "_totalqtycommitted"
            }),
            search.createColumn({
              name: "locationquantityonhand",
              label: "_totalqtyonhand"
            }),
            search.createColumn({
              name: "locationquantityonorder",
              label: "_totalqtyonorder"
            })
          ]
        });
        var searchResultCount = itemSearchObj.runPaged().count;
        LOG.debug("itemSearchObj result count", searchResultCount);
        return dataSets.formatSavedSearch(itemSearchObj, "itemSearchObj", dataObj, true, true);
      },
      purchaseOrder: function (ITEM_ID, LOCATION_ID) {
        //searching Purchase Order by Item Id and Inventory Location
        var DATE_FIELD = assignDefaultValue(BRANDSCOPE_SETUP.purchaseorder_fields.date, "duedate");
        var purchaseorderSearchObj = search.create({
          type: "purchaseorder",
          filters: [
            ["type", "anyof", "PurchOrd"], //Type	is Purchase Order
            "AND",
            ["status", "anyof", "PurchOrd:D", "PurchOrd:E", "PurchOrd:B"], //Status	is any of Purchase Order:Partially Received, Purchase Order:Pending Billing/Partially Received, Purchase Order:Pending Receipt
            "AND",
            ["mainline", "is", "F"], //Main Line	is false
            "AND",
            ["location", "anyof", LOCATION_ID.toString().trim()],
            "AND",
            ["item", "anyof", ITEM_ID.toString().trim()]
          ],
          columns: [
            search.createColumn({
              name: "internalid",
              summary: "GROUP",
              label: "internalid" //Internal ID
            }),
            search.createColumn({
              name: "tranid",
              summary: "GROUP",
              label: "tranid" //Document Number
            }),
            search.createColumn({
              name: "statusref",
              summary: "MAX",
              label: "status" //Status
            }),
            search.createColumn({
              name: "item",
              summary: "MAX",
              label: "item" //Item
            }),
            search.createColumn({
              name: "trandate",
              summary: "MAX",
              label: "trandate" //Date
            }),
            search.createColumn({
              name: "duedate",
              summary: "MAX",
              label: "duedate" //	Due Date/Receive By
            }),
            search.createColumn({
              name: DATE_FIELD,
              summary: "MAX",
              sort: search.Sort.ASC,
              label: "DATE_FIELD" //Date Field mentioned in BrandScope Setup
            }),
            search.createColumn({
              name: "location",
              summary: "GROUP",
              label: "location" //Location
            }),
            search.createColumn({
              name: "quantity",
              summary: "SUM",
              label: "quantity" //Quantity
            }),
            search.createColumn({
              name: "quantityshiprecv",
              summary: "SUM",
              label: "quantityshiprecv" //Quantity Fulfilled/Received
            }),
            search.createColumn({
              name: "formulanumeric",
              summary: "SUM",
              formula: "{quantity}-nvl({quantityshiprecv},0)",
              label: "quantityremaining" //Quantity Remaining
            })
          ]
        });
        var searchResultCount = purchaseorderSearchObj.runPaged().count;
        LOG.debug("purchaseorderSearchObj result count", searchResultCount);
        return dataSets.formatSavedSearch(purchaseorderSearchObj, "purchaseorderSearchObj");
      },
      salesOrder: function (ITEM_ID, LOCATION_ID, FIRST_PURCHASE_ORDER_DATE) {
        //searching Sales Order by Item Id and Inventory Location
        var DATE_FIELD = assignDefaultValue(BRANDSCOPE_SETUP.salesorder_fields.date, "trandate").toString().trim();

        if (FIRST_PURCHASE_ORDER_DATE)
          FIRST_PURCHASE_ORDER_DATE = moment(FIRST_PURCHASE_ORDER_DATE, BRANDSCOPE_SETUP.date_format.ns_format).format('MM/DD/YYYY');

        var QTY_REMAINING_FORMULA = '';

        if (FIRST_PURCHASE_ORDER_DATE)
          QTY_REMAINING_FORMULA = "CASE WHEN {" + DATE_FIELD + "}<TO_DATE('" + FIRST_PURCHASE_ORDER_DATE + "','MM/DD/YYYY') THEN (CASE WHEN(nvl({quantitycommitted}, 0) + nvl({quantityshiprecv}, 0) + {quantity} - nvl({quantityshiprecv}, 0) - nvl({quantitycommitted}, 0)) = 0 THEN {quantity} ELSE({quantity} - nvl({quantityshiprecv}, 0) - nvl({quantitycommitted}, 0)) END) ELSE ({quantity}-nvl({quantityshiprecv}, 0)) END"; //IF(DATE_FIELD<FIRST_PURCHASE_ORDER_DATE) THEN (IF (COMITTED + BACKORDERD + FULFILLED = 0) THEN QUANTITY ELSE BACKORDERD) ELSE (QUANTITY - FULFILLED)
        else
          QTY_REMAINING_FORMULA = "CASE WHEN (nvl({quantitycommitted},0)+nvl({quantityshiprecv},0)+{quantity}-nvl({quantityshiprecv},0)-nvl({quantitycommitted},0))=0 THEN {quantity} ELSE ({quantity}-nvl({quantityshiprecv},0)-nvl({quantitycommitted},0)) END"; //IF COMITTED + BACKORDERD + FULFILLED = 0 , THEN QUANTITY ELSE BACKORDERD

        var salesorderSearchObj = search.create({
          type: "salesorder",
          filters: [
            ["type", "anyof", "SalesOrd"], //Type	is Sales Order
            "AND",
            ["status", "anyof", "SalesOrd:D", "SalesOrd:A", "SalesOrd:E", "SalesOrd:B"], //Status	is any of Sales Order:Partially Fulfilled, Sales Order:Pending Approval, Sales Order:Pending Billing/Partially Fulfilled, Sales Order:Pending Fulfillment
            "AND",
            ["mainline", "is", "F"], //Main Line	is false
            "AND",
            ["location", "anyof", LOCATION_ID.toString().trim()],
            "AND",
            ["item", "anyof", ITEM_ID.toString().trim()]
          ],
          columns: [
            search.createColumn({
              name: "internalid",
              summary: "GROUP",
              label: "internalid" //Internal ID
            }),
            search.createColumn({
              name: "tranid",
              summary: "GROUP",
              label: "tranid" //Document Number
            }),
            search.createColumn({
              name: "statusref",
              summary: "MAX",
              label: "status" //Status
            }),
            search.createColumn({
              name: "item",
              summary: "MAX",
              label: "item" //Item
            }),
            search.createColumn({
              name: "trandate",
              summary: "MAX",
              label: "trandate" //Date
            }),
            search.createColumn({
              name: DATE_FIELD,
              summary: "MAX",
              sort: search.Sort.ASC,
              label: "DATE_FIELD" //Date Field mentioned in BrandScope Setup
            }),
            search.createColumn({
              name: "location",
              summary: "GROUP",
              label: "location" //Location
            }),
            search.createColumn({
              name: "quantity",
              summary: "SUM",
              label: "quantity" //Quantity
            }),
            search.createColumn({
              name: "quantityshiprecv",
              summary: "SUM",
              label: "quantityshiprecv" //Quantity Fulfilled/Received
            }),
            search.createColumn({
              name: "quantitycommitted",
              summary: "SUM",
              label: "quantitycommitted" //Quantity Committed
            }),
            search.createColumn({
              name: "formulanumeric",
              summary: "SUM",
              formula: " {quantity}-nvl({quantityshiprecv},0)-nvl({quantitycommitted},0)",
              label: "quantitybackordered" //Quantity Backordered
            }),
            search.createColumn({
              name: "formulanumeric",
              summary: "SUM",
              formula: QTY_REMAINING_FORMULA,
              label: "quantityremaining" //Quantity Remaining With OffSet
            })
          ]
        });
        var searchResultCount = salesorderSearchObj.runPaged().count;
        LOG.debug("salesorderSearchObj result count", searchResultCount);
        return dataSets.formatSavedSearch(salesorderSearchObj, "salesorderSearchObj");
      }
    };
    applyTryCatch(dataSets, "dataSets");

    //Manipulating and formating Dataset
    var dataManipulate = {
      initialiseBrandScopeSetup: function (brandScopeSetup) {
        //Initialise BrandScope environment by fetching NetSuite Field Id's and Date Format

        //USER_PREFERENCES
        var USER_PREFERENCES = config.load({
          type: config.Type.USER_PREFERENCES
        });
        var USER_PREFERENCES_DATEFORMAT = USER_PREFERENCES.getValue({
          fieldId: 'DATEFORMAT'
        });
        USER_PREFERENCES_DATEFORMAT = USER_PREFERENCES_DATEFORMAT.toString().trim().replace(/fm/gi, "").replace(/fd/gi, "").replace(/fy/gi, "").replace(/fn/gi, "");
        //COMPANY_PREFERENCES
        var COMPANY_PREFERENCES = config.load({
          type: config.Type.COMPANY_PREFERENCES
        });
        var COMPANY_PREFERENCES_DATEFORMAT = COMPANY_PREFERENCES.getValue({
          fieldId: 'DATEFORMAT'
        });
        COMPANY_PREFERENCES_DATEFORMAT = COMPANY_PREFERENCES_DATEFORMAT.toString().trim().replace(/fm/gi, "").replace(/fd/gi, "").replace(/fy/gi, "").replace(/fn/gi, "");

        BRANDSCOPE_SETUP = {
          brandscope_fields: {
            atstoken: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_ats_token.value, ""),
            atsendpoint: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_ata_endpoint.value, ""),
            nsemployee: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_email_sender.value, "-5")
          },
          item_fields: {
            sku: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_integration_field_id.value, "internalid"),
            color: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_item_color_fieldid.value, "internalid"),
            size: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_item_size_fieldid.value, "internalid"),
            brand: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_item_brand_fieldid.value, "internalid"),
          },
          salesorder_fields: {
            date: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_expected_ship_date.value, "trandate")
          },
          purchaseorder_fields: {
            date: assignDefaultValue(brandScopeSetup.custrecord_jj_bpl2_expectd_rec_ship_date.value, "duedate")
          },
          date_format: {
            ns_format: assignDefaultValue(COMPANY_PREFERENCES_DATEFORMAT),
            required_format: "DD/MM/YYYY"
          }
        };
        return true;
      },
      findFirstPurchaseOrderDate: function (dataObj, PO_ARRAY) {
        //returns first future dated purchase order date
        var FIRST_PURCHASE_ORDER_DATE = false;
        for (var index = 0, len = PO_ARRAY.length; index < len; index++) {
          if (dateLogic.isBetween(dataObj._atoncedate, false, PO_ARRAY[index].DATE_FIELD.value, "days", "()")) { //Future Dated Purchase Order created after today
            FIRST_PURCHASE_ORDER_DATE = PO_ARRAY[index].DATE_FIELD.value;
            break;
          }
        }
        return FIRST_PURCHASE_ORDER_DATE;
      },
      findOffset: function (dataObj, SO_ARRAY, PO_ARRAY) {
        //calculate OffSet Qunatity
        if (SO_ARRAY.length < 1) return "0";
        var FIRST_PURCHASE_ORDER_DATE = PO_ARRAY.length > 0 ? dataManipulate.findFirstPurchaseOrderDate(dataObj, PO_ARRAY) : false;
        if (!FIRST_PURCHASE_ORDER_DATE) return "0";
        var OFFSET = 0;
        for (var index = 0, len = SO_ARRAY.length; index < len; index++) {
          //if no value is given for the date field, skip that iteration
          if (!checkForParameter(SO_ARRAY[index].DATE_FIELD.value)) continue;
          if (dateLogic.isBetween(FIRST_PURCHASE_ORDER_DATE, false, SO_ARRAY[index].DATE_FIELD.value, "days", "[)")) //Offset is Calulated by taking All Sales Order created on or after first future dated purchase order
            OFFSET += Number(assignDefaultValue(SO_ARRAY[index].quantitycommitted.value, 0));
        }
        return OFFSET.toString();
      },
      findUnreceivedPastPurchaseOrder: function (dataObj, PO_ARRAY) {
        //Calculate the remaining qunaity of past dated (and present) pending Purchase Order
        if (PO_ARRAY.length < 1) return Number(0).toString();
        var filteredArray = PO_ARRAY.filter(function (result) {
          return dateLogic.isBetween(false, dataObj._atoncedate, result.DATE_FIELD.value, "days", "(]"); //Past Dated Purchase order including today
        });
        if (filteredArray.length > 0)
          return assignDefaultValue(filteredArray.reduce(function (accumulator, currentValue) {
            return (Number(accumulator) + Number(currentValue.quantityremaining.value));
          }, 0), 0).toString();
        return Number(0).toString();
      },
      createSortedDateArray: function (dataObj, PO_ARRAY) {
        //creates Sorted Date Array
        var DATE_ARRAY = [],
          skipDuplicateDate = {};
        DATE_ARRAY.push(dataObj._atoncedate);
        skipDuplicateDate[dataObj._atoncedate] = true;
        for (var index = 0, len = PO_ARRAY.length; index < len; index++)
          if (dateLogic.isBetween(dataObj._atoncedate, false, PO_ARRAY[index].DATE_FIELD.value, "days", "()")) //Skip all past dated Purchase Order including today
            if (!skipDuplicateDate[PO_ARRAY[index].DATE_FIELD.value]) {
              DATE_ARRAY.push(PO_ARRAY[index].DATE_FIELD.value);
              skipDuplicateDate[PO_ARRAY[index].DATE_FIELD.value] = true;
            }
        return DATE_ARRAY;
      },
      createBucket: function (dataObj, SO_ARRAY, PO_ARRAY) {
        //Create periods as Bucket and assigns value into each Bucket Array
        var DATE_ARRAY = dataManipulate.createSortedDateArray(dataObj, PO_ARRAY);
        var BUCKET = {};
        for (var dateIndex = 0, dateLen = DATE_ARRAY.length; dateIndex < dateLen; dateIndex++) {
          BUCKET[DATE_ARRAY[dateIndex]] = [];
          for (var soIndex = 0, soLen = SO_ARRAY.length; soIndex < soLen; soIndex++) {
            if (dateIndex == 0) { //if date is start date or atonce date
              if (dateLen > 1) { //atleast one future purchase order exist
                if (dateLogic.isBetween(false, DATE_ARRAY[dateIndex + 1], SO_ARRAY[soIndex].DATE_FIELD.value, "days", "[)")) //end date will be future purchase order
                  BUCKET[DATE_ARRAY[dateIndex]].push(SO_ARRAY[soIndex]);
              } else if (dateLogic.isBetween(false, DATE_ARRAY[dateIndex], SO_ARRAY[soIndex].DATE_FIELD.value, "days", "[]")) //no future purchase order exist,end date will be start date or atonce date
                BUCKET[DATE_ARRAY[dateIndex]].push(SO_ARRAY[soIndex]);
            } else if (dateLen > 1 && dateIndex == (dateLen - 1)) { //if date is end date or last purchase order date and atleast one future purchase order exist
              if (dateLogic.isBetween(DATE_ARRAY[dateIndex], false, SO_ARRAY[soIndex].DATE_FIELD.value, "days", "[)"))
                BUCKET[DATE_ARRAY[dateIndex]].push(SO_ARRAY[soIndex]);
            } else { //if date is inbetween purchase order date bucket
              if (dateLogic.isBetween(DATE_ARRAY[dateIndex], DATE_ARRAY[dateIndex + 1], SO_ARRAY[soIndex].DATE_FIELD.value, "days", "[)"))
                BUCKET[DATE_ARRAY[dateIndex]].push(SO_ARRAY[soIndex]);
            }
          }
        }
        return {
          DATE_ARRAY: DATE_ARRAY,
          BUCKET: BUCKET
        };
      },
      consolidatePurchaseOrderByDate: function (dataObj, PO_ARRAY) {
        //Consolidate Purchase Order by Bucket(date)
        var CONSOLIDATED_PO_OBJECT = {};
        for (var index = 0, len = PO_ARRAY.length; index < len; index++)
          if (dateLogic.isBetween(dataObj._atoncedate, false, PO_ARRAY[index].DATE_FIELD.value, "days", "()")) { //Include only future date Purchase Order excluding today
            if (!CONSOLIDATED_PO_OBJECT[PO_ARRAY[index].DATE_FIELD.value])
              CONSOLIDATED_PO_OBJECT[PO_ARRAY[index].DATE_FIELD.value] = {
                date: PO_ARRAY[index].DATE_FIELD.value,
                quantityremaining: 0
              };
            CONSOLIDATED_PO_OBJECT[PO_ARRAY[index].DATE_FIELD.value].quantityremaining += Number(assignDefaultValue(PO_ARRAY[index].quantityremaining.value, 0));
          }
        return CONSOLIDATED_PO_OBJECT;
      },
      consolidateSalesOrderByBucket: function (dataObj, DATE_ARRAY, BUCKET) {
        //Consolidate Sales Order by Bucket(date)
        var CONSOLIDATED_SO_OBJECT = {};
        for (var dateIndex = 0, dateLen = DATE_ARRAY.length; dateIndex < dateLen; dateIndex++) {
          if (!CONSOLIDATED_SO_OBJECT[DATE_ARRAY[dateIndex]])
            CONSOLIDATED_SO_OBJECT[DATE_ARRAY[dateIndex]] = {
              date: DATE_ARRAY[dateIndex] + (dateIndex == 0 ? ' (AtOnce)' : ''),
              quantityremaining: 0
            };
          for (var bucketIndex = 0, bucketLen = BUCKET[DATE_ARRAY[dateIndex]].length; bucketIndex < bucketLen; bucketIndex++) {
            CONSOLIDATED_SO_OBJECT[DATE_ARRAY[dateIndex]].quantityremaining += Number(assignDefaultValue(BUCKET[DATE_ARRAY[dateIndex]][bucketIndex].quantityremaining.value, 0));
          }
        }
        return CONSOLIDATED_SO_OBJECT;
      },
      calculateATS: function (dataObj, DATE_ARRAY, BUCKET, PO_ARRAY, isForm) {
        //Calculate ATS qunatity and ATS Object
        var CONSOLIDATED_PO_OBJECT = dataManipulate.consolidatePurchaseOrderByDate(dataObj, PO_ARRAY);
        LOG.debug('CONSOLIDATED_PO_OBJECT', CONSOLIDATED_PO_OBJECT);
        var CONSOLIDATED_SO_OBJECT = dataManipulate.consolidateSalesOrderByBucket(dataObj, DATE_ARRAY, BUCKET);
        LOG.debug('CONSOLIDATED_SO_OBJECT', CONSOLIDATED_SO_OBJECT);
        var ATS = [],
          tempObj = {},
          summaryObj = {},
          brandScopeATSObj = {},
          eachSummaryCount = 0;
        var CARRY_FORWARD = -0;
        for (var index = 0, len = DATE_ARRAY.length; index < len; index++) {
          tempObj["Date"] = index == 0 ? "AtOnce" : DATE_ARRAY[index];
          tempObj["Carry_Forward"] = 0;
          tempObj["ATS"] = 0;
          //Adding Previous Carry Forward to ATS
          tempObj["ATS"] += CARRY_FORWARD;

          if (index == 0) //if AtOnce or Current Date, ATS will be ( Quantity Available - Quantity BackOrdered )
            tempObj["ATS"] += Number(assignDefaultValue(dataObj._qtyavailable, 0)) - Number(assignDefaultValue(dataObj._qtybackordered, 0));
          if (index == 1) //if First Future Purchase Order Date, ATS will have Sum of Remaining Quantities in Past Dated Purchase Order
            tempObj["ATS"] += Number(assignDefaultValue(dataObj._totalpastpurchaseorder, 0));

          if (CONSOLIDATED_PO_OBJECT[DATE_ARRAY[index]]) //If there exists Purchase Order/s on this date, then the quantity remaining will be added to ATS
            tempObj["ATS"] += Number(assignDefaultValue(CONSOLIDATED_PO_OBJECT[DATE_ARRAY[index]].quantityremaining, 0));
          if (CONSOLIDATED_SO_OBJECT[DATE_ARRAY[index]] && len > 1) //If there exists Sales Order on this date, then Substract Sales Order Remaining Quantity only if there exists a Future Dated Purchase Order , ie OFFSET is not calculated if there isn't any Future Dated Purchase Order
            tempObj["ATS"] -= Number(assignDefaultValue(CONSOLIDATED_SO_OBJECT[DATE_ARRAY[index]].quantityremaining, 0));

          //If request is from Suitelet Form,then generate Summary to be shown in Suitelet Form
          if (isForm) {
            eachSummaryCount = 0;
            summaryObj = {
              'SO_QUANTITY': (CONSOLIDATED_SO_OBJECT[DATE_ARRAY[index]] && len > 1) ? -Number(assignDefaultValue(CONSOLIDATED_SO_OBJECT[DATE_ARRAY[index]].quantityremaining, 0)) : 0,
            };
            if (index > 0) {
              summaryObj['PO_QUANTITY'] = (CONSOLIDATED_PO_OBJECT[DATE_ARRAY[index]]) ? Number(assignDefaultValue(CONSOLIDATED_PO_OBJECT[DATE_ARRAY[index]].quantityremaining, 0)) : 0;
              summaryObj['CARRY_FORWARD (Previous Bucket)'] = CARRY_FORWARD;
            }

            if (index == 0) {
              summaryObj["QUANTITY AVAILABLE"] = Number(assignDefaultValue(dataObj._qtyavailable, 0));
              summaryObj["QUANTITY BACKORDERED"] = -Number(assignDefaultValue(dataObj._qtybackordered, 0));
            }
            if (index == 1)
              summaryObj["UNRECEIVED PAST PURCHASE ORDER"] = Number(assignDefaultValue(dataObj._totalpastpurchaseorder, 0));

            tempObj["Summary"] = '';
            for (var key in summaryObj) {
              eachSummaryCount += summaryObj[key];
              tempObj["Summary"] += key.toString() + ' = ' + summaryObj[key].toString() + '<br/>';
            }
            if (eachSummaryCount >= 0)
              tempObj["Summary"] += '<span style="font-weight:bold;" >Net Value = ' + '<span style="color:green;" >' + eachSummaryCount.toString() + '</span>' + '</span>';
            else
              tempObj["Summary"] += '<span style="font-weight:bold;" >Net Value = ' + '<span style="color:red;" >' + eachSummaryCount.toString() + '</span>' + '</span>';
            summaryObj = undefined;
            summaryObj = {};
          }

          //ATS Value will always be greater than or equal to Zero. If the calculated ATS Value is negative, we will assign that value to Carry Forward and make ATS value as zero
          if (tempObj["ATS"] < 0) {
            tempObj["Carry_Forward"] = tempObj["ATS"];
            tempObj["ATS"] = 0;
            CARRY_FORWARD = tempObj["Carry_Forward"];
          } else {
            tempObj["Carry_Forward"] = 0;
            CARRY_FORWARD = 0;
          }

          tempObj["ATS"] = tempObj["ATS"].toString();
          tempObj["Carry_Forward"] = tempObj["Carry_Forward"].toString();

          //If request is from Suitelet Form,then generate ATS array else generate BrandScope Object
          if (isForm)
            ATS.push(tempObj);
          else {
            if (index > 0) //If not AtOnce or current Date
              brandScopeATSObj[dateLogic.formatDate(tempObj["Date"], BRANDSCOPE_SETUP.date_format.required_format)] = tempObj["ATS"];
            else
              brandScopeATSObj["At Once"] = tempObj["ATS"];
          }

          tempObj = undefined;
          tempObj = {};
        }
        if (isForm)
          LOG.debug('ATS array for Suitelet', ATS);
        else
          LOG.debug('brandScopeATSObj for Scheduler', brandScopeATSObj);

        //If request is from Suitelet Form,then return ATS array else return BrandScope Object
        if (isForm)
          return ATS;
        else
          return brandScopeATSObj;
      }
    };
    applyTryCatch(dataManipulate, "dataManipulate");

    //Main or Root Function of this Custom Module. This will be the function(Object) that will be exposed to user(public)
    var main = {
      moment: moment, //exposing third party library in custom module
      dateLogic: dateLogic, //exposing private functions in custom module
      dataSets: dataSets, //exposing private functions in custom module
      dataManipulate: dataManipulate, //exposing private functions in custom module
      initialise: function () {
        //Trigger initialse BrandScope Environment
        var brandScopeSetup = dataSets.brandScopeSetup();
        if (brandScopeSetup.length)
          return dataManipulate.initialiseBrandScopeSetup(brandScopeSetup[0]);
        return false;
      },
      getBrandScopeSetup: function () {
        //retun BrandScope Environment
        return BRANDSCOPE_SETUP;
      },
      cleanSlate: function (dataObj) {
        //rreinitialsie Object Properties (variables)
        return {
          _internalid: dataObj._internalid,
          _itemfield: dataObj._itemfield,
          _locationfield: dataObj._locationfield
        };
      },
      generateFormValues: function (dataObj) {
        //if request is from Suitelet, then retun entire dataset
        return main.generateATSValue(dataObj, true);
      },
      generateSchedulerValues: function (dataObj) {
        //if request is from Scheduled Script, then return only the neccessary data
        return main.generateATSValue(dataObj);
      },
      generateATSValue: function (dataObj, isForm) {
        //Tirggering all prerequisite functions and then proceed with ATS calculation

        //Cleaning dataObj and resetting it with only the neccassary values
        dataObj = main.cleanSlate(dataObj);
        var purchaseOrderArray = [],
          FIRST_PURCHASE_ORDER_DATE = false,
          salesOrderArray = [],
          mappedATS = [],
          bucketPeriod = {
            DATE_ARRAY: [],
            BUCKET: {}
          };
        //Setting AtOnce Date
        dataObj._atoncedate = dateLogic.formatDate(moment(), BRANDSCOPE_SETUP.date_format.ns_format);
        //Fetching Item Details
        dataObj = dataSets.item(dataObj._internalid, dataObj._locationfield, dataObj);
        //Fetching Purchase Order Details
        purchaseOrderArray = dataSets.purchaseOrder(dataObj._internalid, dataObj._locationfield);
        FIRST_PURCHASE_ORDER_DATE = purchaseOrderArray.length > 0 ? dataManipulate.findFirstPurchaseOrderDate(dataObj, purchaseOrderArray) : false;
        //Fetching Sales Order Details
        salesOrderArray = dataSets.salesOrder(dataObj._internalid, dataObj._locationfield, FIRST_PURCHASE_ORDER_DATE);
        //Calculating OffSet
        dataObj._totaloffset = dataManipulate.findOffset(dataObj, salesOrderArray, purchaseOrderArray);
        //Calculating Past Purchase Order
        dataObj._totalpastpurchaseorder = dataManipulate.findUnreceivedPastPurchaseOrder(dataObj, purchaseOrderArray);
        //Initialse dataObj with the inventory details 
        var initialiseFields = ["_totalqtyavailable", "_totalqtycommitted", "_totalqtybackordered", "_totalqtyonorder"].concat(["_totaloffset", "_totalpastpurchaseorder", "_qtyavailable", "_qtycommitted", "_qtybackordered"]);
        for (var index = 0, len = initialiseFields.length; index < len; index++)
          if (!checkForParameter(dataObj[initialiseFields[index]]))
            dataObj[initialiseFields[index]] = "0";

        //Reflecting real NetSuite Inventory Details by taking into account OffSet value
        //Calculating Quantity Comitted by taking in OffSet
        dataObj._qtycommitted = (Number(dataObj._totalqtycommitted) - Number(dataObj._totaloffset)).toString();
        //Calculating Quantity Available and Quantity Backordered
        if (Number(dataObj._totaloffset) + Number(dataObj._totalqtyavailable) - Number(dataObj._totalqtybackordered) >= Number(0)) {
          dataObj._qtyavailable = (Number(dataObj._totaloffset) + Number(dataObj._totalqtyavailable) - Number(dataObj._totalqtybackordered)).toString();
          dataObj._qtybackordered = "0";
        } else {
          dataObj._qtyavailable = "0";
          dataObj._qtybackordered = Math.abs(Number(dataObj._totaloffset) + Number(dataObj._totalqtyavailable) - Number(dataObj._totalqtybackordered)).toString();
        }
        //Creating Bucket Period
        bucketPeriod = dataManipulate.createBucket(dataObj, salesOrderArray, purchaseOrderArray);
        //Creating ATS Object
        mappedATS = dataManipulate.calculateATS(dataObj, bucketPeriod.DATE_ARRAY, bucketPeriod.BUCKET, purchaseOrderArray, isForm);


        LOG.debug("dataObj", dataObj);
        LOG.debug("bucketPeriod.DATE_ARRAY", bucketPeriod.DATE_ARRAY);
        LOG.debug("bucketPeriod.BUCKET", bucketPeriod.BUCKET);
        LOG.debug("BRANDSCOPE_SETUP", BRANDSCOPE_SETUP);

        if (isForm) //If request is from Suitelet form return all the neccessary values for setting up the form else return only the mapped ATS Value
          return {
            dataObj: dataObj,
            purchaseOrderArray: purchaseOrderArray,
            salesOrderArray: salesOrderArray,
            bucketPeriod: bucketPeriod,
            mappedATS: mappedATS
          };
        return mappedATS;
      }
    };
    applyTryCatch(main, "main");


    return main;
  });

if (!Array.prototype.push) {
  Array.prototype.push = function (x) {
    this[this.length] = x;
    return true;
  };
}
if (!Array.prototype.pop) {
  Array.prototype.pop = function () {
    var response = this[this.length - 1];
    this.length--;
    return response;
  };
}
if (!Array.prototype.remove) {
  Array.prototype.remove = function (from, to) {
    var rest = this.slice(parseInt(to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
  };
}
if (typeof Object.assign != "function") {
  Object.defineProperty(Object, "assign", {
    value: function assign(target, varArgs) {
      "use strict";
      if (target == null) {
        throw new TypeError("Cannot convert undefined or null to object");
      }
      var to = Object(target);
      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];
        if (nextSource != null) {
          for (var nextKey in nextSource) {
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
    writable: true,
    configurable: true
  });
}
if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, "reduce", {
    value: function (callback /*, initialValue*/ ) {
      if (this === null) {
        throw new TypeError(
          "Array.prototype.reduce " + "called on null or undefined"
        );
      }
      if (typeof callback !== "function") {
        throw new TypeError(callback + " is not a function");
      }
      var o = Object(this);
      var len = o.length >>> 0;
      var k = 0;
      var value;
      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++;
        }
        if (k >= len) {
          throw new TypeError(
            "Reduce of empty array " + "with no initial value"
          );
        }
        value = o[k++];
      }
      while (k < len) {
        if (k in o) {
          value = callback(value, o[k], k, o);
        }
        k++;
      }
      return value;
    }
  });
}
if (!Array.prototype.map) {
  Array.prototype.map = function (callback /*, thisArg*/ ) {
    var T, A, k;
    if (this == null) {
      throw new TypeError("this is null or not defined");
    }
    var O = Object(this);
    var len = O.length >>> 0;
    if (typeof callback !== "function") {
      throw new TypeError(callback + " is not a function");
    }
    if (arguments.length > 1) {
      T = arguments[1];
    }
    A = new Array(len);
    k = 0;
    while (k < len) {
      var kValue, mappedValue;
      if (k in O) {
        kValue = O[k];
        mappedValue = callback.call(T, kValue, k, O);
        A[k] = mappedValue;
      }
      k++;
    }
    return A;
  };
}
if (!Array.prototype.filter) {
  Array.prototype.filter = function (func, thisArg) {
    "use strict";
    if (!((typeof func === "Function" || typeof func === "function") && this))
      throw new TypeError();
    var len = this.length >>> 0,
      res = new Array(len), // preallocate array
      t = this,
      c = 0,
      i = -1;
    if (thisArg === undefined) {
      while (++i !== len) {
        if (i in this) {
          if (func(t[i], i, t)) {
            res[c++] = t[i];
          }
        }
      }
    } else {
      while (++i !== len) {
        if (i in this) {
          if (func.call(thisArg, t[i], i, t)) {
            res[c++] = t[i];
          }
        }
      }
    }
    res.length = c; // shrink down array to proper size
    return res;
  };
}
if (!Array.prototype.mapUsingReduce) {
  Array.prototype.mapUsingReduce = function (callback, thisArg) {
    return this.reduce(function (mappedArray, currentValue, index, array) {
      mappedArray[index] = callback.call(thisArg, currentValue, index, array);
      return mappedArray;
    }, []);
  };
}

BPL-6 JJ SL BrandScope ATS Unit Test.js

/**
 * @NApiVersion 2.x
 * @NScriptType Suitelet
 * @NModuleScope SameAccount
 */
/*******************************************************************************
 * * Jobin & Jismi IT Services | BrandScope | ATS Unit Test*
 * **************************************************************************
 *
 * Author: Jobin & Jismi IT Services LLP
 *
 * Date Created : 05-March-2019
 *
 * Created By : Manu Antony, Jobin & Jismi IT Services LLP
 *
 * SCRIPT ID: customscript_jj_bpl6_sl_ats_unit_test
 *
 * DEPLOYMENT ID: customdeploy_jj_bpl6_sl_ats_unit_test
 *
 * REVISION HISTORY
 *
 *
 ******************************************************************************/
"use strict";
const SCRIPT_OBJ = {
  SCRIPT_ID: "customscript_jj_bpl6_sl_ats_unit_test",
  DEPLOYMENT_ID: ["customdeploy_jj_bpl6_sl_ats_unit_test"]
};
var BRANDSCOPE_SETUP = {
  brandscope_fields: {
    atstoken: "",
    atsendpoint: "",
    nsemployee: "-5"
  },
  item_fields: {
    sku: "internalid",
    color: "internalid",
    size: "internalid",
    brand: "internalid"
  },
  salesorder_fields: {
    date: "trandate"
  },
  purchaseorder_fields: {
    date: "duedate"
  },
  date_format: {
    ns_format: "",
    required_format: "DD/MM/YYYY"
  }
};
define(["N/record", "N/ui/serverWidget", "N/url", "N/log", "./BPL-7 JJ BrandScope Logic"],
  function (record, serverWidget, url, log, brandscopelogic) {
    //To check whether a value exists in parameter
    function checkForParameter(parameter, parameterName) {
      if (parameter !== null && parameter !== undefined && parameter !== false && parameter !== "null" && parameter !== "undefined" && parameter !== "false" && parameter != "" && parameter != " ")
        return true;
      if (parameterName)
        log.debug("Empty Value found", "Empty Value for parameter " + parameterName);
      return false;
    }

    //To assign a default value if the it is empty
    function assignDefaultValue(value, defaultValue) {
      if (checkForParameter(value)) return value;
      return defaultValue;
    }

    //To reject predefined set of values
    function rejectThisValues(value) {
      var rejectObj = {
        null: true,
        undefined: true,
        NaN: true,
        0: true,
        false: true,
        "": true
      };
      return rejectObj[value] ? false : true;
    }

    //Common Try-Catch function
    function applyTryCatch(DATA_OBJ, NAME) {
      function tryCatch(myfunction, key) {
        return function () {
          try {
            return myfunction.apply(this, arguments);
          } catch (e) {
            log.error("error in " + key, e);
            return false;
          }
        };
      }
      for (var key in DATA_OBJ) {
        if (typeof DATA_OBJ[key] === "function") {
          DATA_OBJ[key] = tryCatch(DATA_OBJ[key], NAME + "." + key);
        }
      }
    }

    //Apply Styles
    var formatText = {
      allignContent: function (value, alignValue, noValue) {
        alignValue = assignDefaultValue(alignValue, "center");
        noValue = assignDefaultValue(noValue, "-");
        return ('<p align="' + alignValue + '">' + assignDefaultValue(value, noValue) + "</p>");
      },
      applyLink: function (hrefURL, text) {
        hrefURL = assignDefaultValue(hrefURL, "javascript:void(0);");
        text = assignDefaultValue(text, '- NIL -');
        return '<a href="' + hrefURL + '" target="_blank" >' + text + '</a>';
      },
      applyStyle: function (param) {
        var str = '<span style="';
        if (param.FONT_WEIGHT) str += "font-weight:" + param.FONT_WEIGHT + ";";
        if (param.FONT_COLOR) str += "color:" + param.FONT_COLOR + ";";
        if (param.FONT_SIZE) str += "font-size:" + param.FONT_SIZE + ";";
        if (param.FONT_STYLE) str += "font-style:" + param.FONT_STYLE + ";";
        if (param.FONT_FAMILY) str += "font-family:" + param.FONT_FAMILY + ";";
        str += '"> ' + param.VALUE + " </span>";
        return str;
      }
    };
    applyTryCatch(formatText, "formatText");

    //Main or Root Function of Suitelet -> Used to set form
    var main = {
      setformFieldProperty: function (field, propObj) {
        var setFieldProp = {
          updateLayoutType: function (field, value) {
            field.updateLayoutType({
              layoutType: value
            });
          },
          updateBreakType: function (field, value) {
            field.updateBreakType({
              breakType: value
            });
          },
          updateDisplayType: function (field, value) {
            field.updateDisplayType({
              displayType: value
            });
          },
          setHelpText: function (field, value) {
            field.setHelpText({
              help: value
            });
          },
          isMandatory: function (field, value) {
            field.isMandatory = value;
          },
          defaultValue: function (field, value) {
            field.defaultValue = value;
          }
        };
        for (var prop in propObj)
          if (propObj[prop]) setFieldProp[prop](field, propObj[prop]);
      },
      setProductToTraceContent: function (form, dataObj) {
        var fieldgroup = form.addFieldGroup({
          id: "_product_trace",
          label: "Product to Trace"
        });
        // fieldgroup.isSingleColumn = true;
        var _itemfield = form.addField({
          id: "_itemfield",
          type: serverWidget.FieldType.SELECT,
          label: "ITEM",
          source: "item",
          container: "_product_trace"
        });
        main.setformFieldProperty(_itemfield, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: "Select an Item",
          isMandatory: true,
          defaultValue: dataObj._itemfield
        });
        var _locationfield = form.addField({
          id: "_locationfield",
          type: serverWidget.FieldType.SELECT,
          label: "LOCATION",
          source: "location",
          container: "_product_trace"
        });
        main.setformFieldProperty(_locationfield, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: "Only the selected location will be considered for ATS calculation",
          isMandatory: true,
          defaultValue: dataObj._locationfield
        });
      },
      setProductDetailContent: function (form, dataObj) {
        form.addFieldGroup({
          id: "_product_details",
          label: "Product Details"
        });
        var _displayname = form.addField({
          id: "_displayname",
          type: serverWidget.FieldType.TEXT,
          label: "DISPLAY NAME/CODE",
          container: "_product_details"
        });
        main.setformFieldProperty(_displayname, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._displayname
        });
        var _itemid = form.addField({
          id: "_itemid",
          type: serverWidget.FieldType.TEXT,
          label: "ITEM NAME/NUMBER",
          container: "_product_details"
        });
        main.setformFieldProperty(_itemid, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._itemid
        });
        var _sku = form.addField({
          id: "_sku",
          type: serverWidget.FieldType.TEXT,
          label: "SKU",
          container: "_product_details"
        });
        main.setformFieldProperty(_sku, {
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "normal",
            VALUE: "Value is sourced from the ",
            FONT_COLOR: "black"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: BRANDSCOPE_SETUP.item_fields.sku,
            FONT_COLOR: "green"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "normal",
            VALUE: " field on Item Record",
            FONT_COLOR: "black"
          }),
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._sku
        });
        var _color = form.addField({
          id: "_color",
          type: serverWidget.FieldType.TEXT,
          label: "COLOR",
          container: "_product_details"
        });
        main.setformFieldProperty(_color, {
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "normal",
            VALUE: "Value is sourced from the ",
            FONT_COLOR: "black"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: BRANDSCOPE_SETUP.item_fields.color,
            FONT_COLOR: "green"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "normal",
            VALUE: " field on Item Record",
            FONT_COLOR: "black"
          }),
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._color
        });
        var _size = form.addField({
          id: "_size",
          type: serverWidget.FieldType.TEXT,
          label: "SIZE",
          container: "_product_details"
        });
        main.setformFieldProperty(_size, {
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "normal",
            VALUE: "Value is sourced from the ",
            FONT_COLOR: "black"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: BRANDSCOPE_SETUP.item_fields.size,
            FONT_COLOR: "green"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "normal",
            VALUE: " field on Item Record",
            FONT_COLOR: "black"
          }),
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._size
        });
        var _brand = form.addField({
          id: "_brand",
          type: serverWidget.FieldType.TEXT,
          label: "Brand",
          container: "_product_details"
        });
        main.setformFieldProperty(_brand, {
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "normal",
            VALUE: "Value is sourced from the ",
            FONT_COLOR: "black"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: BRANDSCOPE_SETUP.item_fields.brand,
            FONT_COLOR: "green"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "normal",
            VALUE: " field on Item Record",
            FONT_COLOR: "black"
          }),
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._brand
        });
      },
      setInventoryDetailContent: function (form, dataObj) {
        form.addFieldGroup({
          id: "_inventory_details",
          label: "NetSuite Inventory Details"
        });
        var _atoncedate = form.addField({
          id: "_atoncedate",
          type: serverWidget.FieldType.DATE,
          label: "NetSuite AtOnce Date",
          container: "_inventory_details"
        });
        main.setformFieldProperty(_atoncedate, {
          setHelpText: "Current Date",
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._atoncedate
        });
        var _totalqtyavailable = form.addField({
          id: "_totalqtyavailable",
          type: serverWidget.FieldType.INTEGER,
          label: "NetSuite QUANTITY AVAILABLE",
          container: "_inventory_details"
        });
        main.setformFieldProperty(_totalqtyavailable, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._totalqtyavailable
        });
        var _totalqtycommitted = form.addField({
          id: "_totalqtycommitted",
          type: serverWidget.FieldType.INTEGER,
          label: "NetSuite QUANTITY COMMITTED",
          container: "_inventory_details"
        });
        main.setformFieldProperty(_totalqtycommitted, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._totalqtycommitted
        });
        var _totalqtybackordered = form.addField({
          id: "_totalqtybackordered",
          type: serverWidget.FieldType.INTEGER,
          label: "NetSuite QUANTITY BACKORDERED",
          container: "_inventory_details"
        });
        main.setformFieldProperty(_totalqtybackordered, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._totalqtybackordered
        });
        var _totalqtyonorder = form.addField({
          id: "_totalqtyonorder",
          type: serverWidget.FieldType.INTEGER,
          label: "NetSuite QUANTITY ONORDER",
          container: "_inventory_details"
        });
        main.setformFieldProperty(_totalqtyonorder, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          updateBreakType: serverWidget.FieldBreakType.STARTCOL,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._totalqtyonorder
        });
      },
      setCalculatedInventoryDetailContent: function (form, dataObj) {
        form.addFieldGroup({
          id: "_calculated_inventory_details",
          label: "Calculated Inventory Details"
        });
        var _totaloffset = form.addField({
          id: "_totaloffset",
          type: serverWidget.FieldType.INTEGER,
          label: "OFFSET QUANTITY",
          container: "_calculated_inventory_details"
        });
        main.setformFieldProperty(_totaloffset, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: "All Committed Quantity of Sales Order on or after First Future Dated Purchase Order",
            FONT_COLOR: "black"
          }),
          updateBreakType: serverWidget.FieldBreakType.NONE,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._totaloffset
        });
        var _qtyavailable = form.addField({
          id: "_qtyavailable",
          type: serverWidget.FieldType.INTEGER,
          label: "QUANTITY AVAILABLE",
          container: "_calculated_inventory_details"
        });
        main.setformFieldProperty(_qtyavailable, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: "NETSUITE QUANTITY AVAILABLE - NETSUITE QUANTITY BACKORDERED + OFFSET QUANTITY",
            FONT_COLOR: "green"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: ", only if this value is positive else 0",
            FONT_COLOR: "black"
          }),
          updateBreakType: serverWidget.FieldBreakType.NONE,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._qtyavailable
        });
        var _qtycommitted = form.addField({
          id: "_qtycommitted",
          type: serverWidget.FieldType.INTEGER,
          label: "QUANTITY COMMITTED",
          container: "_calculated_inventory_details"
        });
        main.setformFieldProperty(_qtycommitted, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: "NETSUITE QUANTITY COMMITTED - OFFSET QUANTITY",
            FONT_COLOR: "green"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: ", only if this value is positive else 0",
            FONT_COLOR: "black"
          }),
          updateBreakType: serverWidget.FieldBreakType.NONE,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._qtycommitted
        });
        var _qtybackordered = form.addField({
          id: "_qtybackordered",
          type: serverWidget.FieldType.INTEGER,
          label: "QUANTITY BACKORDERED",
          container: "_calculated_inventory_details"
        });
        main.setformFieldProperty(_qtybackordered, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: "NETSUITE QUANTITY AVAILABLE - NETSUITE QUANTITY BACKORDERED + OFFSET QUANTITY",
            FONT_COLOR: "green"
          }) + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: ", only if this value is negative else 0",
            FONT_COLOR: "black"
          }),
          updateBreakType: serverWidget.FieldBreakType.NONE,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._qtybackordered
        });
        var _totalpastpurchaseorder = form.addField({
          id: "_totalpastpurchaseorder",
          type: serverWidget.FieldType.INTEGER,
          label: "Unreceived Past Purchase Order",
          container: "_calculated_inventory_details"
        });
        main.setformFieldProperty(_totalpastpurchaseorder, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: "Total Unreceived Quantity of Past Dated Purchase Order (including today). This value will be added to First Future Dated Purchase Order",
            FONT_COLOR: "black"
          }),
          updateBreakType: serverWidget.FieldBreakType.NONE,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: dataObj._totalpastpurchaseorder
        });
      },
      setBodyFields: function (form, dataObj) {
        //Product to Trace
        main.setProductToTraceContent(form, dataObj);
        //Product Details
        main.setProductDetailContent(form, dataObj);
        //Inventory Details
        main.setInventoryDetailContent(form, dataObj);
        //Calculated Inventory Details
        main.setCalculatedInventoryDetailContent(form, dataObj);
      },
      setSavedSearchResultAsSublist: function (SUBLIST_FIELD, dataObj, DATA_ARRAY, RECORD_TYPE) {
        //To initilize sublist columns
        var coulmnDetails = {};
        if (DATA_ARRAY.length > 0)
          for (var key in DATA_ARRAY[0]) {
            coulmnDetails[key] = ("custpage_" + key).toLowerCase();
            SUBLIST_FIELD.addField({
              id: coulmnDetails[key],
              label: key.toString().trim().toUpperCase(),
              type: serverWidget.FieldType.TEXT
            });
          }
        coulmnDetails.summary = "custpage_summary".toLowerCase();
        SUBLIST_FIELD.addField({
          id: coulmnDetails.summary,
          label: "summary".toString().trim().toUpperCase(),
          type: serverWidget.FieldType.TEXT
        });
        for (var index = 0, len = DATA_ARRAY.length; index < len; index++) {
          for (var key in coulmnDetails) {
            if (key == "summary")
              SUBLIST_FIELD.setSublistValue({
                id: coulmnDetails[key],
                line: index,
                value: formatText.applyStyle(Object.assign({
                  FONT_WEIGHT: "bold"
                }, brandscopelogic.dateLogic.isBetween(dataObj._atoncedate, false, DATA_ARRAY[index].DATE_FIELD.value, "days", "()") ? {
                  VALUE: "Future Dated",
                  FONT_COLOR: "green"
                } : {
                  VALUE: "Past Dated",
                  FONT_COLOR: "red"
                }))
              });
            else if (key == "internalid")
              //Set link to netsuite record if key is internalid
              SUBLIST_FIELD.setSublistValue({
                id: coulmnDetails[key],
                line: index,
                value: formatText.applyLink(url.resolveRecord({
                  recordType: RECORD_TYPE,
                  recordId: DATA_ARRAY[index][key].value,
                  isEditMode: false
                }), DATA_ARRAY[index][key].value)
              });
            else if (DATA_ARRAY[index][key].text || DATA_ARRAY[index][key].value)
              //Set value to sublist field only if there exists a value
              SUBLIST_FIELD.setSublistValue({
                id: coulmnDetails[key],
                line: index,
                value: DATA_ARRAY[index][key].text ?
                  DATA_ARRAY[index][key].text : DATA_ARRAY[index][key].value
              });
          }
        }
      },
      setObjectAsSublist: function (SUBLIST_FIELD, DATA_ARRAY) {
        //To initilize sublist columns
        var coulmnDetails = {};
        if (DATA_ARRAY.length > 0)
          for (var key in DATA_ARRAY[0]) {
            coulmnDetails[key] = ("custpage_" + key).toLowerCase();
            SUBLIST_FIELD.addField({
              id: coulmnDetails[key],
              label: key.toString().trim().toUpperCase(),
              type: serverWidget.FieldType.TEXT
            });
          }
        for (var index = 0, len = DATA_ARRAY.length; index < len; index++) {
          for (var key in coulmnDetails) {
            if (DATA_ARRAY[index][key])
              //Set value to sublist field only if there exists a value
              SUBLIST_FIELD.setSublistValue({
                id: coulmnDetails[key],
                line: index,
                value: DATA_ARRAY[index][key]
              });
          }
        }
      },
      setTabField: function (form, dataObj, SO_ARRAY, PO_ARRAY, bucketPeriod, mappedATS) {
        //Adding Subtab for showing Summary Detils
        form.addTab({
          id: "_summary_details_tab",
          label: "Summary"
        });
        //Sales Order Tab Details
        form.addSubtab({
          id: '_summary_salesorder',
          tab: '_summary_details_tab',
          label: 'Sales Order'
        });
        var _sodatefield = form.addField({
          id: "_sodatefield",
          type: serverWidget.FieldType.TEXT,
          label: "DATE_FIELD",
          container: "_summary_salesorder"
        });
        main.setformFieldProperty(_sodatefield, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: "The Date Field in Sales Order taken for consideration. Its sourced from BrandScope Setup. If none is given," + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: "trandate",
            FONT_COLOR: "green"
          }) + " is used as default ",
          updateBreakType: serverWidget.FieldBreakType.NONE,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: assignDefaultValue(BRANDSCOPE_SETUP.salesorder_fields.date, "trandate")
        });
        main.setSavedSearchResultAsSublist(form.addSublist({
          id: "_salesorder_sublist",
          type: serverWidget.SublistType.LIST,
          tab: "_summary_salesorder",
          label: "Sales Order"
        }), dataObj, SO_ARRAY, record.Type.SALES_ORDER);

        //Purchase Order Tab Details
        form.addSubtab({
          id: '_summary_purchaseorder',
          tab: '_summary_details_tab',
          label: 'Purchase Order'
        });
        var _podatefield = form.addField({
          id: "_podatefield",
          type: serverWidget.FieldType.TEXT,
          label: "DATE_FIELD",
          container: "_summary_purchaseorder"
        });
        main.setformFieldProperty(_podatefield, {
          updateLayoutType: serverWidget.FieldLayoutType.NORMAL,
          setHelpText: "The Date Field in Purchase Order taken for consideration. Its sourced from BrandScope Setup. If none is given," + formatText.applyStyle({
            FONT_WEIGHT: "bold",
            VALUE: "duedate",
            FONT_COLOR: "green"
          }) + " is used as default",
          updateBreakType: serverWidget.FieldBreakType.NONE,
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: assignDefaultValue(BRANDSCOPE_SETUP.purchaseorder_fields.date, "duedate")
        });
        main.setSavedSearchResultAsSublist(form.addSublist({
          id: "_purchaseorder_sublist",
          type: serverWidget.SublistType.LIST,
          tab: "_summary_purchaseorder",
          label: "Purchase Order"
        }), dataObj, PO_ARRAY, record.Type.PURCHASE_ORDER);

        //Consolidated Sales Order Details
        var consolidateSO = brandscopelogic.dataManipulate.consolidateSalesOrderByBucket(dataObj, bucketPeriod.DATE_ARRAY, bucketPeriod.BUCKET);
        main.setObjectAsSublist(form.addSublist({
          id: "_consolidated_so_sublist",
          type: serverWidget.SublistType.LIST,
          tab: "_summary_details_tab",
          label: "Consolidated Sales Order"
        }), Object.keys(consolidateSO).map(function (e) {
          return {
            date: consolidateSO[e].date.toString(),
            quantityremaining: consolidateSO[e].quantityremaining.toString()
          };
        }));

        //Consolidated Purchase Order Details
        var consolidatePO = brandscopelogic.dataManipulate.consolidatePurchaseOrderByDate(dataObj, PO_ARRAY);
        // reducer function helper take obj and return the actual reducer function
        var reducerFunctionHelper = function (obj) {
          return function (accumulator, currentKey) {
            accumulator.push({
              date: obj[currentKey].date.toString(),
              quantityremaining: obj[currentKey].quantityremaining.toString()
            });
            return accumulator;
          };
        };
        main.setObjectAsSublist(form.addSublist({
            id: "_consolidated_po_sublist",
            type: serverWidget.SublistType.LIST,
            tab: "_summary_details_tab",
            label: "Consolidated Purchase Order"
          }), // Object.keys(consolidatePO).reduce(reducerFunctionHelper(consolidatePO), [])
          Object.keys(consolidatePO).map(function (e) {
            return {
              date: consolidatePO[e].date.toString(),
              quantityremaining: consolidatePO[e].quantityremaining.toString()
            };
          }));

        //ATS Tab Details
        main.setObjectAsSublist(form.addSublist({
          id: "_ats_sublist",
          type: serverWidget.SublistType.LIST,
          tab: "_summary_details_tab",
          label: "ATS Details"
        }), mappedATS);

      },
      generateForm: function (dataObj) {
        log.debug("generateForm", "generateForm");
        //initialize form
        var form = serverWidget.createForm({
          title: "Brandscope ATS Calculation"
        });
        form.addSubmitButton({
          id: "_search_button",
          label: "Search"
        });
        var _hiddeninlinehtml = form.addField({
          id: '_hidden_inline_html_field',
          type: serverWidget.FieldType.INLINEHTML,
          label: 'Inline HTML'
        });
        dataObj._hiddeninlinehtml = '';
        var purchaseOrderArray = [],
          salesOrderArray = [],
          mappedATS = [],
          bucketPeriod = {
            DATE_ARRAY: [],
            BUCKET: {}
          };
        if (brandscopelogic.initialise()) {
          BRANDSCOPE_SETUP = brandscopelogic.getBrandScopeSetup();
          dataObj._atoncedate = brandscopelogic.dateLogic.formatDate(brandscopelogic.moment(), BRANDSCOPE_SETUP.date_format.ns_format);
          if (checkForParameter(dataObj._itemfield) && checkForParameter(dataObj._locationfield)) {
            dataObj = brandscopelogic.dataSets.item(dataObj._itemfield, dataObj._locationfield, dataObj);
            if (dataObj._internalid) {
              var generateFormValues = brandscopelogic.generateFormValues(dataObj, true);
              dataObj = generateFormValues.dataObj;
              purchaseOrderArray = generateFormValues.purchaseOrderArray;
              salesOrderArray = generateFormValues.salesOrderArray;
              bucketPeriod = generateFormValues.bucketPeriod;
              mappedATS = generateFormValues.mappedATS;
            } else
              dataObj._hiddeninlinehtml = '<script>alert("No Inventory Details found for this product at this location")</script>';
          }
        } else
          dataObj._hiddeninlinehtml = '<script>alert("Please Setup BrandScope Settings")</script>';

        //To set data on Body field of form
        main.setBodyFields(form, dataObj);
        //To set data on Tab section of form
        main.setTabField(form, dataObj, salesOrderArray, purchaseOrderArray, bucketPeriod, mappedATS);

        //Set value to Inline HTML field if any 
        main.setformFieldProperty(_hiddeninlinehtml, {
          updateDisplayType: serverWidget.FieldDisplayType.DISABLED,
          defaultValue: assignDefaultValue(dataObj._hiddeninlinehtml, '')
        });

        return form;
      },
      onRequest: function (context) {
        if (context.request.method === "GET" || context.request.method === "POST") {
          var form = main.generateForm({
            _itemfield: assignDefaultValue(context.request.parameters._itemfield, ""),
            _locationfield: assignDefaultValue(context.request.parameters._locationfield, "")
          });
          if (form) {
            context.response.writePage(form);
            return true;
          }
        }
        context.response.write(main.errorInProcess());
        return false;
      },
      errorInProcess: function () {
        return '<html><head><script>(function () {alert("Something went wrong");window.close();}());</script></head><body></body></html>';
      }
    };
    applyTryCatch(main, "main");

    return main;
  });
if (!Array.prototype.push) {
  Array.prototype.push = function (x) {
    this[this.length] = x;
    return true;
  };
}
if (!Array.prototype.pop) {
  Array.prototype.pop = function () {
    var response = this[this.length - 1];
    this.length--;
    return response;
  };
}
if (!Array.prototype.remove) {
  Array.prototype.remove = function (from, to) {
    var rest = this.slice(parseInt(to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
  };
}
if (typeof Object.assign != "function") {
  Object.defineProperty(Object, "assign", {
    value: function assign(target, varArgs) {
      "use strict";
      if (target == null) {
        throw new TypeError("Cannot convert undefined or null to object");
      }
      var to = Object(target);
      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];
        if (nextSource != null) {
          for (var nextKey in nextSource) {
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
    writable: true,
    configurable: true
  });
}
if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, "reduce", {
    value: function (callback /*, initialValue*/ ) {
      if (this === null) {
        throw new TypeError(
          "Array.prototype.reduce " + "called on null or undefined"
        );
      }
      if (typeof callback !== "function") {
        throw new TypeError(callback + " is not a function");
      }
      var o = Object(this);
      var len = o.length >>> 0;
      var k = 0;
      var value;
      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++;
        }
        if (k >= len) {
          throw new TypeError(
            "Reduce of empty array " + "with no initial value"
          );
        }
        value = o[k++];
      }
      while (k < len) {
        if (k in o) {
          value = callback(value, o[k], k, o);
        }
        k++;
      }
      return value;
    }
  });
}
if (!Array.prototype.map) {
  Array.prototype.map = function (callback /*, thisArg*/ ) {
    var T, A, k;
    if (this == null) {
      throw new TypeError("this is null or not defined");
    }
    var O = Object(this);
    var len = O.length >>> 0;
    if (typeof callback !== "function") {
      throw new TypeError(callback + " is not a function");
    }
    if (arguments.length > 1) {
      T = arguments[1];
    }
    A = new Array(len);
    k = 0;
    while (k < len) {
      var kValue, mappedValue;
      if (k in O) {
        kValue = O[k];
        mappedValue = callback.call(T, kValue, k, O);
        A[k] = mappedValue;
      }
      k++;
    }
    return A;
  };
}
if (!Array.prototype.filter) {
  Array.prototype.filter = function (func, thisArg) {
    "use strict";
    if (!((typeof func === "Function" || typeof func === "function") && this))
      throw new TypeError();
    var len = this.length >>> 0,
      res = new Array(len), // preallocate array
      t = this,
      c = 0,
      i = -1;
    if (thisArg === undefined) {
      while (++i !== len) {
        if (i in this) {
          if (func(t[i], i, t)) {
            res[c++] = t[i];
          }
        }
      }
    } else {
      while (++i !== len) {
        if (i in this) {
          if (func.call(thisArg, t[i], i, t)) {
            res[c++] = t[i];
          }
        }
      }
    }
    res.length = c; // shrink down array to proper size
    return res;
  };
}
if (!Array.prototype.mapUsingReduce) {
  Array.prototype.mapUsingReduce = function (callback, thisArg) {
    return this.reduce(function (mappedArray, currentValue, index, array) {
      mappedArray[index] = callback.call(thisArg, currentValue, index, array);
      return mappedArray;
    }, []);
  };
}

BPL-7 JJ SS BrandScope Scheduler.js

/**
 * @NApiVersion 2.x
 * @NScriptType ScheduledScript
 * @NModuleScope SameAccount
 */
/*******************************************************************************
 * * Jobin & Jismi IT Services | BrandScope | Scheduler*
 * **************************************************************************
 *
 * Author: Jobin & Jismi IT Services LLP
 *
 * Date Created : 25-March-2019
 *
 * Created By : Manu Antony, Jobin & Jismi IT Services LLP
 *
 * SCRIPT ID: customscript_jj_bpl7_ss_scheduler
 *
 * DEPLOYMENT ID: customdeploy_jj_bpl7_ss_scheduler_0, customdeploy_jj_bpl7_ss_scheduler_1
 *
 * REVISION HISTORY
 *
 *
 ******************************************************************************/
"use strict";
const SCRIPT_OBJ = {
  SCRIPT_ID: "customscript_jj_bpl7_ss_scheduler",
  DEPLOYMENT_ID: ["customdeploy_jj_bpl7_ss_scheduler_0", "customdeploy_jj_bpl7_ss_scheduler_1"]
};
var BRANDSCOPE_SETUP = {
  brandscope_fields: {
    atstoken: "",
    atsendpoint: "",
    nsemployee: "-5"
  },
  item_fields: {
    sku: "internalid",
    color: "internalid",
    size: "internalid",
    brand: "internalid"
  },
  salesorder_fields: {
    date: "trandate"
  },
  purchaseorder_fields: {
    date: "duedate"
  },
  date_format: {
    ns_format: "",
    required_format: "DD/MM/YYYY"
  }
};

define(["N/runtime", "N/task", "N/util", "N/http", "N/https", "N/record", 'N/config', "N/log", "./BPL-7 JJ BrandScope Logic"],
  function (runtime, task, util, http, https, record, config, log, brandscopelogic) {
    //To check whether a value exists in parameter
    function checkForParameter(parameter, parameterName) {
      if (parameter !== null && parameter !== undefined && parameter !== false && parameter !== "null" && parameter !== "undefined" && parameter !== "false" && parameter !== "" && parameter !== " ")
        return true;
      if (parameterName)
        log.debug("Empty Value found", "Empty Value for parameter " + parameterName);
      return false;
    }

    //To assign a default value if the it is empty
    function assignDefaultValue(value, defaultValue) {
      if (checkForParameter(value)) return value;
      return defaultValue;
    }

    //To reject predefined set of values
    function rejectThisValues(value) {
      var rejectObj = {
        null: true,
        undefined: true,
        NaN: true,
        0: true,
        false: true,
        "": true
      };
      return rejectObj[value] ? false : true;
    }

    //Common Try-Catch function
    function applyTryCatch(DATA_OBJ, NAME) {
      function tryCatch(myfunction, key) {
        return function () {
          try {
            return myfunction.apply(this, arguments);
          } catch (e) {
            log.error("error in " + key, e);
            return false;
          }
        };
      }
      for (var key in DATA_OBJ) {
        if (typeof DATA_OBJ[key] === "function") {
          DATA_OBJ[key] = tryCatch(DATA_OBJ[key], NAME + "." + key);
        }
      }
    }


    //Encapsulates Scheduler Functions
    var scheduler = {
      currentScript: undefined,
      run: function (key) {
        return ({
          initialise: function () {
            return scheduler.initialise();
          },
          id: function () {
            return scheduler.getScriptId();
          },
          deploymentId: function () {
            return scheduler.getDeploymentId();
          },
          remainingUsage: function () {
            return scheduler.getRemainingUsage();
          },
          parameter: function (args) {
            return scheduler.getParameter(args);
          },
          reschedule: function (args) {
            return scheduler.submitTask(args);
          }
        })[key](arguments);
      },
      initialise: function () {
        this.currentScript = runtime.getCurrentScript();
      },
      getScriptId: function () {
        return this.currentScript.id;
      },
      getDeploymentId: function () {
        return this.currentScript.deploymentId;
      },
      getRemainingUsage: function () {
        return Number(runtime.getCurrentScript().getRemainingUsage());
      },
      getParameter: function (args) {
        //arguments = Array.prototype.slice(Array.prototype.shift.apply(arguments));
        if (args[1])
          return assignDefaultValue(this.currentScript.getParameter({
            name: args[1].toString().toLowerCase().trim()
          }), false);
        return false;
      },
      submitTask: function (args) {
        //if args, thens args are scriptId(String),deploymentId(String),params(Object)
        return task.create({
          taskType: task.TaskType.SCHEDULED_SCRIPT,
          scriptId: assignDefaultValue(args[1] ? args[1] : this.run("id"), this.run("id")),
          deploymentId: assignDefaultValue(args[2] ? args[2] : this.run("deploymentId"), this.run("deploymentId")),
          params: (function () {
            var tempObj = {};
            if (args[3])
              for (var key in args[3])
                tempObj[key] = args[3][key];
            return tempObj;
          })()
        }).submit();
      }

    };
    applyTryCatch(scheduler, "scheduler");

    //Manipulating DataSet such as formating,cleansing,calculting etc ...
    var dataManipulate = {
      cleanSlateProtocol: function (recordType, recordId) {
        //Delete 'BrandScope Scheduler DataSet' entries
        recordType = 'customrecord_jj_bpl7_brandscope_schedule';
        if (!recordType && !recordId)
          return false;
        if (recordType && recordId)
          return record.delete({
            type: recordType,
            id: recordId,
          });
        return false;
      },
      cleanseBranScopeSchedulerDataSet: function () {
        //Clearing 'BrandScope Scheduler DataSet' on primary execution of Scheduled Script
        var clensingArray = brandscopelogic.dataSets.brandScopeSchedulerDataSet();
        clensingArray.forEach(function (eachResult) {
          dataManipulate.cleanSlateProtocol('customrecord_jj_bpl7_brandscope_schedule', eachResult["Internal ID"].value);
        });
        return true;
      },
      processBrandScopeSchedulerDataSet: function () {
        //Read data from 'BrandScope Scheduler DataSet'
        function parseObject(obj) {
          try {
            return JSON.parse(obj);
          } catch (er) {
            return {};
          }
        }
        return brandscopelogic.dataSets.brandScopeSchedulerDataSet().reduce(function (accumulator, currentValue) {
          accumulator[currentValue.Item.value] = parseObject(
            record.load({
              type: 'customrecord_jj_bpl7_brandscope_schedule',
              id: currentValue["Internal ID"].value,
              isDynamic: false
            })
            .getValue({
              fieldId: 'custrecord_bpl7_scheduler_data'
            })
          );
          return accumulator;
        }, {}); // Final result will be Object whose structure is { ITEM_ID :  ATS VALUES }
      },
      processBrandScopeLocations: function (LOCATION_LIST) {
        //Creates BrandScope Location Object
        return brandscopelogic.dataSets.brandScopeLocation().reduce(function (accumulator, currentValue) {
          LOCATION_LIST[currentValue.Location.value] = currentValue.Location.text;
          accumulator[currentValue.Location.value] = currentValue.Abbreviations.value;
          return accumulator;
        }, {}); // Final result will be Object whose structure is { LOCATION_INTERNAL_ID : LOCATION_ABBREVIATIONS }
      },
      processBrandScopeBrands: function (BRAND_LIST) {
        //Creates BrandScope Brand Object
        return brandscopelogic.dataSets.brandScopeBrand().reduce(function (accumulator, currentValue) {
          BRAND_LIST[currentValue.Brand.value] = currentValue.Brand.text;
          if (accumulator[currentValue.Location.value])
            accumulator[currentValue.Location.value].push(currentValue.Brand.value);
          else
            accumulator[currentValue.Location.value] = [currentValue.Brand.value];
          return accumulator;
        }, {}); // Final result will be Object whose structure is { LOCATION_INTERNAL_ID : [ BRAND_INTERNAL_ID ] }
      },
      processApprovedItems: function (LOCATION_LIST, LOCATION_MAP, BRAND_LIST) {
        //Creates ATS Object for only the aproved items,brands and location
        return brandscopelogic.dataSets.approvedItems(Object.keys(LOCATION_LIST), Object.keys(BRAND_LIST))
          .reduce(function (accumulator, currentValue) {
            if (accumulator[currentValue['Internal ID'].value])
              accumulator[currentValue['Internal ID'].value].push(Object.assign(
                currentValue, {
                  WarehouseCode: {
                    value: assignDefaultValue(LOCATION_MAP[currentValue['Inventory Location'].value], ''),
                    text: null
                  }
                }));
            else
              accumulator[currentValue['Internal ID'].value] = [Object.assign(
                currentValue, {
                  WarehouseCode: {
                    value: assignDefaultValue(LOCATION_MAP[currentValue['Inventory Location'].value], ''),
                    text: null
                  }
                })];
            return accumulator;
          }, {});
      },
      setBrandScopeSchedulerDataSetInstance: function (item, itemArray, BRAND_MAP) {
        //Create 'BrandScope Scheduler DataSet' instance
        var brandScopeSchedulerDataSetRecord = record.create({
          type: 'customrecord_jj_bpl7_brandscope_schedule',
          isDynamic: false
        });
        brandScopeSchedulerDataSetRecord.setValue({
          fieldId: 'custrecord_bpl7_scheduler_item', //ITEM
          value: item,
          ignoreFieldChange: false
        });
        var dataSet = itemArray.reduce(function (accumulator, currentValue) {
          if (BRAND_MAP[currentValue["Inventory Location"].value] && currentValue.Brand.value)
            if (BRAND_MAP[currentValue["Inventory Location"].value].length)
              if (BRAND_MAP[currentValue["Inventory Location"].value].indexOf(currentValue.Brand.value) > -1 || BRAND_MAP[currentValue["Inventory Location"].value].indexOf(currentValue.Brand.value.toString().trim()) > -1) // Process the item only if Brand and Location is approved
                accumulator.push({
                  "Type": currentValue.Type.value,
                  "SourceSystem": currentValue.SourceSystem.value,
                  "Brand": currentValue.Brand.text,
                  "Integration_ID": currentValue.Integration_ID.value,
                  "Barcode": currentValue.Barcode.value,
                  "ProductName": currentValue.ProductName.value,
                  "WarehouseCode": currentValue.WarehouseCode.value,
                  "Quantity": brandscopelogic.generateSchedulerValues({
                    "_internalid": currentValue["Internal ID"].value,
                    "_itemfield": currentValue["Barcode"].value,
                    "_locationfield": currentValue["Inventory Location"].value
                  })
                });
          return accumulator;
        }, []);
        brandScopeSchedulerDataSetRecord.setValue({
          fieldId: 'custrecord_bpl7_scheduler_data', //DATA
          value: JSON.stringify(dataSet),
          ignoreFieldChange: false
        });
        brandScopeSchedulerDataSetRecord.save({
          enableSourcing: true,
          ignoreMandatoryFields: false
        });
      },
      calculatePayload: function (brandScopeSchedulerDataSet) {
        //Create Payload for HTTP Request
        var payload = [];
        for (var item in brandScopeSchedulerDataSet)
          if (checkForParameter(brandScopeSchedulerDataSet[item])) //To Skip Array Object if it is empty
            if (util.isArray(brandScopeSchedulerDataSet[item]))
              if (brandScopeSchedulerDataSet[item].length)
                payload = payload.concat(brandScopeSchedulerDataSet[item]);
        return payload;
      }
    };
    applyTryCatch(dataManipulate, "dataManipulate");



    //Main or Root Function of Scheduled Script
    var main = {
      isSandBox: function () {
        var companyInfo = config.load({
          type: config.Type.COMPANY_INFORMATION
        });
        var ns_companyid = companyInfo.getValue({
          fieldId: 'companyid'
        });
        ns_companyid = ns_companyid.toString().trim().toLowerCase();

        if (ns_companyid.indexOf('sb') > -1)
          return true;
        return false;
      },
      initialize: function () {
        //To Initialise BrandScope Environment
        if (brandscopelogic.initialise()) {
          BRANDSCOPE_SETUP = brandscopelogic.getBrandScopeSetup();
          return true;
        }
        return false;
      },
      execute: function (scriptContext) {
        if (main.isSandBox()) //If current executing environment is SandBox, then disregard the entire process
          return false;

        log.debug('*** START ***', '*** SCHEDULED SCRIPT STARTS ***');

        //Initialize Scheduler Functions 
        scheduler.run("initialise");

        if (main.initialize()) { //Proceed only if BrandScope is already setup

          var RESCHEDULER_PARAMETER = scheduler.run("parameter", 'custscript_bpl7_current_item_on_schedule');

          if (!RESCHEDULER_PARAMETER) //If first scheduler instance, cleanse BranScope Scheduler DataSet
            dataManipulate.cleanseBranScopeSchedulerDataSet();

          if (RESCHEDULER_PARAMETER && (RESCHEDULER_PARAMETER == true || RESCHEDULER_PARAMETER == 'true')) { // All Applicable Items are proccessed and we need to send the data stored in BranScope Scheduler DataSet

            var brandScopeSchedulerDataSet = dataManipulate.processBrandScopeSchedulerDataSet(); //Fetching all the existing data on BranScope Scheduler DataSet
            log.debug('brandScopeSchedulerDataSet', brandScopeSchedulerDataSet);

            if (Object.keys(brandScopeSchedulerDataSet).length) {
              var payload = dataManipulate.calculatePayload(brandScopeSchedulerDataSet);
              log.debug('payload', payload);

              var requestObj = {
                url: BRANDSCOPE_SETUP.brandscope_fields.atsendpoint,
                headers: {
                  'cache-control': 'no-cache',
                  'authorization': 'Token ' + BRANDSCOPE_SETUP.brandscope_fields.atstoken,
                  'content-type': 'application/json'
                },
                body: JSON.stringify({
                  ats: payload
                })
              };
              log.debug('requestObj', requestObj);
              var response = ((BRANDSCOPE_SETUP.brandscope_fields.atsendpoint).toString().trim().indexOf('https') > -1) ? https.post(requestObj) : http.post(requestObj);
              log.debug('response', response);
            }
          } else { // All Applicable Items are not yet proccessed or in phase of being processed

            var LOCATION_LIST = {},
              LOCATION_MAP = dataManipulate.processBrandScopeLocations(LOCATION_LIST);
            log.debug('LOCATION_MAP', LOCATION_MAP);
            log.debug('LOCATION_LIST', LOCATION_LIST);

            if (Object.keys(LOCATION_MAP).length) { //Proceed only if Location Abbreviations is setup on BrandScope Settings
              var BRAND_LIST = {},
                BRAND_MAP = dataManipulate.processBrandScopeBrands(BRAND_LIST);
              log.debug('BRAND_MAP', BRAND_MAP);
              log.debug('BRAND_LIST', BRAND_LIST);

              if (Object.keys(BRAND_MAP).length) { //Proceed only if Brand is setup on BrandScope Settings
                var approvedItemsById = dataManipulate.processApprovedItems(LOCATION_LIST, LOCATION_MAP, BRAND_LIST); //All Items that should be taken for consideration grouped by Item Internal ID

                if (Object.keys(approvedItemsById).length) { //Proceed only if there exists Items with the defined parameters
                  var IS_ALREADY_RESCHEDULED = false;
                  if (RESCHEDULER_PARAMETER)
                    IS_ALREADY_RESCHEDULED = true;

                  for (var key in approvedItemsById) { //Process each item

                    if (RESCHEDULER_PARAMETER && IS_ALREADY_RESCHEDULED) { //Skip all the keys until the first occurence of unprocessed Item
                      if (RESCHEDULER_PARAMETER == key || RESCHEDULER_PARAMETER.toString().trim() == key.toString().trim())
                        IS_ALREADY_RESCHEDULED = false;
                      else
                        continue;
                    }

                    if (scheduler.run("remainingUsage") < 2500) { //Rescheduling Condition
                      scheduler.run("reschedule", false, false, {
                        custscript_bpl7_current_item_on_schedule: key
                      });
                      IS_ALREADY_RESCHEDULED = true;
                      log.debug('*** RESCHEDULE ***', '*** SCHEDULED SCRIPT RESCHEDULES ***');
                      break;
                    }

                    //Setting Data into Scheduler DataSet
                    dataManipulate.setBrandScopeSchedulerDataSetInstance(key, approvedItemsById[key], BRAND_MAP);

                  }

                  if (!IS_ALREADY_RESCHEDULED) { //It means every items is processed and BrandScope Scheduler DataSet is created
                    scheduler.run("reschedule", false, false, {
                      custscript_bpl7_current_item_on_schedule: true
                    });
                    log.debug('*** RESCHEDULE ***', '*** SCHEDULED SCRIPT RESCHEDULES ***');
                  }
                }
              }
            }
          }
          log.debug('SCRIPT_OBJ', SCRIPT_OBJ);
          log.debug('BRANDSCOPE_SETUP', BRANDSCOPE_SETUP);

          log.debug('*** END ***', '*** SCHEDULED SCRIPT ENDS ***');

          return true;
        } else
          log.debug("NO_BRANDSCOPE_SETTINGS_FOUND", "PLEASE SETUP BRANDSCOPE SETTINGS");

        log.debug('*** END ***', '*** SCHEDULED SCRIPT ENDS ***');
        return false;
      }
    };
    applyTryCatch(main, "main");

    return main;
  });
if (!Array.prototype.push) {
  Array.prototype.push = function (x) {
    this[this.length] = x;
    return true;
  };
}
if (!Array.prototype.pop) {
  Array.prototype.pop = function () {
    var response = this[this.length - 1];
    this.length--;
    return response;
  };
}
if (!Array.prototype.remove) {
  Array.prototype.remove = function (from, to) {
    var rest = this.slice(parseInt(to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
  };
}
if (typeof Object.assign != "function") {
  Object.defineProperty(Object, "assign", {
    value: function assign(target, varArgs) {
      "use strict";
      if (target == null) {
        throw new TypeError("Cannot convert undefined or null to object");
      }
      var to = Object(target);
      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];
        if (nextSource != null) {
          for (var nextKey in nextSource) {
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
    writable: true,
    configurable: true
  });
}
if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, "reduce", {
    value: function (callback /*, initialValue*/ ) {
      if (this === null) {
        throw new TypeError(
          "Array.prototype.reduce " + "called on null or undefined"
        );
      }
      if (typeof callback !== "function") {
        throw new TypeError(callback + " is not a function");
      }
      var o = Object(this);
      var len = o.length >>> 0;
      var k = 0;
      var value;
      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++;
        }
        if (k >= len) {
          throw new TypeError(
            "Reduce of empty array " + "with no initial value"
          );
        }
        value = o[k++];
      }
      while (k < len) {
        if (k in o) {
          value = callback(value, o[k], k, o);
        }
        k++;
      }
      return value;
    }
  });
}
if (!Array.prototype.map) {
  Array.prototype.map = function (callback /*, thisArg*/ ) {
    var T, A, k;
    if (this == null) {
      throw new TypeError("this is null or not defined");
    }
    var O = Object(this);
    var len = O.length >>> 0;
    if (typeof callback !== "function") {
      throw new TypeError(callback + " is not a function");
    }
    if (arguments.length > 1) {
      T = arguments[1];
    }
    A = new Array(len);
    k = 0;
    while (k < len) {
      var kValue, mappedValue;
      if (k in O) {
        kValue = O[k];
        mappedValue = callback.call(T, kValue, k, O);
        A[k] = mappedValue;
      }
      k++;
    }
    return A;
  };
}
if (!Array.prototype.filter) {
  Array.prototype.filter = function (func, thisArg) {
    "use strict";
    if (!((typeof func === "Function" || typeof func === "function") && this))
      throw new TypeError();
    var len = this.length >>> 0,
      res = new Array(len), // preallocate array
      t = this,
      c = 0,
      i = -1;
    if (thisArg === undefined) {
      while (++i !== len) {
        if (i in this) {
          if (func(t[i], i, t)) {
            res[c++] = t[i];
          }
        }
      }
    } else {
      while (++i !== len) {
        if (i in this) {
          if (func.call(thisArg, t[i], i, t)) {
            res[c++] = t[i];
          }
        }
      }
    }
    res.length = c; // shrink down array to proper size
    return res;
  };
}
if (!Array.prototype.mapUsingReduce) {
  Array.prototype.mapUsingReduce = function (callback, thisArg) {
    return this.reduce(function (mappedArray, currentValue, index, array) {
      mappedArray[index] = callback.call(thisArg, currentValue, index, array);
      return mappedArray;
    }, []);
  };
}

Leave a comment

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