Skip to content

Map Handling Policy

Map raw rows into the scenario's handling policy table: the rule for handling cost at each location, what it costs to move one unit through that facility in warehouse fees, loading, unloading and processing.

This is the input side of handling. Pair it with Map Handling State on baselines that also need observed totals.

When to use this

  • A facility charges per-unit handling fees that should enter the cost the optimizer minimizes
  • You want handling to enter the routing decision rather than sit outside it

Without it, handling is free in the optimizer's arithmetic. A high handling cost at a hub can flip a routing decision, so leaving it out makes hub routing look cheaper than it is.

What you need

  • An upstream Import Data node with one row per (location, product) handling rate
  • A column identifying the facility, matching a location identifier
  • A per-unit handling cost. If you only have realized totals, use Map Handling State instead
  • The unit the cost is per, such as pallet or kg: a column, or one unit for the whole file

Field mapping

Fields are matched by name unless you set them. When the workflow runs, every field you have not set a column for is matched against the headers listed below, case-insensitively and ignoring spaces around the header, and a space inside your header reads as an underscore, so Site Name matches site_name. Setting a column for one field fixes that field only; the others keep following your file's headers, so a renamed column is still found. A required field that no column supplies — no header matched, or you set none or one your table lacks — is reported once, with the headers your table does have.

Set mappings in the node's panel. Connect an upstream table and select the mapping node. A field matched by name is marked Matched by name; pick a column to set it yourself, and Match by name puts it back. Match all by name clears every field you set. Required fields without a match are marked in the panel.

Reshape rows in a Script first. A mapping node only says which column is which field. To drop rows, recode values, or split or combine columns, connect a Script node before it and map the columns the Script returns.

Same for every row. A file with no unit column still states its unit: in Quantity Unit, pick Same for every row and type the unit, such as pallets, and every row is in it. Over MCP, set it in field_mappings as "quantity_unit": "__const__:pallets". Quantity Unit is required on every row with Unit Handling Cost, and the panel marks it required once it is mapped.

Field Type Required Example What it is Auto-detected headers
Location text Yes Warehouse A Where handling happens. Must match a Location name. location, loc, name, id, location_id, loc_id
Product text Yes Widget Product or SKU handled, or ALL for a rate that applies to every product at this location. Any other value must match a Product name. product, sku, item, material, product_id
Unit Handling Cost number No 0.5 Cost to handle one unit passing through this location, in the scenario currency per the row's Quantity Unit. Blank = handling is free. Must be greater than or equal to 0. unit_handling_cost, handling_fee, processing_cost, handling_rate
Quantity Unit text No pallets Unit the handling cost is per. Required on every row that states a cost. On an ALL row in another unit than the scenario's, each product's cost is converted with its own conversion. quantity_unit, qty_unit, unit, uom

How it works

Each row becomes a handling policy record. Network Optimization treats Unit Handling Cost as the fee charged on throughput at that facility. Total handling cost is the rate times throughput. To write a location-wide rate, set the product to ALL. A location has either one ALL row or rows of its own for each product, never both: an ALL row beside a row naming a product at the same location, or two rows for one product there, is refused with both rows named. To give one product a different rate, replace the ALL row with a row for each product.

Every cost states its unit. Quantity Unit says what one unit of the cost is: 11 EUR per pallet is a different cost from 11 EUR per kg. Create Scenario refuses a row with a cost and no unit, and a unit with no conversion to the scenario's Unit. An ALL row in another unit than the scenario's is converted for each product with that product's own conversion, so 11 EUR per pallet is a different cost per kg for each product.

Cost to Serve does not read this table. It allocates the realized total on handling state. Network Optimization writes that total from this rate and the solved throughput, so an optimized scenario carries handling into the per-customer breakdown. A scenario that was never optimized has handling cost to allocate only from Map Handling State.

Workflow wiring

For an optimization, wire the policy side beside the tables Network Optimization needs: locations, products, lanes, and the supply and demand policies.

flowchart LR
    n1["Import Data (locations.csv)"] --> n2["Map Locations"]
    n3["Import Data (products.csv)"] --> n4["Map Products"]
    n5["Import Data (lanes.csv)"] --> n6["Map Lanes"]
    n7["Import Data (supply.csv)"] --> n8["Map Supply Policy"]
    n9["Import Data (demand.csv)"] --> n10["Map Demand Policy"]
    n11["Import Data (handling.csv)"] --> n12["Map Handling Policy"]
    n2 & n4 & n6 & n8 & n10 & n12 --> n13["Create Scenario"]
    n13 --> n14["Network Optimization"]
    n14 --> n15["Create Scenario (optimized)"]

For a baseline that also preserves observed totals, fan the file out to both:

flowchart LR
    n1["Import Data (handling.csv)"] --> n2["Map Handling Policy"]
    n1 --> n3["Map Handling State"]
    n4["Import Data (locations.csv)"] --> n5["Map Locations"]
    n6["Import Data (products.csv)"] --> n7["Map Products"]
    n2 & n3 & n5 & n7 --> n8["Create Scenario"]

Common mistakes

  • Mapping a realized total to Unit Handling Cost. The rate goes on policy. The total belongs on Map Handling State.
  • Leaving Quantity Unit blank. A cost per unit with no unit is refused, not read as the scenario's unit.
  • Leaving this node out of a network with hub routing. Handling is then free in the optimizer's arithmetic, and routing through the hub always looks cheap.

Messages this node can show

The table this node makes is checked again with the rest of the scenario when Create Scenario assembles it: see messages about the scenario.

A run gives this node 5 minutes. A node that takes longer stops with Time limit reached.

Like every node, it can also stop on the checks before a run and the run's limits.