Here are some real-world examples of solutions that have been built in Infoplus using Scripts.  


Automatically place Orders on Hold

Use Case:  You want to place a Hold on any Order that is placed meeting certain conditions (such as, for a total value over some amount, or for a specific line item, or with a special ship-to destination).  


This script could be assigned to run with a Trigger that searched for new Orders containing the Item "SOURCE".

order.holdCode = "H";
 
// explicitly clear these values, to avoid "not modifyable" error
order.extraLineItemData = null;
order.extraOrderData = null;
 
utils.log("Will try to set order " + order.orderNo + " hold code to H...");
infoplusApi.update("order", order);
utils.log("Set order " + order.orderNo + " hold code to H");


Update the names of all Third Party Parcel Accounts to match their Account Numbers

Use Case:  To clean up the data in your Third Party Parcel Account table, you want to update all records so that their Account Names match their Account Numbers.  


This can be done by creating a simple script like this, then selecting rows from the Third Party Parcel Accounts table and using the Bulk Run Script process.

thirdPartyParcelAccount.accountName = thirdPartyParcelAccount.accountNo;
utils.log("Updating thirdPartyParcelAccount [" + thirdPartyParcelAccount.id + "] to have name [" + thirdPartyParcelAccount.accountName + "].");
infoplusApi.update("thirdPartyParcelAccount", thirdPartyParcelAccount);


Split an Order into Two Orders

Use Case:  Any time an Order is placed for the Item "SOURCE", a second order should be created, with the same root order number, for the Item "TARGET".


This script could be assigned to run with a Trigger that searched for new Orders containing the Item "SOURCE".

var SOURCE_SKU = "SOURCE";
var TARGET_SKU = "TARGET";

var sourceLineItem = null;
if(order.lineItems)
{
   for(var i=0; i<order.lineItems.size(); i++)
   {
      if(order.lineItems.get(i).sku == SOURCE_SKU)
      {
         sourceLineItem = order.lineItems.get(i);
         break;
      }
   }
}

if(sourceLineItem == null)
{
   utils.log("Did not find source sku [" + SOURCE_SKU + "] on order.  Exiting.");
   return;
}

var blankOrder = infoplusApi.constructModel("order");
var newOrder = infoplusApi.duplicate("order", order.orderNo);
newOrder.lineItems = blankOrder.lineItems;

var newLineItem = infoplusApi.duplicate("orderLine", sourceLineItem.id);
newLineItem.sku = TARGET_SKU;
newLineItem.orderedQty = sourceLineItem.orderedQty;

newOrder.addToLineItems(newLineItem);
newOrder.useOrderNoRoot = Math.floor(order.orderNo);
newOrder.holdCode = null;
newOrder.carrierId = 0;
newOrder.needByDate = null;
newOrder.deliverOnDate = null;
newOrder.shipVia = null;

var addedOrder = infoplusApi.add("order", newOrder);
utils.log("Created order [" + addedOrder.orderNo + "] with SKU [" + TARGET_SKU + "].");


Modify an Order based on Extraneous data from a Shopping Cart

Use Case:  For any Orders from your Shopify site, if they have a "shipping code" of "Priority", update them to ship from warehouse 47.


Comments:  Infoplus stores all data available from the Shopping Cart's API when it pulls orders.  These data all go into the order's "extra data" sub-table.  The script below includes a function which loops over the extra data on an order, looking for a specified value (in this case, the one with the code of "SHOP-SHIPPING_LINES.0.CODE").  


This script could be assigned to run with a Trigger that searched for new Orders with an Order Source that corresponded to your Shopify shopping cart connection.

function getOrderExtraData(order, code)
{
   var extraDataList = order.extraOrderData;
   if(extraDataList != null)
   {
      for(var i=0; i<extraDataList.size(); i++)
      {
         var extraData = extraDataList.get(i);
         if(extraData.code == code)
         {
            return(extraData.value);
         }
      }
   }
   return(null);
}

var shippingCode = getOrderExtraData(order, "SHOP-SHIPPING_LINES.0.CODE")
if(shippingCode == null)
{
   utils.log("Order [" + order.orderNo + "] does not have a shipping code.");
   return;
}


if(shippingCode == "Priority")
{
   utils.log("Order [" + order.orderNo + "] has shipping code [" + shippingCode + "] - switching order Warehouse");
   order.warehouseId = 47;
   infoplusApi.update("order", order);
   
   infoplusApi.addTag("order", order.orderNo, "Priority-Shipping");
   infoplusApi.addAudit("order", order.orderNo, "This order's shipping code was 'Priority', so its warehouse was changed via Infoplus Script");
}


Tag Orders where all lines are in a set of SKUs

Use Case: For any orders with multiple SKUs, where you want to 'include only' a search criteria containing exclusively the SKUs you're searching for, verbatim, and not a list of all orders containing any one of the SKUs mentioned.
For example:

                        I want to 'Include Only'
                        INBK201708CA
                        WI6PK1
                        WISB01480CA
                        WISB01572CA
                        WISB01743CA
                        WISB01745CA
                        WISB01878CA
                        WISB02540CA

In Infoplus, if you searched on the order table, you would receive a list of all orders containing any one of those SKUs. This script allows you to define a set of SKUs to consider, and it will search for orders that only have that set of SKUs. This script can run against the order table (once you have edited the script to include the SKUs you'd like to consider).  
var skuSet = {};

// Here, we define the set of SKUs that you want to consider.  Each SKU gets its own line.
skuSet["BASIC1"] = 1;
skuSet["BASIC2"] = 1;
skuSet["BASIC3"] = 1;

// Here, we define the tag name that you want applied to the orders 
var tagName = "all-lines-were-in-set";

// Below here we will look at all of the line items on the order.  
// If all are in the skuSet, we will then put the tag on the order.
utils.log("Looking at line items on order [" + order.orderNo + "]");
for(var i=0; i<order.lineItems.size(); i++)
{
   var sku = order.lineItems.get(i).sku;
   utils.log("Looking at line [" + i + "] which is sku [" + sku + "]");
   if(skuSet[sku])
   {
      utils.log("- This SKU is in the set!");
   }
   else
   {
      utils.log("- This SKU is NOT in the set.  Exiting.");
      return;
   }
}

utils.log("All lines on the order were in the set.");
utils.log("Tag [" + tagName + "] will be added to the order.");
infoplusApi.addTag("order", order.orderNo, tagName);



Change carrier for Order in FedEx's Zone 2

Use Case: Change the carrier for any order that's shipping to a ZIP code that's included in FedEx's "Zone 2".


For example, in the script below we are using a hash map which includes the first 3 digits of all possible ZIP codes in Zone 2.  Whenever an order comes across with a Ship To ZIP code whose first 3 digits matches one of the ZIP codes in zone 2, change the carrier to carrierId 7000 (FedEx Ground).  If it doesn't match, therefore not being in zone 2, change the carrier to carrierId 7002 (FedEx 2-Day).  


This script can be adapted to include other zones and carriers.

// Initialize mySet to a hash map with all the zone 2 ZIP codes
var mySet = {'005': true, '012': true, '060': true, '061': true, '062': true, '063': true, '064': true, '065': true, '066': true, '067': true, '068': true, '069': true, '070': true, '071': true, '072': true, '073': true, '074': true, '075': true, '076': true, '077': true, '078': true, '079': true, '080': true, '081': true, '082': true, '083': true, '084': true, '085': true, '086': true, '087': true, '088': true, '089': true, '090': true, '091': true, '092': true, '093': true, '094': true, '095': true, '096': true, '097': true, '098': true, '099': true, '100': true, '101': true, '102': true, '103': true, '104': true, '105': true, '106': true, '107': true, '108': true, '109': true, '110': true, '111': true, '112': true, '113': true, '114': true, '115': true, '116': true, '117': true, '118': true, '119': true, '124': true, '125': true, '126': true, '127': true, '137': true, '138': true, '139': true, '168': true, '169': true, '170': true, '171': true, '172': true, '173': true, '174': true, '175': true, '176': true, '177': true, '178': true, '179': true, '180': true, '181': true, '182': true, '183': true, '184': true, '185': true, '186': true, '187': true, '188': true, '189': true, '190': true, '191': true, '192': true, '193': true, '194': true, '195': true, '196': true, '197': true, '198': true, '199': true, '200': true, '201': true, '202': true, '203': true, '204': true, '205': true, '206': true, '207': true, '208': true, '209': true, '210': true, '211': true, '212': true, '214': true, '216': true, '217': true, '218': true, '219': true, '220': true, '221': true, '222': true, '223': true};
var zipCode = order.shipToZip;
var zipCodeFirstThree = zipCode.substring(0,3);

utils.log("The first 3 digits of the Ship To ZIP are " + zipCodeFirstThree);
utils.log("mySet[zipCodeFirstThree] = " + mySet[zipCodeFirstThree]);

// If the first 3 digits of the shipTo ZIP code match any of the values in mySet, change the carrier to FedEx Ground
if(mySet[zipCodeFirstThree])
{
    order.carrierId = 7000;
}

// If the first 3 digits of the shipTo ZIP code didn't match the values in mySet, change the carrier to FedEx 2nd day.
else
{
    order.carrierId = 7002;
}

infoplusApi.update("order", order);



Change an Order containing Items set as Hazmat to land on hold with a Tag

Use Case: When an Order lands for an Item set up as Hazmat, place the Order on hold and add a tag to it.

if(order.lineItems)
{
   var targetHoldCode = "H";
   if(order.holdCode.equals(targetHoldCode))
   {
      utils.log("Order already has holdCode " + targetHoldCode);
   }
   else
   {
      ///////////////////////////////////////////////////
      // setup a filter for all the items on the order //
      ///////////////////////////////////////////////////
      var itemFilter = "lobId eq " + order.lobId + " and sku in (";

      for(var i = 0; i < order.lineItems.size(); i++)
      {
         var lineItem = order.lineItems.get(i);
         itemFilter += (i > 0 ? "," : "") + "'" + lineItem.sku + "'";
      }
      itemFilter += ")";

      var orderContainsHazmat = false;
      var items = infoplusApi.search("item", itemFilter, null, 100, null);

      if(items.size() > 0)
      {
         /////////////////////////////////////////////////////////
         // iterate over item list looking for any hazmat items //
         /////////////////////////////////////////////////////////
         for(var i = 0; i < items.size(); i++)
         {
            var item = items.get(i);
            if(item.hazmat.equals("Yes"))
            {
               utils.log("Found Hazmat sku " + item.sku + " or order");
               orderContainsHazmat = true;
               break;
            }
         }
      }
      else
      {
         utils.log("No items found from order line items");
      }

      if(orderContainsHazmat)
      {
         ////////////////////////////////////////////////////////////////////
         // explicitly clear these values, to avoid "not modifyable" error //
         ////////////////////////////////////////////////////////////////////
         order.extraLineItemData = null;
         order.extraOrderData = null;

         ////////////////////////////
         // add a tag to the order //
         ////////////////////////////
         infoplusApi.addTag("order", order.orderNo, "hazmat-shipment");

         //////////////////////////////////
         // put a hold code on the order //
         //////////////////////////////////
         order.holdCode = targetHoldCode;

         utils.log("setting order hold on " + order.orderNo + " found hazmat items");
         infoplusApi.update("order", order);
      }
   }
}


Calculate Average Daily Storage in Cubic Feet for Items

Use Case:  To know, at the end of a month, the daily average cubic feet of storage space used for each item.  


This script is a Report type script, which is meant to be used with a report from the Items table.  The report must contain the following columns:  SKU, LOB, Length, Width, Height.  The Smart Filter that is used to create the report will determine which Items are included in the report. 


The script will, for each item in the report, lookup all Inventory Snapshot records for the item for the previous month, summing all quantities together, then dividing by the number of days in the month, to get the average daily quantity.  Then it will multiply that number by the item's dimensions, and add the computed column to the report.  

///////////////////////////////////////////////////////////////
// set the first/min date to the 1st of the previous month,  //
// by subtracting one from today's month, then set date to 1 //
///////////////////////////////////////////////////////////////
var minDate = new Date();
minDate.setMonth(minDate.getMonth() - 1);
minDate.setDate(1);

////////////////////////////////////////////////////////////////////////
// set the last/max date to the last day of the previous month,       //
// by just making a new date (today), and setting to the 0th of this  //
// month (which gets auto-adjusted to the last day of previous month) //
////////////////////////////////////////////////////////////////////////
var maxDate = new Date();
maxDate.setDate(0);

///////////////////////////////////////////////////////////////////////////////////////////////////////
// the number of days we'll be running for is the date field from the maxDate (ie, 28, 29, 30 or 31) //
///////////////////////////////////////////////////////////////////////////////////////////////////////
var totalDays = maxDate.getDate();

///////////////////////////////////
// reformat dates for api filter //
///////////////////////////////////
minDate = (1900+minDate.getYear()) + "-" + (1+minDate.getMonth()) + "-" + (minDate.getDate()) + "T00:00:00.000Z";
maxDate = (1900+maxDate.getYear()) + "-" + (1+maxDate.getMonth()) + "-" + (maxDate.getDate()) + "T00:00:00.000Z";

utils.log("Running for date range [" + minDate + "] through [" + maxDate + "] (" + totalDays + " days)");



///////////////////////////////////////////////////////////////////////////
// object to store item identifiers (lobName & sku) mapped to quantities //
// and functions to add to these values and fetch them                   //
///////////////////////////////////////////////////////////////////////////
var quantityMap = {};

function addQuantity(lob, sku, quantity)
{
    var key = lob + "\n" + sku;
    if(! quantityMap[key])
    {
        quantityMap[key] = 0;
    }
    
    quantityMap[key] = Number(quantityMap[key]) + Number(quantity);
}

function getTotalQuantity(lob, sku)
{
    var key = lob + "\n" + sku;
    return(quantityMap[key]);
}



///////////////////////////////////////////////
// object to store lob names mapped to ids   //
// and function to populate and use this map //
///////////////////////////////////////////////
var lobIdMap = {};
function getLobId(lobName)
{
    if(!lobIdMap[lobName])
    {
        var lobs = infoplusApi.search("LineOfBusiness", lobName, null, null, null);
        if(lobs && lobs.size())
        {
            var lob = lobs.get(0);
            lobIdMap[lobName] = lob.id;
        }
    }
    
    return(lobIdMap[lobName]);
}



////////////////////////////////////////////////////////////
// look up inventorySnapshots for all items in the report //
////////////////////////////////////////////////////////////
var PAGE_SIZE = 250;
for(var i=0; i<report.originalRows.size(); i++)
{
    var reportRow = report.originalRows.get(i);
    var sku = reportRow.get("SKU");
    var lobName = reportRow.get("LOB");
    
    if(! sku)
    {
        throw("Error:  SKU column must be present in report");
    }   
    
    if(! lobName)
    {
        throw("Error:  LOB column must be present in report");
    }

    var lobId = getLobId(lobName);
    if(! lobId)
    {
        throw("Error:  LOB Id could not be found for LOB name: " + lobName);
    }
    
    ///////////////////////////////////////////////
    // seed the quantity map with 0 for the item //
    ///////////////////////////////////////////////
    addQuantity(lobName, sku, 0);
    utils.log("\nProcessing SKU: " + sku);

    ////////////////////////////////////////////////////////////////////////////////////////////////////
    // lookup all InventorySnapshot rows for this item in the month (rows a per (sku, location, date) //
    // Just sum them all together per sku (not caring how many there are by date),                    //
    // since we'll just be dividing the item's sum by the number of days in the end.                  //
    ////////////////////////////////////////////////////////////////////////////////////////////////////
    var filter = "lobId eq " + lobId + " and sku eq '" + sku + "' and snapshotDate between ('" + minDate + "','" + maxDate + "')";
    for(var pageNo = 1; pageNo < 1000; pageNo++)
    {
        utils.log("Searching for inventory snapshots, page: " + pageNo + ", filter: " + filter);
        var inventorySnapshots = infoplusApi.search("InventorySnapshot", filter, pageNo, PAGE_SIZE, 'id');
        if(inventorySnapshots && inventorySnapshots.size())
        {
            utils.log("   Found [" + inventorySnapshots.size() + "] results.");
            for(var j=0; j<inventorySnapshots.size(); j++)
            {
                var inventorySnapshot = inventorySnapshots.get(j);
                addQuantity(lobName, sku, inventorySnapshot.quantity);
            }
            
            if(inventorySnapshots.size() < PAGE_SIZE)
            {
                utils.log("   Breaking loop - less than a full page of [" + PAGE_SIZE + "] results was found.");
                break;
            }
        }
        else
        {
            utils.log("   Breaking loop - no results were found.");
            break;
        }
    }
}



////////////////////////////////////
// add the new data to the report //
////////////////////////////////////
report.addColumn("Average Daily On Hand");
report.addColumn("Average Daily Cubic Feet");
for(var i=0; i<report.originalRows.size(); i++)
{
    var reportRow = report.originalRows.get(i);
    var sku = reportRow.get("SKU");
    var lobName = reportRow.get("LOB");
    var length = reportRow.get("Length (in)")
    var width = reportRow.get("Width (in)")
    var height = reportRow.get("Height (in)")
    
    var totalMonthlyOnHand = getTotalQuantity(lobName, sku);    
    var averageDailyOnHand = totalMonthlyOnHand / totalDays;
    reportRow.put("Average Daily On Hand", averageDailyOnHand.toFixed(2));

    if(length && width && height)
    {
        var averageCubicFeet = (length * width * height * averageDailyOnHand) / (12*12*12);
        if(averageCubicFeet)
        {
            reportRow.put("Average Daily Cubic Feet", averageCubicFeet.toFixed(2));   
        }
    }
    report.addRow(reportRow);
}


Apply Custom multi-field sorting to a User Report

Use Case:  To sort rows in a User Report by more than just one field.


The bottom half of this script is completely generic, and can be used on any User Report in Infoplus (everything from the // copy the rows comment to the bottom).  The compare function at the top of the script can be customized to look at whatever fields you want to sort by (adding more fields, or using whatever field names you need).  Be careful that you may need to deal with missing value (possibly represented as "--" in the report).  

//////////////////////////////////////////////////////////////////////////////
// custom compare function - takes 2 report rows as input                   
// returns -1 if a comes before b, 1 if a comes after b, or 0 if they tie.
//
//////////////////////////////////////////////////////////////////////////////
function compare(a, b)
{
    /////////////////////////////////////////////////////////////////////////////
    // get first field value - if they differ, return -1 or 1 - else continue. //
    /////////////////////////////////////////////////////////////////////////////
    var skuA = a.get("SKU");
    var skuB = b.get("SKU");
    if(skuA < skuB)
    {
        return(-1);
    }
    else if(skuA > skuB)
    {
        return(1);
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // get next field value - if they differ, return -1 or 1 - else continue. //
    ////////////////////////////////////////////////////////////////////////////
    var receivedDateA = new Date(a.get("Received Date"));
    var receivedDateB = new Date(b.get("Received Date"));
    if(receivedDateA < receivedDateB)
    {
        return(-1);
    }
    else if(receivedDateA > receivedDateB)
    {
        return(1);
    }

    /////////////////////////////////////////////
    // at this point, they're a tie - return 0 //
    /////////////////////////////////////////////
    return(0);
}

///////////////////////////////////////////
// copy the rows into a javascript array //
///////////////////////////////////////////
var rows = [];
for(var i=0; i<report.originalRows.size(); i++)
{
    rows.push(report.originalRows.get(i));
}

/////////////////////////////////////////////////
// sort that array, using our compare function //
/////////////////////////////////////////////////
rows.sort(compare);

///////////////////////////////////////
// put the sorted rows in the report //
///////////////////////////////////////
for(var i=0; i<rows.length; i++)
{
    report.addRow(rows[i]);
}