GuideOdoo InventoryMarch 13, 2026

Odoo 19 Multi-Warehouse Routing:
Push, Pull & Make-to-Order Rules Explained

INTRODUCTION

Your Warehouse Isn't Slow Because of People—It's Slow Because of Routing

Most Odoo implementations get warehousing wrong in the same way: everything runs through a single warehouse with one-step receipts and one-step deliveries. It works for the first six months. Then the business adds a second warehouse, or starts dropshipping, or needs quality inspection before putaway—and the entire inventory flow collapses into manual transfers and spreadsheet workarounds.

The root cause is almost always misconfigured routing rules. Odoo 19's inventory module ships with a powerful routing engine built on push rules, pull rules, and procurement groups. But the terminology is confusing, the UI hides critical settings behind "Storage Locations" and "Multi-Step Routes" checkboxes, and the documentation assumes you already understand supply chain theory.

This guide explains every layer of Odoo 19 warehouse routing from first principles: how routes and rules work internally, when to use push vs. pull, how Make-to-Order differs from Make-to-Stock, how to set up inter-warehouse replenishment, and how to configure multi-step reception and delivery flows.

01

Understanding Routes and Rules: The Core of Odoo Warehouse Routing

Before configuring anything, you need to understand the data model. In Odoo 19, all inventory movement automation flows through three objects: Routes, Rules, and Operation Types. Misunderstanding how these connect is the #1 cause of warehouse routing bugs.

The Routing Hierarchy

ObjectModelPurposeExample
Routestock.routeA named container that groups one or more rules"Receive in 2 steps (Input + Stock)"
Rulestock.ruleA single instruction: move product from location A to location B using action X"When product arrives at Input, push it to Stock via internal transfer"
Operation Typestock.picking.typeDefines the type of transfer (receipt, delivery, internal)"WH: Internal Transfers"

A Route is applied to a product, a product category, a warehouse, or a sales order line. When inventory needs to move, Odoo searches for applicable routes, finds matching rules, and creates stock transfers (pickings) accordingly. The route itself does nothing—the rules inside it do all the work.

Where Routes Can Be Applied

ScopeField LocationPriorityUse Case
Sales Order Linesale.order.line.route_idHighestOverride routing for a single order (dropship this line)
Productproduct.template.route_idsHighThis product always uses MTO or a specific warehouse route
Product Categoryproduct.category.route_idsMediumAll products in "Raw Materials" use a 2-step receipt with QC
Warehousestock.warehouse.route_idsDefaultThe warehouse's default reception and delivery routes
Priority Order Matters

When multiple routes match, Odoo resolves them from most specific to least specific: SO line → Product → Category → Warehouse. If a product has an explicit route, the warehouse default is ignored for that product. This is how you can run most products on MTS while a handful use MTO—without changing the warehouse configuration.

Enabling Multi-Step Routing in Settings

Settings — Inventory Configuration
# Navigate to: Inventory > Configuration > Settings
# Under "Warehouse" section, enable:

[x] Storage Locations    # Enables location-level tracking
[x] Multi-Step Routes    # Unlocks push/pull rule configuration

# These two checkboxes unlock the entire routing engine.
# Without them, you only get 1-step receipt and 1-step delivery.
02

Push Rules: Automatic Transfers Triggered by Incoming Stock

Push rules are the simplest routing concept in Odoo: when product arrives at location A, automatically create a transfer to move it to location B. No demand signal is needed. The mere presence of stock at the source location triggers the next move.

How Push Rules Work Internally

When a stock move is confirmed and its destination matches a push rule's source location, Odoo automatically creates a chained move from the push rule's source to its destination. The chain can be multiple steps deep: Input → Quality Control → Stock, for example, uses two push rules.

Python — Push rule record (stock.rule)
# A push rule is a stock.rule with action = 'push'
# Example: automatically move goods from Input to Stock

rule = env['stock.rule'].create({
    'name': 'Input → Stock (Auto Push)',
    'action': 'push',
    'route_id': receipt_2step_route.id,
    'location_src_id': input_location.id,      # Source: WH/Input
    'location_dest_id': stock_location.id,      # Destination: WH/Stock
    'picking_type_id': internal_transfer.id,    # Op Type: Internal Transfer
    'auto': 'manual',   # 'manual' = create picking, 'transparent' = no picking
    'delay': 0,         # Days to wait before creating the move
})

The auto Field: Picking vs. Transparent

ValueBehaviorUse Case
manualCreates a new picking (transfer document) that a warehouse worker must validateInput → Stock where someone physically moves the goods
transparentNo picking created; the move happens silently in the backgroundVirtual location transitions (e.g., partner location → input zone)

Real-World Example: 2-Step Receipt with Quality Check

XML — Route with two push rules for QC receipt
<odoo>
  <!-- Route: Receive in 2 Steps (Input + Quality) -->
  <record id="route_receipt_2step_qc" model="stock.route">
    <field name="name">Receipt: Input → QC → Stock</field>
    <field name="warehouse_selectable">True</field>
    <field name="sequence">10</field>
  </record>

  <!-- Push Rule 1: Input → Quality Control -->
  <record id="rule_push_input_to_qc" model="stock.rule">
    <field name="name">Input → Quality Control</field>
    <field name="action">push</field>
    <field name="route_id" ref="route_receipt_2step_qc"/>
    <field name="location_src_id" ref="stock.stock_location_company"/>
    <field name="location_dest_id" ref="quality_control_location"/>
    <field name="picking_type_id" ref="stock.picking_type_internal"/>
    <field name="auto">manual</field>
  </record>

  <!-- Push Rule 2: Quality Control → Stock -->
  <record id="rule_push_qc_to_stock" model="stock.rule">
    <field name="name">Quality Control → Stock</field>
    <field name="action">push</field>
    <field name="route_id" ref="route_receipt_2step_qc"/>
    <field name="location_src_id" ref="quality_control_location"/>
    <field name="location_dest_id" ref="stock.stock_location_stock"/>
    <field name="picking_type_id" ref="stock.picking_type_internal"/>
    <field name="auto">manual</field>
  </record>
</odoo>
When to Use Push Rules

Push rules are ideal for supply-driven flows: goods arrive and need to be routed to the right place regardless of demand. Quality inspection, cross-docking zones, hazmat segregation, and cold chain staging areas are all push-rule territory. If the trigger is "product showed up here," use a push rule.

03

Pull Rules: Demand-Driven Procurement and Replenishment

Pull rules work in the opposite direction from push rules: demand at location B triggers a procurement action to bring product from location A. A sales order confirms, Odoo sees demand at the customer location, and pull rules cascade backward through the supply chain to fulfill it.

How Pull Rules Cascade

When a need (procurement) is created at a destination location, Odoo searches for a pull rule whose destination matches. The rule creates a stock move and, if the source location also has a pull rule, a new procurement cascades backward. This chain continues until it reaches a source with no further pull rules (typically a vendor location or a manufacturing location).

Text — Pull rule cascade for 3-step delivery
# Customer confirms Sales Order
# Demand: 50 units at Customer Location

Step 1 (Pull Rule): Customer Location <-- Output Zone
  → Creates: Delivery Order (WH/OUT)

Step 2 (Pull Rule): Output Zone <-- Packing Zone
  → Creates: Packing Transfer (WH/PACK)

Step 3 (Pull Rule): Packing Zone <-- Stock
  → Creates: Pick Transfer (WH/PICK)

# All three transfers are created simultaneously
# when the SO is confirmed. Workers process them
# in reverse order: Pick → Pack → Ship.

Pull Rule Actions

ActionCodeWhat HappensUse Case
Pull FrompullCreates a stock move to bring goods from the source locationStandard delivery, internal transfers
Pull & Pushpull_pushCombines pull behavior with an automatic push at the destinationCross-dock scenarios
BuybuyCreates a purchase order (RFQ) instead of a stock moveMTO purchases, automated replenishment
ManufacturemanufactureCreates a manufacturing orderMTO production, kit assembly
Python — Pull rule that triggers a purchase
# Pull rule with 'buy' action: demand triggers a PO
rule = env['stock.rule'].create({
    'name': 'Buy from Vendor when Needed',
    'action': 'buy',
    'route_id': mto_route.id,
    'location_dest_id': stock_location.id,
    'picking_type_id': receipt_type.id,
    'procure_method': 'make_to_order',   # Key field for MTO
    'group_propagation_policy': 'propagate',
    'delay': 7,  # Expected vendor lead time in days
})
Push vs. Pull: The Decision Framework

Push = supply-driven (goods arrive, route them automatically). Pull = demand-driven (someone needs goods, go get them). Most warehouse flows use a combination: pull rules cascade from the sales order backward to create all the transfers, and push rules handle internal routing after goods arrive at intermediate locations. Understanding this duality is the key to designing any Odoo warehouse flow.

04

Make-to-Order vs. Make-to-Stock: Choosing the Right Procurement Strategy

MTO and MTS are not routes—they're procurement methods defined on pull rules. This distinction matters because most Odoo users confuse the MTO route with the MTO procurement method, leading to configurations that either over-order or under-deliver.

The Two Procurement Methods

MethodField ValueBehaviorInventory Impact
Make to Stock (MTS)make_to_stockFulfills demand from existing stock. If stock is insufficient, the delivery waits.Requires safety stock and reorder rules to avoid stockouts
Make to Order (MTO)make_to_orderEvery demand triggers a new procurement upstream (purchase, manufacture, or transfer)Zero inventory carrying cost but longer lead times

Configuring MTO on a Product

UI Steps — Setting up Make-to-Order
# 1. Enable the MTO route on the product
#    Product form → Inventory tab → Routes
#    Check: "Replenish on Order (MTO)"

# 2. Ensure the product has a vendor or a BoM
#    MTO needs a source. Without a vendor (for 'buy' rules)
#    or a Bill of Materials (for 'manufacture' rules),
#    the procurement will fail with:
#    "No rule has been found to replenish..."

# 3. What happens when a SO confirms:
#    - SO line creates demand at Customer Location
#    - Delivery pull rule: Customer <-- WH/Stock (procure_method='make_to_order')
#    - Because procure_method='make_to_order', Odoo does NOT check stock
#    - Instead, it cascades to the next rule: Buy or Manufacture
#    - Result: PO or MO is auto-created, linked to the SO

MTO + MTS Hybrid: The Best of Both Worlds

Odoo 19 supports a hybrid approach using reorder rules with MTO. The product uses MTS by default (ships from stock), but a reorder rule with "Make to Order" checked triggers replenishment only when stock drops below the minimum. This gives you fast delivery from stock with demand-driven replenishment:

Python — Reorder rule with MTO behavior
# Create a reorder rule that triggers on-demand procurement
reorder = env['stock.warehouse.orderpoint'].create({
    'product_id': product.id,
    'warehouse_id': warehouse.id,
    'location_id': stock_location.id,
    'product_min_qty': 10,     # Reorder when stock falls below 10
    'product_max_qty': 50,     # Order up to 50 units
    'qty_multiple': 5,         # Order in multiples of 5
    'route_id': buy_route.id,  # Use the "Buy" route for procurement
    'trigger': 'auto',         # Run scheduler automatically
})

# With this setup:
# - Sales orders ship from stock immediately (MTS behavior)
# - When stock hits 10, a PO is auto-created for 40 units
# - No manual intervention needed
When to Use Pure MTO

Use pure MTO only for high-value, low-volume, or custom-configured products where carrying inventory is expensive or impossible. Examples: custom machinery, made-to-spec components, or products with short shelf life. For everything else, MTS with reorder rules gives faster delivery and smoother operations.

05

Inter-Warehouse Replenishment: Automated Stock Transfers Between Locations

When you operate multiple warehouses, you need a way to move stock between them automatically. Odoo 19 provides inter-warehouse replenishment routes that let a secondary warehouse pull stock from a primary warehouse using the same rule engine that handles single-warehouse flows.

Setting Up a Resupply Route

UI Steps — Inter-warehouse resupply
# 1. Go to: Inventory → Configuration → Warehouses
# 2. Open the SECONDARY warehouse (the one that needs stock)
# 3. Under "Resupply From" → check the PRIMARY warehouse

# What Odoo creates automatically:
# - A new route: "Secondary: Supply Product from Primary"
# - A pull rule: Secondary/Stock <-- Primary/Stock
#   with action='pull' and picking type = inter-warehouse transit

# 4. Apply this route to products or categories:
#    Product → Inventory tab → Routes
#    Check: "Secondary: Supply Product from Primary"

# 5. Create reorder rules on the secondary warehouse
#    to trigger automatic replenishment when stock is low

The Transit Location

Inter-warehouse transfers flow through a transit location (stock.location with usage='transit'). This is critical for accounting: goods in transit are neither in the source warehouse nor the destination. The transfer creates two pickings:

Text — Inter-warehouse transfer flow
# Transfer: Primary WH → Secondary WH (50 units of Product A)

Picking 1 (Delivery from Primary):
  Source:      Primary/Stock
  Destination: Inter-Company Transit
  Op Type:     Primary: Delivery Orders

Picking 2 (Receipt at Secondary):
  Source:      Inter-Company Transit
  Destination: Secondary/Stock
  Op Type:     Secondary: Receipts

# Both pickings are linked via the same procurement group.
# Picking 2 becomes "Waiting" until Picking 1 is validated.
# This ensures accurate stock valuation during transit.

Automating with Reorder Rules

Python — Reorder rule for inter-warehouse replenishment
# Reorder rule on the secondary warehouse
# Triggers when stock falls below minimum
orderpoint = env['stock.warehouse.orderpoint'].create({
    'product_id': product.id,
    'warehouse_id': secondary_wh.id,
    'location_id': secondary_wh.lot_stock_id.id,
    'product_min_qty': 20,
    'product_max_qty': 100,
    'qty_multiple': 10,
    'route_id': resupply_route.id,  # The auto-created resupply route
    'trigger': 'auto',
})

# When the scheduler runs (or on SO confirmation if trigger='manual'):
# 1. Stock at Secondary <= 20 → procurement created
# 2. Resupply route finds the pull rule: Secondary <-- Primary
# 3. Two pickings created: Primary delivery + Secondary receipt
# 4. Warehouse workers at both sites see their tasks
Multi-Company vs. Multi-Warehouse

If your warehouses belong to different companies, you need inter-company rules (which generate purchase orders between entities) instead of simple inter-warehouse routes. Inter-warehouse resupply only works within a single company. For multi-company setups, configure the "Inter-Company Trade" setting and create vendor/customer relationships between your companies.

06

Multi-Step Reception and Delivery: Configuring Complex Warehouse Flows

Odoo 19 warehouses support 1, 2, or 3-step flows for both incoming and outgoing goods. The number of steps is configured per warehouse and determines which routes and rules Odoo auto-generates.

Reception Steps Compared

StepsFlowLocations UsedBest For
1-StepVendor → StockWH/StockSmall warehouses, low volume, no QC needed
2-StepVendor → Input → StockWH/Input, WH/StockReceiving dock staging, batch putaway
3-StepVendor → Input → QC → StockWH/Input, WH/Quality Control, WH/StockRegulated industries, high-value goods

Delivery Steps Compared

StepsFlowLocations UsedBest For
1-StepStock → CustomerWH/StockDirect shipping, small operations
2-StepStock → Output → CustomerWH/Stock, WH/OutputPick and ship, staging area needed
3-StepStock → Pack → Output → CustomerWH/Stock, WH/Packing Zone, WH/OutputE-commerce, B2B with specific packing requirements

Changing Steps on an Existing Warehouse

Python — Changing warehouse to 3-step delivery
# Change delivery from 1-step to 3-step (Pick + Pack + Ship)
warehouse = env['stock.warehouse'].browse(1)
warehouse.write({
    'delivery_steps': 'pick_pack_ship',
    # Options: 'ship_only', 'pick_ship', 'pick_pack_ship'
})

# Change reception from 1-step to 2-step (Input + Stock)
warehouse.write({
    'reception_steps': 'two_steps',
    # Options: 'one_step', 'two_steps', 'three_steps'
})

# Odoo automatically:
# 1. Creates the new locations (WH/Packing Zone, WH/Output)
# 2. Creates new operation types (WH: Pick, WH: Pack)
# 3. Creates the route with chained pull rules
# 4. Archives the old 1-step route

# WARNING: Changing steps while transfers are in progress
# does NOT retroactively update existing pickings.
# Complete or cancel all open transfers first.

Mixing Steps Across Warehouses

Each warehouse can have its own step configuration. Your main distribution center might use 3-step delivery (Pick + Pack + Ship) while a satellite warehouse uses 1-step. The routing engine handles this transparently—sales orders routed to different warehouses will create the appropriate number of transfers based on each warehouse's configuration.

Performance Consideration

Every additional step creates an additional stock.picking record and associated stock.move records. For high-volume warehouses processing 1,000+ orders per day, 3-step delivery means 3,000+ pickings daily. Make sure your scheduler cron (ir.cron for stock.warehouse.orderpoint) and your database can handle the load. Index stock_move.state and stock_picking.state if you haven't already.

07

3 Multi-Warehouse Routing Mistakes That Cause Inventory Chaos

1

Enabling MTO Without a Fallback Procurement Source

You check the "Replenish on Order (MTO)" route on a product and confirm a sales order. Instead of a purchase order or manufacturing order appearing, you get a red error: "No rule has been found to replenish product X in WH/Stock." The sales order is stuck, the customer is waiting, and your operations team has no idea what to do.

Our Fix

MTO is not a complete route—it's a modifier on the procurement method. It tells Odoo "don't fulfill from stock, cascade upstream." But "upstream" needs to exist. The product must have either a vendor with a vendor pricelist (for the Buy rule) or a Bill of Materials (for the Manufacture rule). Before enabling MTO on any product, verify the supply chain is configured end-to-end by running Inventory → Operations → Replenishment and checking for errors.

2

Conflicting Routes on Products and Warehouses

A product has both the "Buy" route and the warehouse's default "Receive in 1 step" route. A reorder rule triggers replenishment. Odoo creates two separate procurements—one from each route—and you end up with duplicate purchase orders. Or worse: the rules conflict, and Odoo picks the wrong one based on sequence numbers you never configured.

Our Fix

Audit every product's route assignments with a domain search: env['product.template'].search([('route_ids', '!=', False)]). Products should have at most one procurement route (Buy, Manufacture, or a custom resupply route). The warehouse routes (reception/delivery steps) are separate and don't conflict. When in doubt, remove product-level route assignments and let the warehouse defaults handle routing. Only add product-level routes for exceptions (MTO products, dropship items).

3

Changing Warehouse Steps with Open Transfers in Progress

You switch your warehouse from 1-step to 3-step delivery while 200 delivery orders are in "Ready" state. The existing pickings don't update—they still reference the old route and locations. New orders use the 3-step flow. Now you have two parallel workflows running in the same warehouse, workers are confused about which transfers to process, and some orders ship directly from Stock while others go through Pick → Pack → Ship.

Our Fix

Never change warehouse steps during business hours with open transfers. Schedule the change during a maintenance window. Before switching: validate or cancel all open pickings, run the scheduler to clear pending procurements, and take a database backup. After switching: verify the new locations exist, test with a single order end-to-end, and only then resume normal operations. Document the cutover time so your accounting team knows which transfers used which flow.

BUSINESS ROI

What Proper Multi-Warehouse Routing Saves Your Business

Routing isn't a technical exercise. It's a direct lever on fulfillment speed, inventory cost, and order accuracy:

30-50%Faster Fulfillment

Multi-step routing with automated transfers eliminates manual handoffs. Workers see exactly what to pick, pack, and ship—no guessing, no spreadsheets, no radio calls to the dock.

15-25%Lower Carrying Costs

MTO for slow-movers and inter-warehouse replenishment rules mean you stock the right products in the right warehouse. No more overstocking satellite locations "just in case."

90%+Reduction in Routing Errors

Automated push and pull rules replace manual transfer creation. When the system decides where goods go, human routing errors drop to near zero.

For a company operating 3 warehouses with 500 SKUs, properly configured routing typically eliminates 2-3 full-time-equivalent hours per day of manual transfer creation and reduces mis-ships by 80%. Over a year, that's 700+ labor hours saved and thousands of dollars in shipping corrections avoided.

SEO NOTES

Optimization Metadata

Meta Desc

Complete guide to Odoo 19 multi-warehouse routing. Learn push rules, pull rules, MTO vs MTS strategies, inter-warehouse replenishment, and multi-step reception/delivery configuration.

H2 Keywords

1. "Understanding Routes and Rules: The Core of Odoo Warehouse Routing"
2. "Push Rules: Automatic Transfers Triggered by Incoming Stock"
3. "Pull Rules: Demand-Driven Procurement and Replenishment"
4. "Make-to-Order vs. Make-to-Stock: Choosing the Right Procurement Strategy"
5. "Inter-Warehouse Replenishment: Automated Stock Transfers Between Locations"
6. "Multi-Step Reception and Delivery: Configuring Complex Warehouse Flows"

Stop Fighting Your Warehouse—Let the Routing Engine Do Its Job

Every manual stock transfer, every "where did that shipment go?" email, and every satellite warehouse running on gut-feel reordering is a symptom of misconfigured routing. Odoo 19's push and pull rule engine is powerful enough to automate multi-warehouse operations for companies running thousands of SKUs across dozens of locations—but only if the routes, rules, and procurement methods are configured correctly.

If your warehouse team is still creating manual transfers or your MTO products keep failing procurement, we should talk. We audit and redesign Odoo warehouse routing for companies that have outgrown their initial configuration. The typical engagement takes 3-5 days and the efficiency gains show up in your first week of operations.

Book a Free Warehouse Routing Audit