Negative Stock Errors in Odoo
When processing deliveries or transfers, you encounter:
UserError: It is not possible to unreserve more products than you have in stock.
Warning: Not enough stock available for Product A.
Required: 10.0 | Available: 3.0
# Or in the inventory report:
Product A: On Hand = -5.0 (should never be negative)Why Negative Stock Occurs
Negative inventory happens when more products are shipped out than exist in the system. This is caused by:
- Deliveries processed without prior receipt confirmation
- Manual stock adjustments that reduce quantity below zero
- Inventory counts that mismatch with actual deliveries
- The "Allow Negative Stock" setting enabled
- Backdated stock moves processed after current transactions
Fix 1: Check and Disable Negative Stock Setting
# Odoo can be configured to allow or block negative stock
# Check current setting:
# Inventory > Configuration > Settings
# Under "Operations" section:
# "Allow Negative Stock" — should be UNCHECKED for most businesses
# Per product override:
# Product > Inventory tab > "Allow Negative Stock"
# Uncheck if enabled
# Per warehouse:
# Inventory > Configuration > Warehouses
# Check the delivery steps configurationFix 2: Correct Existing Negative Stock
# Option 1: Create an inventory adjustment
# Inventory > Operations > Physical Inventory
# Find the product with negative stock
# Set the "Counted Quantity" to the actual physical count (usually 0)
# Apply — this creates an adjustment move
# Option 2: Create a receipt to add missing stock
# Inventory > Operations > Receipts > Create
# Add the product with the quantity needed to reach 0
# This is appropriate if goods were physically received but not recorded
# Option 3: Via database (emergency only)
sudo -u postgres psql -d mydb -c "
SELECT pp.id, pt.name, sq.quantity, sq.location_id, sl.complete_name
FROM stock_quant sq
JOIN product_product pp ON sq.product_id = pp.id
JOIN product_template pt ON pp.product_tmpl_id = pt.id
JOIN stock_location sl ON sq.location_id = sl.id
WHERE sq.quantity < 0
ORDER BY sq.quantity;
"Fix 3: Find the Root Cause
# Trace the stock moves that caused negative stock:
sudo -u postgres psql -d mydb -c "
SELECT sm.id, sm.date, sm.reference, sm.product_qty,
sl_src.complete_name as source, sl_dst.complete_name as destination,
sm.state
FROM stock_move sm
JOIN stock_location sl_src ON sm.location_id = sl_src.id
JOIN stock_location sl_dst ON sm.location_dest_id = sl_dst.id
WHERE sm.product_id = PRODUCT_ID
AND sm.state = 'done'
ORDER BY sm.date DESC
LIMIT 20;
"
# Look for:
# - Outgoing moves (to customer) without prior incoming moves
# - Backdated moves that were processed out of sequence
# - Duplicate delivery orders for the same saleFix 4: Prevent Future Negative Stock
# 1. Use proper warehouse operations:
# - 2-step or 3-step delivery forces picking before shipping
# - Reservations prevent shipping more than available
# 2. Configure product routes correctly:
# Product > Inventory tab > Routes
# Ensure proper replenishment rules are set
# 3. Use the "Check Availability" button on delivery orders
# This reserves stock before allowing validation
# 4. Set reordering rules:
# Inventory > Configuration > Reordering Rules
# Set minimum stock levels to trigger automated purchaseFix 5: Quant Reconciliation
# Stock quants track current quantities per location
# Sometimes quants get out of sync with stock moves
# Check quant vs move totals:
sudo -u postgres psql -d mydb -c "
-- Current quant quantity
SELECT SUM(quantity) as quant_total
FROM stock_quant
WHERE product_id = PRODUCT_ID
AND location_id IN (SELECT id FROM stock_location WHERE usage = 'internal');
"
sudo -u postgres psql -d mydb -c "
-- Calculated from moves
SELECT
SUM(CASE WHEN sl_dst.usage = 'internal' THEN sm.product_qty ELSE 0 END) -
SUM(CASE WHEN sl_src.usage = 'internal' THEN sm.product_qty ELSE 0 END) as move_total
FROM stock_move sm
JOIN stock_location sl_src ON sm.location_id = sl_src.id
JOIN stock_location sl_dst ON sm.location_dest_id = sl_dst.id
WHERE sm.product_id = PRODUCT_ID
AND sm.state = 'done';
"
# If they differ, run the quant fix:
# Inventory > Operations > Physical Inventory
# Count and adjust to match physical realityPrevention
DeployMonkey's AI agent monitors stock levels and configures proper warehouse operations. Negative stock detection runs proactively, alerting before inventory discrepancies affect business operations.