Table of Contents
Picking Class Shipment Matching Scripts
Updated by Colin
When ShipStream creates a Shipment, the final step is to assign the Shipment to a Picking Class. Each Shipment is evaluated against each Picking Class in order of the Sort Order to determine which one will be assigned. By using a script you can apply complex logic to this process so that your shipments are classified according to your needs for an efficient picking and packing operation.
See Scripting Basics to become more familiar with scripting in ShipStream in general.
Picking Class Matching
A Soft Match counts as a match but will allow remaining Picking Classes to be evaluated, and if there is another Picking Class that matches the last one wins. A Hard Match will match and short-circuit the remaining Picking Classes so that no other Picking Class will be evaluated. Essentially the Soft Match allows a match to "fall through" so that another Picking Class can be matched and a Hard Match does not.
The scripts in this case are not able to mutate any of the shipment data, they can only determine if there is a match or not. This is done by calling SoftMatch()
and HardMatch()
. If neither of these methods are called in the script execution, the Picking Class will not match the Shipment being evaluated and the next Picking Class will be evaluated until all are evaluated or there is a Hard Match.
Example Script
The following example script would result in a Hard Match for shipments that have a total weight greater than or equal to 200 lbs or a total quantity of pickable items greater than or equal to 100. If neither of these criteria are true there would be no match.
// Huge shipments
if (shipment.total_weight >= 200 || shipment.total_qty >= 100) {
HardMatch();
}
Script Data
The script is executed in a scope with three variables:
shipment
- The shipment being matchedorder
- The order of the shipment being matchedOrder
- An object exposing methods for the order of the shipment being matched
Here is an example of the data contained within these variables:
const shipment = {
"shipment_id": "1100000091",
"order_unique_id": "1100000044",
"order_ref": null,
"carrier_code": "external",
"shipping_method": "external_ltl",
"tpb_group_id": null,
"warehouse_id": "2",
"total_weight": "5.0000",
"total_qty": "5.0000",
"items": [
{
"sku": "AIR-1",
"name": "O'hare Air - Single",
"order_item_id": "172",
"qty": "1.0000",
"qty_picked": "0.0000",
"qty_shipped": "0.0000",
"qty_cancel_requested": "0.0000",
"qty_canceled": "0.0000",
"weight": "1.000",
"product": {
"sku": "AIR-1",
"name": "O'hare Air - Single",
"barcode": "AIR-1",
"external_id": null,
"vendor_sku": "BoM_Tests",
"goods_type": "NORMAL",
"regulation_id": null,
"status": "1",
"availability": "1",
"visibility": "2",
"weight": "1.0000",
"length": "9.1000",
"width": "4.1000",
"height": "4.1000",
"export_description": null,
"country_of_manufacture": null,
"customs_value_usd": null,
"hts_base_code": null,
"hts_country_code": null,
"requires_packaging": 1,
"requires_infill": null,
"require_weight_check": 1,
"confirmation_per_item": 0,
"valid_containers": [],
"special_supplies": [],
"special_other": [],
"unit_qty": 1,
"bulk_qty": null,
"max_per_package": null,
"is_ship_separate": 0,
"ship_separate_tag": null,
"can_tip": 1,
"can_contain_other_items": 0
}
},
{
"sku": "AIR-1",
"name": "O'hare Air - Single",
"order_item_id": "173",
"qty": "4.0000",
"qty_picked": "0.0000",
"qty_shipped": "0.0000",
"qty_cancel_requested": "0.0000",
"qty_canceled": "0.0000",
"weight": "1.000",
"product": {
"sku": "AIR-1",
"name": "O'hare Air - Single",
"barcode": "AIR-1",
"external_id": null,
"vendor_sku": "BoM_Tests",
"goods_type": "NORMAL",
"regulation_id": null,
"status": "1",
"availability": "1",
"visibility": "2",
"weight": "1.0000",
"length": "9.1000",
"width": "4.1000",
"height": "4.1000",
"export_description": null,
"country_of_manufacture": null,
"customs_value_usd": null,
"hts_base_code": null,
"hts_country_code": null,
"requires_packaging": 1,
"requires_infill": null,
"require_weight_check": 1,
"confirmation_per_item": 0,
"valid_containers": [],
"special_supplies": [],
"special_other": [],
"unit_qty": 1,
"bulk_qty": null,
"max_per_package": null,
"is_ship_separate": 0,
"ship_separate_tag": null,
"can_tip": 1,
"can_contain_other_items": 0
}
}
],
"solution": {
"source_type": "algorithm",
"source_id": "box_packer",
"num_containers": "1",
"containers": [
{
"qty": "1",
"product": {
"sku": "PB16824",
"name": "Plain Box 16x8x24",
"barcode": "B3",
"external_id": null,
"vendor_sku": null,
"status": "1",
"availability": "1",
"visibility": "2",
"weight": "1.3000",
"length": "16.0000",
"width": "8.0000",
"height": "24.0000"
},
"volume": "3072.0000",
"weight": 6.2999999999999998,
"length": "16.0000",
"width": "8.0000",
"height": "24.0000"
}
]
}
}
const order = {
"order_id": "62",
"unique_id": "1100000044",
"order_ref": null,
"store_code": "acme_inc",
"state": "new",
"status": "new",
"carrier_code": "external",
"shipping_method": "external_ltl",
"shipping_description": "LTL",
"weight": "5.0000",
"total_item_count": "2",
"signature_required": "none",
"saturday_delivery": "0",
"overbox": "0",
"custom_greeting": null,
"requested_ship_date": null,
"submitted_by_id": "1",
"submitted_by_type": "admin",
"other_shipping_options": "",
"declared_value": "0.000",
"backorder_policy": "default",
"priority": "50",
"tpb_group_id": null,
"desired_delivery_date": null,
"reason_for_export": null,
"customs_value": null,
"shipping_address": {
"region": "Missouri",
"postcode": "65807",
"lastname": "Goalley",
"street": "15491 West Whiteside Street",
"city": "Springfield",
"email": "celina.goalley@thompson-torp.com",
"telephone": "+444175193773",
"firstname": "Celina",
"company": "Thompson-Torp",
"classification": null,
"is_valid": null,
"shipping_name": "Celina Goalley",
"country": "US"
},
"items": [
{
"sku": "AIR-1",
"name": "O'hare Air - Single",
"weight": "1.000",
"row_weight": "1.000",
"qty_ordered": "1.0000",
"qty_backordered": "0.0000",
"qty_canceled": "0.0000",
"qty_processing": "0.0000",
"qty_shipped": "0.0000",
"allocation_data": [
{
"warehouse_id": "2",
"qty_allocated": "1.0000"
}
],
"order_item_id": "172",
"order_item_ref": null,
"product": {
"sku": "AIR-1",
"name": "O'hare Air - Single",
"barcode": "AIR-1",
"external_id": null,
"vendor_sku": "BoM_Tests",
"goods_type": "NORMAL",
"regulation_id": null,
"status": "1",
"availability": "1",
"visibility": "2",
"weight": "1.0000",
"length": "9.1000",
"width": "4.1000",
"height": "4.1000",
"export_description": null,
"country_of_manufacture": null,
"customs_value_usd": null,
"hts_base_code": null,
"hts_country_code": null,
"requires_packaging": 1,
"requires_infill": null,
"require_weight_check": 1,
"confirmation_per_item": 0,
"valid_containers": [],
"special_supplies": [],
"special_other": [],
"unit_qty": 1,
"bulk_qty": null,
"max_per_package": null,
"is_ship_separate": 0,
"ship_separate_tag": null,
"can_tip": 1,
"can_contain_other_items": 0
}
},
{
"sku": "AIR-4",
"name": "O'hare Air - 4 Pack",
"weight": "4.000",
"row_weight": "4.000",
"qty_ordered": "1.0000",
"qty_backordered": "0.0000",
"qty_canceled": "0.0000",
"qty_processing": "0.0000",
"qty_shipped": "0.0000",
"allocation_data": [
{
"warehouse_id": "2",
"qty_allocated": "1.0000"
}
],
"order_item_id": "173",
"order_item_ref": null,
"product": {
"sku": "AIR-4",
"name": "O'hare Air - 4 Pack",
"barcode": null,
"external_id": null,
"vendor_sku": "BoM_Tests",
"goods_type": "NORMAL",
"regulation_id": null,
"status": "1",
"availability": "1",
"visibility": "2",
"weight": "4.0000",
"length": "12.1000",
"width": "4.1000",
"height": "9.1000",
"export_description": null,
"country_of_manufacture": null,
"customs_value_usd": null,
"hts_base_code": null,
"hts_country_code": null,
"requires_packaging": 1,
"requires_infill": null,
"require_weight_check": 1,
"confirmation_per_item": 0,
"valid_containers": [],
"special_supplies": [],
"special_other": [],
"unit_qty": 1,
"bulk_qty": null,
"max_per_package": null,
"is_ship_separate": 0,
"ship_separate_tag": null,
"can_tip": 1,
"can_contain_other_items": 0
}
}
]
}
const Order = {
getCustomField: function(code) (),
getCustomFieldValue: function(code) (),
getCustomFieldId: function(code) (),
getCustomFieldLabel: function(code) (),
}
Custom Fields
Order Custom Fields are accessed and updated using a number of methods on the Order
object rather than properties of the order
object.
Order.getCustomField(code)
This method returns either an object or an array depending on the type of the custom field.
Field Type | Empty Return Value | Non-Empty Return Value | Example |
Text | null | Object{value: string} | {"value":"Greetings!"} |
Multiline Text | null | Object{value: string} | {"value":"Hello\nworld!"} |
Number | null | Object{value: number} | {"value":42} |
Currency | null | Object{amount: number} | {"amount":1.29} |
Select | null | Object{id: number, label: string} | {"id":13,"label":"Damaged in shipping"} |
Multiselect | [] | Array{Object{id: number, label: string}} | [{"id":13,"label":"Label 1"},{"id":15,"label":"Label 2"}] |
Yes/No | null | boolean | {"value":true} |
Date | null | string | {"value":"2023-05-09"} |
Admin User | null | Object{id: number, label: string} | {"id":51,"label":"Bernard Greensmith"} |
Client User | null | Object{id: number, label: string} | {"id":51,"label":"Bernard Greensmith"} |
null | Object{value: string} | {"value":"user@example.com"} | |
URL | null | Object{value: string} | {"value":"https://example.com"} |
Get the custom field value for a custom field with code "my_custom_field":
let myValue = Order.getCustomField('my_custom_field') // null or {"value":"x"}
Order.getCustomFieldValue(code)
Like Order.getCustomField()
above, but returns the "value" or "amount" property instead of an object. This can still return null
so make sure you account for that to avoid errors from calling methods on null
. This method cannot be used for Select, Multiselect, Admin User or Client User types.
if ((Order.getCustomFieldValue('district')||'').match(/^pattern/)) {
// do something...
}
if (Order.getCustomFieldValue('customer_since') > "2020-01-01") {
// do something...
}
Order.getCustomFieldId(code)
Like above, but returns just the "id" property for single-select fields and an array of "id" for multi-select fields.
print(order.getCustomFieldId('claim_reason')) // 13
print(order.getCustomFieldId('claim_reasons')) // [15,16]
Order.getCustomFieldLabel(code)
Like above, but returns just the "label" property for single-select fields and an array of "label" for multi-select fields.
print(order.getCustomFieldLabel('claim_reason')) // "Damaged in shipping"
print(order.getCustomFieldLabel('claim_reasons')) // ["Damaged in shipping","Did not fit"]
Cookbook
The following examples demonstrate some of the scripting capabilities you have with matching scripts. These can be combined and modified to fit your needs.
Match by specific item properties
// Match shipment by specific item properties
if (shipment.items.find(item => item.product.requires_packaging === 1)) {
HardMatch();
}
Match by shipping carrier
// Match all "External Shipping Methods"
if (shipment.carrier_code === "external") {
HardMatch();
}
Match by shipping methods
// Match all FedEx Overnight methods
const methodRegex = /^fedex_.+OVERNIGHT$/
if (shipment.shipping_method.match(methodRegex)) {
HardMatch();
}
Match by product longest dimension
// Match longest dimension greater than 24 inches
const itemMatch = shipment.items.some(function(item){
const length = parseFloat((item.product||{length:0}).length)
const width = parseFloat((item.product||{width:0}).width)
const height = parseFloat((item.product||{height:0}).height)
return Math.max(length, width, height) >= 24
})
if (itemMatch) {
HardMatch()
}
Match by container properties
// Match all shipments NOT using "Plain Box" containers
const boxRegex = /^Plain Box/
if (
! shipment.solution ||
! shipment.solution.containers.some(container => container.product.name.match(boxRegex)
) {
HardMatch()
}
Match by Other Shipping Options
The Other Shipping Options field can contain any valid JSON object. For example:
{"gift_wrap":true}
// Match all orders with "gift_wrap" flag
if (order.other_shipping_options && order.other_shipping_options.gift_wrap) {
HardMatch()
}