Back to Blog

November 2, 2026

Odoo Patches a Silent Inventory Bug Where Return Orders Were Pulling Stock From the Wrong Warehouse Zone

A subtle flaw in Odoo's multi-step delivery returns caused the system to reserve returned goods from the main Stock area instead of the Output zone, creating phantom move lines and corrupting the reservation chain. The fix locks each return to its correct source location.

Diagram comparing the bug path and the fix path in a multi-step warehouse return: the bug incorrectly reserves from Stock instead of Output, while the fix correctly draws from the Output zone back to Stock

There’s a particular category of inventory bug that doesn’t throw an error, doesn’t block a shipment, and doesn’t trigger a warning banner. It just quietly moves numbers around in ways that don’t match physical reality. By the time anyone notices, the damage is spreadsheet-deep: stock counts don’t reconcile, auditors are asking questions, and warehouse managers are standing in an output zone staring at pallets the system says aren’t there.

Odoo 20 has patched exactly this kind of bug in its multi-step delivery return flow. The issue affected warehouses using a two-step (or more) delivery process — Pick, then Ship — and it only surfaced when goods were returned after a partial shipment. The fix is surgical, but the story behind it is a useful reminder of how inventory logic can silently diverge from the warehouse floor.

How Two-Step Delivery Returns Are Supposed to Work

Most warehouses that handle any meaningful volume don’t ship directly from their main storage area. Instead, they use a multi-step process. In a typical two-step delivery, a pick operation moves goods from the main Stock location to an intermediateOutputzone — a staging area near the loading dock. A second operation, the shipment, then moves those goods from Output to the Customer.

When a customer returns goods, the flow reverses. The return comes back from the Customer to Output, and from there it’s put away back into Stock. Each step has its own inventory move, and the system links those moves in a chain so it knows which return corresponds to which original shipment. The chain matters because it tells the reservation engine where to look for available quantity. If the return is supposed to land in Output first, then reservation should draw from Output’s on-hand stock — not from the main Stock location two zones away.

The Bug: Returns That Skipped the Output Zone Entirely

Here’s where things went sideways. When a delivery was returned, the system created a new return move and routed it through the standard incoming flow. That part worked fine — the move was assigned the right destination (Stock) and the right operation type (a receipt). But the code that linked the return move to its origin chain was too permissive.

Specifically, the return preparation logic connected the new move toeveryreturn of the original shipment’s destination moves. In a clean scenario — one shipment, one return — this produced the right chain. But when a shipment was only partially fulfilled, the picture got messier. Say a warehouse picked five units from Stock to Output, shipped three to the customer, and held two in Output. If the customer returned those three units, the return move linked itself to moves whose source location was the main Stock zone, not the Output zone where the goods actually lived.

The result was an inventory move line that read “Stock → Stock” instead of “Output → Stock.” No error. No warning. The system happily reserved quantity from the wrong location, the move completed, and the numbers balanced — on paper. In the physical warehouse, Output had extra units the system didn’t know about, and Stock was short by exactly the same amount.

The discrepancy compounded with every partial return. A busy warehouse processing dozens of returns per day could develop a significant gap between system records and physical reality within a few weeks, and the root cause would be nearly impossible to trace without digging into individual move chains.

The Fix: Locking Returns to Their Actual Source

The correction is elegant in its simplicity. Instead of linking a return move to every possible origin, the system now computes the return’s source location once, up front, and filters the origin chain to include only moves whose destination is a child of that location. If the return starts from the Customer and is meant to land in Output, only moves ending in Output (or its sub-locations) are linked.

The return move’s own location_idis then set from that same computed source, ensuring the entire chain stays internally consistent. Reservation draws from the correct zone, the move lines reflect what’s physically happening, and the inventory audit trail remains intact.

To validate the fix, Odoo added a regression test that mirrors the exact scenario where the bug surfaced: a two-step delivery where five units are picked, only three are shipped and then returned, and the remaining two are returned from the pick stage. The test verifies that every return move line has the correct source and destination — Output to Stock, not Stock to Stock.

Why Silent Inventory Bugs Are the Hardest to Catch

This fix won’t make headlines at the next Odoo Experience conference. It doesn’t add a new feature, redesign a dashboard, or introduce AI-powered anything. But for warehouses running multi-step delivery workflows, it addresses something arguably more important: trust in the numbers.

The insidious quality of this class of bug is that everythingappearsto work. Orders process. Returns complete. Stock levels update. It’s only when someone walks the warehouse floor, runs a cycle count, or digs into discrepancies during an audit that the misalignment becomes visible. By then, the root cause is buried under hundreds of transactions.

Odoo’s inventory module handles a staggering number of edge cases — multi-step routes, partial shipments, inter-company transfers, serial number tracking, lot-based reservations, and cross-dock workflows, to name a few. Each combination multiplies the surface area for subtle reservation bugs. The fact that this particular issue was caught, isolated, and corrected with a targeted fix rather than a sweeping refactor speaks to the maturity of the codebase.

For operations teams, the takeaway is practical: if your warehouse uses two-step or three-step delivery and you’ve noticed unexplained stock discrepancies in your output zones after processing partial shipment returns, this patch is the explanation you’ve been looking for. The numbers should line up now.

Ready to experience Odoo AI?

Join hundreds of teams using DearERP to customize Odoo in minutes, not weeks. Plans start at $29/month.