The most common inventory bug in distribution is the same one, in every company, regardless of size: treating reserved stock as still on hand. It's the root cause behind overselling, behind warehouse-team distrust of the sales team, behind the frantic Saturday-morning phone calls when a driver shows up to pick product that isn't there.
The single-field trap
If your stock table has one column β quantity β you can only do one thing: subtract. When a quote is closed, you subtract. When it's cancelled, you add back. Any concurrent delivery ships the wrong number.
The root cause is that a single field can't distinguish between stock that's physically present and stock that's promised. Both states collapse into the same integer. This works in a single-user system where the person subtracting is the same person who knows what's promised. It breaks the moment two people touch the system β and it breaks silently. Nothing throws an error when you oversell. The number just goes negative, or worse, it stays positive but represents a promise you can't keep.
Two fields, one property
<a href='/features' class='text-[var(--color-accent)] underline'>Quotery's inventory system</a> uses two fields β on_hand and reserved β and a derived available = on_hand β reserved. Closing a quote increases reserved; cancelling decreases it. Only a posted delivery note decreases on_hand. The math holds under any concurrent scenario.
The separation is what makes it safe. on_hand answers 'what's physically in the warehouse?' reserved answers 'what's committed to a closed quote?' available answers 'what can I still promise to the next customer?' Each field has exactly one writer β on_hand changes only through posted fulfillment documents; reserved changes only through quote state transitions. No field gets touched by two different workflows, so there's no race condition.
This design also makes over-reservation possible as a deliberate choice. When a quote closes with insufficient available stock, reserved can exceed on_hand β available goes negative, which is a visible signal, not a silent failure. The commercial team sees it and acts on it. The constraint is enforced at delivery, not at quoting. For more on this decision, see our post on why over-reservation is a feature.
Ledger, not math
Every change is written to a StockMovement row. The two numbers on the stock item are a cache; the ledger is the truth. Reconstructing any point in time is a query, not a prayer.
The <a href='/docs/product/inventory-stock' class='text-[var(--color-accent)] underline'>inventory stock ledger</a> means you can answer questions that single-field systems can't even ask. What was available stock of SKU X last Tuesday at 3pm? Which quotes were holding reservations against this product when the stock receipt arrived? If the cached on_hand ever drifts from the sum of ledger entries, the ledger is the arbiter. You rebuild the cache from the log β you never edit the log to match the cache.
