Order Fulfillment

Order fulfillment

A how-to guide for specifying the input and output schemas in order fulfillment.

The order fulfillment app is available in one modeling language as a Mixed Integer Problem (MIP). You can also choose to make customizations to the model by instantiating the app first.

nextmv community clone -a order-fulfillment-gosdk
Copy

Once you have the code locally, you can customize the model, run it locally and deploy it to Nextmv Platform.

Input

The input schema is a JSON payload defining the items, distribution centers, carrier capacities, and carrier delivery costs . Nextmv's tools are designed to operate directly on business data (in JSON) to produce decisions that are actionable by software systems. This makes decisions more interpretable and easier to test. It also makes integration with data warehouses and business intelligence platforms significantly easier. An input contains the following components:

Field nameRequiredData typeSI UnitDescriptionExample
carton_volumeYesfloatNAThe volume of a carton.{"carton_volume": 2.0}
itemsYesarray of itemNAThe items which need to be fulfilled.See item
distribution_centersYesarray of distribution_centerNAThe distribution centers available.{"depot": 0}
carrier_capacitiesYesmap of string to map of string to floatNAThe capacities of each distribution center and carrier combination.{"carrier_capacites": {"distribution_center_1": "carrier1": 10.0, "carrier2": 25.0}}
carrier_delivery_costsYesmap of string to map of string to map of string to array of floatNAThe cost of each carrier and distribution center combination by weight tier.{"carrier_delivery_costs": "distribution_center_1": {"carrier1": {"weight_tiers": [2,3], "weight_rate": [1.2, 3.4]}}}

Item

Field nameRequiredData typeSI UnitDescriptionExample
item_idYesstringNAThe ID of the item.{"item_id": "book"}
quantityYesfloatNAThe quantity needed of the item.{"quantity": 5}
unit_volumeYesfloatNAThe volume per unit of item.{"unit_volume": 0.1}
unit_weightYesfloatNAThe quantity needed of the item.{"unit_weight": 0.6}

Distribution center

Field nameRequiredData typeSI UnitDescriptionExample
distribution_center_idYesstringNAThe ID of the distribution center.{"distribution_center_id": "distribution_center_1"}
handling_costYesfloatNAThe handling cost at the distribution center.{"handling_cost": 1}
inventoryYesmapNAThe inventory of each item available at the distribution center.{"inventory": {"book": 8, "sneaker": 5}}

Here you can find a sample .json with the input schema:

{
  "carton_volume": 2.0,
  "items": [
    {
      "item_id": "book",
      "quantity": 5,
      "unit_volume": 0.1,
      "unit_weight": 0.6
    },
    {
      "item_id": "sneaker",
      "quantity": 2,
      "unit_volume": 0.2,
      "unit_weight": 0.8
    },
    {
      "item_id": "hydrating gel",
      "quantity": 12,
      "unit_volume": 0.1,
      "unit_weight": 0.01
    },
    {
      "item_id": "pressure cooker",
      "quantity": 2,
      "unit_volume": 0.4,
      "unit_weight": 1.5
    },
    {
      "item_id": "mattress",
      "quantity": 2,
      "unit_volume": 3,
      "unit_weight": 6.5
    }
  ],
  "distribution_centers": [
    {
      "distribution_center_id": "distribution_center_1",
      "handling_cost": 1,
      "inventory": {
        "book": 0,
        "sneaker": 8,
        "hydrating gel": 4,
        "pressure cooker": 3,
        "mattress": 5
      }
    },
    {
      "distribution_center_id": "distribution_center_2",
      "handling_cost": 0.3,
      "inventory": {
        "book": 10,
        "sneaker": 6,
        "hydrating gel": 9,
        "pressure cooker": 2,
        "mattress": 4
      }
    }
  ],
  "carrier_capacities": {
    "distribution_center_1": {
      "carrier1": 10.0,
      "carrier2": 25.0
    },
    "distribution_center_2": {
      "carrier1": 21.0,
      "carrier2": 18.0
    }
  },
  "carrier_delivery_costs": {
    "distribution_center_1": {
      "carrier1": {
        "weight_tiers": [
          2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
        ],
        "weight_rates": [
          3.73, 3.76, 3.77, 3.77, 3.8, 3.88, 3.96, 4.05, 4.09, 4.11, 4.34, 4.58,
          4.62, 4.68, 4.69
        ]
      },
      "carrier2": {
        "weight_tiers": [
          2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
        ],
        "weight_rates": [
          3.97, 3.97, 4.07, 4.11, 4.18, 4.32, 4.37, 4.4, 4.52, 4.92, 5.06, 5.11,
          5.12, 5.33, 5.75
        ]
      }
    },
    "distribution_center_2": {
      "carrier1": {
        "weight_tiers": [
          2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
        ],
        "weight_rates": [
          3.73, 3.76, 3.77, 3.77, 3.8, 3.88, 3.96, 4.05, 4.09, 4.11, 4.34, 4.58,
          4.62, 4.68, 4.69
        ]
      },
      "carrier2": {
        "weight_tiers": [
          2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
        ],
        "weight_rates": [
          3.97, 3.97, 4.07, 4.11, 4.18, 4.32, 4.37, 4.4, 4.52, 4.92, 5.06, 5.11,
          5.12, 5.33, 5.75
        ]
      }
    }
  },
  "carrier_dimensional_weight_factors": {
    "carrier1": 1.33,
    "carrier2": 1.43
  }
}
Copy

Output

The output schema defines the solution to the order fulfillment problem in JSON format. The output schema contains the following components.

Field nameAlways presentData typeSI UnitDescriptionExample
solutionsYesarray of solutionNASolutions to the order fulfillment problem.{"solutions": []}
statisticsYesstatisticsNASummary statistics of the solution.{"statistics": {"total_cost": 123}}
{
  "solutions": [
    {
      "assignments": [
        {
          "carrier_id": "carrier1",
          "distribution_center_id": "distribution_center_2",
          "item_id": "book",
          "quantity": 3
        },
        {
          "carrier_id": "carrier2",
          "distribution_center_id": "distribution_center_2",
          "item_id": "book",
          "quantity": 2
        },
        {
          "carrier_id": "carrier2",
          "distribution_center_id": "distribution_center_1",
          "item_id": "sneaker",
          "quantity": 1
        },
        {
          "carrier_id": "carrier2",
          "distribution_center_id": "distribution_center_2",
          "item_id": "sneaker",
          "quantity": 1
        },
        {
          "carrier_id": "carrier2",
          "distribution_center_id": "distribution_center_1",
          "item_id": "hydrating gel",
          "quantity": 3
        },
        {
          "carrier_id": "carrier1",
          "distribution_center_id": "distribution_center_2",
          "item_id": "hydrating gel",
          "quantity": 1
        },
        {
          "carrier_id": "carrier1",
          "distribution_center_id": "distribution_center_2",
          "item_id": "hydrating gel",
          "quantity": 8
        },
        {
          "carrier_id": "carrier1",
          "distribution_center_id": "distribution_center_2",
          "item_id": "pressure cooker",
          "quantity": 1
        },
        {
          "carrier_id": "carrier2",
          "distribution_center_id": "distribution_center_2",
          "item_id": "pressure cooker",
          "quantity": 1
        },
        {
          "carrier_id": "carrier2",
          "distribution_center_id": "distribution_center_2",
          "item_id": "mattress",
          "quantity": 1
        },
        {
          "carrier_id": "carrier1",
          "distribution_center_id": "distribution_center_2",
          "item_id": "mattress",
          "quantity": 1
        }
      ],
      "billable_weights": {
        "distribution_center_1-carrier1": 2,
        "distribution_center_1-carrier2": 4,
        "distribution_center_2-carrier1": 10,
        "distribution_center_2-carrier2": 10
      },
      "cartons": {
        "distribution_center_1-carrier1": 0,
        "distribution_center_1-carrier2": 0.25,
        "distribution_center_2-carrier1": 2.3000000000000003,
        "distribution_center_2-carrier2": 1.9000000000000001
      },
      "delivery_costs": {
        "distribution_center_1-carrier1": 3.73,
        "distribution_center_1-carrier2": 3.97,
        "distribution_center_2-carrier1": 3.8000000000000003,
        "distribution_center_2-carrier2": 4.18
      },
      "dimensional_weights": {
        "distribution_center_1-carrier1": 0,
        "distribution_center_1-carrier2": 0.715,
        "distribution_center_2-carrier1": 6.118,
        "distribution_center_2-carrier2": 5.433999999999999
      },
      "status": "optimal",
      "value": 17.19,
      "volumes": {
        "distribution_center_1-carrier1": 0,
        "distribution_center_1-carrier2": 0.5,
        "distribution_center_2-carrier1": 4.6000000000000005,
        "distribution_center_2-carrier2": 3.8000000000000003
      },
      "weight_tiers": {
        "distribution_center_1-carrier1": {
          "0": 1,
          "1": 0,
          "10": 0,
          "11": 0,
          "12": 0,
          "13": 0,
          "14": 0,
          "15": 0,
          "2": 0,
          "3": 0,
          "4": 0,
          "5": 0,
          "6": 0,
          "7": 0,
          "8": 0,
          "9": 0
        },
        "distribution_center_1-carrier2": {
          "0": 0,
          "1": 1,
          "10": 0,
          "11": 0,
          "12": 0,
          "13": 0,
          "14": 0,
          "15": 0,
          "2": 0,
          "3": 0,
          "4": 0,
          "5": 0,
          "6": 0,
          "7": 0,
          "8": 0,
          "9": 0
        },
        "distribution_center_2-carrier1": {
          "0": 0,
          "1": 0,
          "10": 0,
          "11": 0,
          "12": 0,
          "13": 0,
          "14": 0,
          "15": 0,
          "2": 0,
          "3": 0,
          "4": 1,
          "5": 0,
          "6": 0,
          "7": 0,
          "8": 0,
          "9": 0
        },
        "distribution_center_2-carrier2": {
          "0": 0,
          "1": 0,
          "10": 0,
          "11": 0,
          "12": 0,
          "13": 0,
          "14": 0,
          "15": 0,
          "2": 0,
          "3": 0,
          "4": 1,
          "5": 0,
          "6": 0,
          "7": 0,
          "8": 0,
          "9": 0
        }
      },
      "weights": {
        "distribution_center_1-carrier1": 0,
        "distribution_center_1-carrier2": 0.8300000000000001,
        "distribution_center_2-carrier1": 9.89,
        "distribution_center_2-carrier2": 10
      }
    }
  ],
  "statistics": {
    "result": {
      "custom": {
        "delivery_costs": 15.68,
        "handling_costs": 1.51
      },
      "duration": 0.123,
      "value": 17.19
    },
    "run": {
      "duration": 0.123
    },
    "schema": "v1"
  },
  "version": {
    "sdk": "VERSION"
  }
}
Copy

Solution

Field nameAlways presentData typeSI UnitDescriptionExample
assignmentsYesarray of assignmentNASolution to the order fulfillment problemSee assignment

Assignment

Field nameAlways presentData typeSI UnitDescriptionExample
item_idYesstringNAID of the item.{"item_id": "book"}
quantityYesintNAQuantity of the items in the assignment.{"quantity": 1}
distribution_center_idYesstringNAID of the distribution center.{"distribution_center_id": "distribution_center_2"}
carrier_idYesstringNAID of the carrier.{"carrier_id": "carrier1"}

Statistics

Field nameAlways presentData typeSI UnitDescriptionExample
resultNoresultNAFinal result of the solutions.See result
runYesrunNAInformation about the run.See run
schemaYesstringNASchema of the statistics.{"schema": "v1"}

Here you can find additional definitions used in the statistics schema:

  • result

    Field nameAlways presentData typeSI UnitDescriptionExample
    durationYesfloatsecondsTime duration to get to the final result.{"duration": 0.123}
    valueYesfloatNAValue of the final result.{"value": 0.123}
    customYesanyNACustom solver metrics.See custom
  • run

    Field nameAlways presentData typeSI UnitDescriptionExample
    durationYesfloatsecondsTime duration of the run.{"duration": 0.123}
  • custom

    Field nameAlways presentData typeSI UnitDescriptionExample
    constraintsYesintNANumber of constraints.{"constraints": 123}
    providerYesstringNASolver provider.{"provider": "highs"}
    statusYesstringNASolver status.{"status": "optimal"}
    variablesYesintNANumber of variables.{"variables": 123}

Run options

These are the default options that are available with routing without constraints.

Nextmv Hybrid Optimization Platform VERSION
Usage:
  -runner.input.path string
    	The input file path (env RUNNER_INPUT_PATH)
  -runner.output.path string
    	The output file path (env RUNNER_OUTPUT_PATH)
  -runner.output.solutions string
    	{all, last} (env RUNNER_OUTPUT_SOLUTIONS) (default "last")
  -runner.profile.cpu string
    	The CPU profile file path (env RUNNER_PROFILE_CPU)
  -runner.profile.memory string
    	The memory profile file path (env RUNNER_PROFILE_MEMORY)
  -solve.control.bool string
    	List of solver-specific control options (configurations) with bool values. Example: "name1=value1,name2=value2", where value1 and value2 are bool values. (env SOLVE_CONTROL_BOOL)
  -solve.control.float string
    	List of solver-specific control options (configurations) with float values. Example: "name1=value1,name2=value2", where value1 and value2 are float values. (env SOLVE_CONTROL_FLOAT)
  -solve.control.int string
    	List of solver-specific control options (configurations) with int values. Example: "name1=value1,name2=value2", where value1 and value2 are int values. (env SOLVE_CONTROL_INT)
  -solve.control.string string
    	List of solver-specific control options (configurations) with string values. Example: "name1=value1,name2=value2", where value1 and value2 are string values. (env SOLVE_CONTROL_STRING)
  -solve.duration duration
    	Maximum duration of the solver. (env SOLVE_DURATION) (default 30s)
  -solve.mip.gap.absolute float
    	Absolute gap stopping value. If the problem is an integer problem the solver will stop if the gap between the relaxed problem and the best found integer problem is less than this value. (env SOLVE_MIP_GAP_ABSOLUTE) (default 1e-06)
  -solve.mip.gap.relative float
    	Relative gap stopping value. If the problem is an integer problem the solver will stop if the relative gap between the relaxed problem and the best found integer problem is less than this value. (env SOLVE_MIP_GAP_RELATIVE) (default 0.0001)
  -solve.verbosity value
    	{off, low, medium, high} Verbosity of the solver in the console. (env SOLVE_VERBOSITY)
Copy

Page last updated

Go to on-page nav menu