The standard Infoplus Cartonization process is based on using real-world dimensions of your products, plus the inner dimensions of the Carton Types you have set up in Infoplus.  


However, there are times when you may need to customize how this algorithm packs your orders.  For example, some orders may not be allowed to use all of the available Carton Types.  Or you might have a business rule that says you need each unique SKU (line item) to be assigned to its own Carton.  Infoplus allows you to customize Cartonization in cases like these, using Cartonization Scripts.  Here's how they work.


Create a Cartonization Script

To create a Cartonization Script, simply navigate to the Script table in Infoplus.  Create a new Script, and choose the Script Type of Cartonization.  


For the code in a Cartonization script, there 3 functions that you must supply, each of which allows you to customize a different part of the Infoplus Cartonization process.  Note that even if you do not want to provide any custom logic in one or more of these functions, that they still need to be present in your script, and provide a default action - else you may receive errors when using the script.  

  • customizeAvailableCartons- This function allows you to customize the carton types allowed for the given order during cartonization.  In other words, if a given order isn't allowed to ship in a particular carton type, this function can be used to make that type not available.  
    • A default version of this function would be:  utils.setOutputCartonList(utils.originalCartonList);
  • customizeCartonizationCall- This function controls whether or not Infoplus should run its standard cartonization process on the given order.  If this function tells Infoplus not to run its standard cartonization process, then you must build your own cartonization output, using the customizeCartonizationOutput function. 
    • A default version of this function would be : utils.setShouldRunCartonization(true);
  • customizeCartonizationOutput- This function runs after Infoplus has ran the default cartonization process (unless customizeCartonizationCall has told Infoplus not to run it), and it allows you to customize the output of cartonization on the given order.  For example, you could split up any carton that had more than a certain number of items in it, or you could change carton types so that an order was shipping in all identical cartons.  If customizeCartonizationCall indicated that Infoplus should not run standard cartonization, then this function must fully cartonize the order - i.e., placing all contents into cartons.
    • A default version of this function would be:  utils.log("No-op on customizeCartonizationOutput");

When you create a new Cartonization Script, Infoplus will pre-populate the Code field with a comment that describes in more detail the variables and functions available in a Cartonization Script.  


Using a Cartonization Script

To use a Cartonization Script, you can select it when defining a Fulfillment Plan or running a Fulfillment Process in Infoplus.  


If you are going to be processing various orders together, some of which should, and some of which shouldn't have the script applied to them, you may need to build some logic into your script, where you look at attributes of the order object, to make decisions about what custom logic to apply (or not to apply).


You can also specify the usage of a Cartonization Script if you are setting up a trigger to run pre cartonization on your orders.  This will help you ensure that the pre cartonization estimated cartonization plan will match the true cartonization plan that is used when your orders are fulfilled:


Example Cartonization Scripts

Only use Special Carton Types for Special Orders

In this example script, there is a certain special order type, which is only allowed to use a special type of carton type.  Also, these special cartons cannot be used for other order sources.  This script will check the order's orderSource, to see if it is a special order or not, and will customize the list of available carton types based on whether those cartonTypes have the the isSpecialCarton custom field set on them.

////////////////////////////////////////////////////////////////////////////
// customizeAvailableCartons
//
////////////////////////////////////////////////////////////////////////////
function customizeAvailableCartons()
{
   utils.log("Starting Cartonization script for Order: " + order.orderNo);

   /////////////////////////////////////////////////////////////////
   // First, check if this order is from the special order source //
   /////////////////////////////////////////////////////////////////
   var isSpecialOrder = false;
   if(order.orderSourceId == 1234)
   {
      utils.log("   Order is special - only using special cartons");
      isSpecialOrder = true;
   }
   else
   {
      utils.log("   Order is not special - only using standard cartons");
   }

   /////////////////////////////////////////
   // Loop through the cartons and check  //
   // if they are the special type or not //
   /////////////////////////////////////////
   var outputCartonList = utils.outputCartonList;
   for(var i=0; i<utils.originalCartonList.size(); i++)
   {
      var carton = utils.originalCartonList.get(i);
      var isSpecialCarton = carton.customFields.get("isSpecialCarton");

      if(isSpecialOrder && isSpecialCarton)
      {
         utils.log("   Adding Special Carton: " + carton.name);
         outputCartonList.push(carton);
      }
      else if(! isSpecialOrder && !isSpecialCarton)
      {
         utils.log("   Adding Standard Carton: " + carton.name);
         outputCartonList.push(carton);
      }
   }

   ////////////////////////////////
   // set the output carton list //
   ////////////////////////////////
   utils.setOutputCartonList(outputCartonList);
}


////////////////////////////////////////////////////////////////////////////
// customizeCartonizationCall
//
////////////////////////////////////////////////////////////////////////////
function customizeCartonizationCall()
{
   utils.log("Returning true for customizeCartonizationCall");
   utils.setShouldRunCartonization(true);
}


////////////////////////////////////////////////////////////////////////////
// customizeCartonizationOutput
//
////////////////////////////////////////////////////////////////////////////
function customizeCartonizationOutput()
{
   utils.log("Noop on customizeCartonizationOutput");
}

Pack Each Line Item in its Own Carton

In this script, we are trying to meet the requirement from a partner that each line item on an order be packed in its own carton.  A caveat to this script is the fact that we will not necessarily be choosing an optimally sized carton, nor will we recognize if too many items are being packed into a single carton.  


////////////////////////////////////////////////////////////////////////////////////
// data dictionary -- note, when copying between test & live, update these values //
////////////////////////////////////////////////////////////////////////////////////
var orderSourcesToRunFor = {};
orderSourcesToRunFor[123] = true; // order source id 123 that requires this use-case

var cartonTypeIdMap = {};
cartonTypeIdMap[999] = 47; // For my LOB Id 999, use cartonTypeId 47 



////////////////////////////////////////////////////////////////////////////
// customizeAvailableCartons
//
////////////////////////////////////////////////////////////////////////////
function customizeAvailableCartons()
{
    utils.log("Starting customizeAvailableCartons");
    utils.log("Running for Order: " + order.orderNo);
    
    /////////////////////////////////////////////////
    // always return the full list of carton types //
    /////////////////////////////////////////////////
    utils.setOutputCartonList(utils.originalCartonList);
}




////////////////////////////////////////////////////////////////////////////
// customizeCartonizationCall
//
////////////////////////////////////////////////////////////////////////////
function customizeCartonizationCall()
{
    utils.log("Starting customizeCartonizationCall for Order: " + order.orderNo);
    if(! orderSourcesToRunFor[order.orderSourceId])
    {
        utils.log("Default cartonization will be used on an order for order source [" + order.orderSourceId + "]");
        utils.setShouldRunCartonization(true);
    }
    else
    {
        utils.log("Customized cartonization (one sku per carton) will be used on an order for order source [" + order.orderSourceId + "]");
        utils.setShouldRunCartonization(false);
    }
}



////////////////////////////////////////////////////////////////////////////
// customizeCartonizationOutput
//
////////////////////////////////////////////////////////////////////////////
function customizeCartonizationOutput()
{
    utils.log("Starting customizeCartonizationOutput for Order: " + order.orderNo);
    
    if(! orderSourcesToRunFor[order.orderSourceId])
    {
        utils.log("This script will not run on an order for order source [" + order.orderSourceId + "]");
        return;
    }
    
    var cartonTypeId = cartonTypeIdMap[order.lobId];
    if(! cartonTypeId)
    {
        throw("Error in Cartonization Script:  No Carton Type Id is defined for this order's LOB (id=" + order.lobId + ")");
    }

    var cartonizationOutput = utils.cartonizationOutput;
    cartonizationOutput.clearCartons();

    ///////////////////////////////////////////////////////////////////
    // specify the cartonTypeId to use for all cartons on this order //
    ///////////////////////////////////////////////////////////////////
    var containerMap = {};

    //////////////////////////////////////////////////////
    // iterate over all "contents" (items being packed) //
    //////////////////////////////////////////////////////
    var allContents = cartonizationOutput.getAllContents();
    utils.log("allContents: " + allContents);

    for(var i=0; i<allContents.size(); i++)
    {
        var content = allContents.get(i);
        
        ///////////////////////////////////////////////////////////////////////
        // if no container for this sku has been created yet, create one now //
        ///////////////////////////////////////////////////////////////////////
        if(!containerMap[content.sku])
        {
            containerMap[content.sku] = utils.createNewContainer(cartonTypeId);
            utils.log("Adding container for sku [" + content.sku + "]");
        }
        
        ////////////////////////////////////////////////////
        // add this content to the container for this sku //
        ////////////////////////////////////////////////////
        containerMap[content.sku].addContent(content);
    }
    
    utils.log("Created [" + Object.getOwnPropertyNames(containerMap).length + "] containers.");
}