Odoo's warehouse module gives you three delivery modes: one-step (ship directly), two-step (pick then ship), and three-step (pick, pack, ship). The difference is not cosmetic. Each mode changes the number of internal transfers Odoo creates, the locations those transfers move stock between, and the order of operations pickers see in their mobile scanners.
Getting the route wrong in production means operators find nothing in their queue, orders ship from the wrong zone, or reservation fails silently because the route tries to pull from a location that has no replenishment rule. This post walks through how each mode works at the operation-type level, how to configure them without losing existing stock reservations, and how to debug when a sale order generates no delivery.
How Odoo builds a delivery from a sale order#
When a confirmed sale order generates a delivery, Odoo does not simply create one transfer. It evaluates the applicable routes on the product, the product category, and the warehouse, then creates a chain of stock.picking records connected by procurement groups.
The warehouse's outgoing shipments setting controls the base chain:
| Setting | Transfers created | Locations |
|---|---|---|
| 1 step | WH/Stock → Customers | One delivery |
| 2 steps | WH/Stock → WH/Output → Customers | Pick + ship |
| 3 steps | WH/Stock → WH/Packing → WH/Output → Customers | Pick + pack + ship |
Odoo creates all transfers immediately on sale order confirmation, but only the first in the chain is in "Ready" or "Waiting" state. Subsequent transfers wait until their preceding transfer is done.
Configuring the warehouse outgoing mode#
Go to Inventory > Configuration > Warehouses. Open your warehouse and set Outgoing Shipments to 1, 2, or 3 steps. Odoo immediately regenerates the operation types and routes associated with that warehouse. Specifically:
- 1 step: One operation type - "Delivery Orders" - with source WH/Stock and destination Customers.
- 2 steps: Two operation types - "Pick" (Stock → Output) and "Delivery Orders" (Output → Customers). A "2-step delivery route" is created in Inventory > Configuration > Routes.
- 3 steps: Three operation types - "Pick" (Stock → Packing Zone), "Pack" (Packing Zone → Output), and "Delivery Orders" (Output → Customers). A "3-step delivery route" is created.
You can verify the operation types at Inventory > Configuration > Operations Types.
Incoming shipments follow the same pattern#
The incoming side mirrors outgoing:
| Setting | Transfers created |
|---|---|
| 1 step | Vendors → WH/Stock |
| 2 steps | Vendors → WH/Input → WH/Stock (with a putaway step) |
| 3 steps | Vendors → WH/Input → WH/Quality Control → WH/Stock |
The 3-step incoming mode adds a quality control location, which lets you hold receipts for inspection before they land in stock. This integrates with the Quality Control module - Odoo can block the internal transfer from QC to Stock until a quality check passes.
How routes control which chain fires#
Every product has a Routes tab where you can force a specific fulfillment chain regardless of the warehouse default. Common routes:
- Buy: triggers procurement of a purchase order.
- Manufacture: triggers production order.
- Resupply Warehouse: moves stock between two warehouses.
- Dropship: routes the demand directly to a vendor, no internal stock movement.
- MTO (Make to Order): creates a new procurement on every sale order, bypassing existing stock.
MTO deserves extra attention. When MTO is active on a product, Odoo never reserves existing stock. It always creates a new procurement chain, even if the product has 100 units in WH/Stock. MTO is commonly activated by accident when copying a product template. Auditing stock reservations that never form - check whether MTO is inadvertently set.
Configuring a custom route#
Go to Inventory > Configuration > Routes. A custom route is a set of rules that map a source location, a destination location, and an operation type.
Each rule has a route trigger, which determines when the rule activates:
| Trigger | Activates when |
|---|---|
| Pull: from replenishment | A procurement is generated for the destination location |
| Push: from previous operation | The previous transfer in the chain is done |
| Pull & Push | Either condition |
For a 3-step delivery, the route has three rules:
- Pull - Customers ← Output (creates delivery when demand hits Output)
- Pull - Output ← Packing (creates pack transfer when demand hits Output)
- Pull - Packing ← Stock (creates pick transfer when demand hits Packing)
The chain fires backwards from demand: Odoo starts at the destination, finds a pull rule that satisfies it, and recursively finds pull rules for each resulting source location until it hits a location with stock.
Putaway rules: routing products to the right bin#
Putaway rules are separate from delivery routes. They fire when a receipt arrives and direct each product to a specific sub-location inside a main location. Configure putaway at Inventory > Configuration > Putaway Rules.
A typical rule: product "Widget A" arriving at WH/Stock → place in WH/Stock/Bin-A2. Putaway does not affect delivery routes but does affect where pickers go to fulfill a pick.
You can also define putaway rules by product category or by storage capacity (using putaway strategies), which are useful when you have a high-SKU-count warehouse where bin assignments must be dynamic.
Reservation methods on operation types#
Each operation type has a Reservation Method that controls when Odoo tries to reserve stock:
- At Confirmation: reserves immediately when the sale order is confirmed. Good for low-volume, high-certainty environments.
- Before Scheduled Date: reserves N days before the scheduled date. Balances inventory lock-up against risk.
- Manually: the warehouse manager triggers reservation manually. Useful when you want to batch-reserve for efficiency.
If the reservation method is "At Confirmation" but there is no stock, the transfer moves to "Waiting" state. It will re-attempt reservation automatically when new stock arrives via a receipt.
Debugging: why is there no delivery for this sale order?#
Common causes:
No route matches the product's origin. If the product has a route set to "Dropship" or "Manufacture" and there is no vendor or BoM, the procurement fails silently. Check Inventory > Operations > Replenishment for failed procurement runs.
MTO set on the product. The system created a new procurement but the upstream chain (purchase, manufacture) did not complete. The delivery exists but is in "Waiting for Another Operation."
Warehouse route not applied. If the product's routes list is empty and the warehouse route is inactive, no chain fires. Go to the product's Inventory tab and verify the warehouse route appears.
Negative forecasted quantity. If Odoo's forecasted stock goes negative before the scheduled date, and reservation is set to "Before Scheduled Date," the delivery stays in "Waiting."
Multiple warehouses with conflicting routes. If you have inter-warehouse resupply, the route engine can get stuck in a loop or select an unexpected warehouse as the fulfillment source. Verify route priorities (lower number = higher priority).
Checking the route chain on a specific transfer#
Open any stock.picking. The Detailed Operations tab shows source location, destination, and quantity. The Additional Info tab shows the procurement group. From the procurement group you can trace all related transfers - including any waiting upstream picks.
From the sale order, the Delivery smart button shows the transfer count and their statuses. Clicking through shows the full chain.
Batch transfers and wave picking#
If you have high-order-volume and want pickers to handle multiple orders in one walk, enable Batch Transfers in Inventory > Configuration > Settings. You can then group pick transfers into a batch and assign them to a single picker. The picker's app shows all lines consolidated, optimized for location proximity.
Wave picking is a further abstraction - you group batches into waves and process them across a shift. Odoo's Wave Transfer feature (available in Enterprise) generates these waves from forecasted demand.
Cross-docking#
Cross-docking is a route that bypasses stock: incoming goods go directly to an outgoing transfer without entering storage. Configure it by enabling the "Cross-Dock" route on the product and setting the warehouse to 2-step or 3-step incoming. Odoo creates a linked pair: receipt to Input, then immediate transfer to Output, then delivery.
Cross-docking is useful for pass-through items, vendor-managed inventory scenarios, or when storage space is constrained.
For stock valuation and costing methods, see the Odoo stock valuation guide. For reordering rules and replenishment, see the Odoo MRP reordering rules guide.

