Stock rules by channel
Warehouse quantities live in WarehouseStock (backend-main/warehouse/models.py). Ecommerce reads/writes through ecommerce/services.py (backend-main/ecommerce/services.py) (get_product_stock, allocate_and_decrement_stock). POS catalog visibility uses stock filters in pos/views.py (backend-main/pos/views.py) / customer-link services, but POS order create does not decrement stock.
Summary
| Channel | When stock is checked | When stock is decremented |
|---|---|---|
| Ecommerce COD | Pre-check get_product_stock in EcommerceCheckoutView; then locked allocate | Same request, before create_cod_order |
| Ecommerce Razorpay | Snapshot records stock_items at start; no hold | On verify/webhook via _decrement_snapshot_stock |
| Ecommerce custom / design lines | Not checked | Not decremented (quantity forced to 1) |
| POS order create | Catalog listing requires stock to show products | Never in POSOrderCreateSerializer.create |
| Customer / catalog link | Catalog APIs expose stock for display | Never on step3 / catalog submit / link create |
Caveats (oversell, swallowed Razorpay failures, POS divergence): Known limitations (from report.md).
Ecommerce allocation
allocate_and_decrement_stock(product, quantity):
- Resolve enabled ecommerce warehouses / listings.
- Walk listings by
warehouse_id;select_for_updateonWarehouseStock. - First warehouse with
quantity >= requesteddecrements and writesStockHistoryEntry(reason='Ecommerce order'). - Else raises
InsufficientStockError.
get_product_stock sums quantities across enabled listing warehouses (unlocked read). COD therefore does a TOCTOU-style pre-check then a locked decrement — concurrent carts can both pass the pre-check; the lock only serializes the final allocate.
COD (EcommerceCheckoutView)
For each non-custom line: require available >= quantity, append to stock_items, then after totals:
for item in stock_items:
allocate_and_decrement_stock(...)
create_cod_order(prepared)
Failure → 400 and no order.
Razorpay
- Start:
stock_itemsstored inPendingRazorpayCheckout.snapshotonly; warehouses unchanged. - Fulfill:
_decrement_snapshot_stockloops snapshot lines; missing product /InsufficientStockError→ name appended tomissing; order still created asverifiedwith a system comment whenmissingis non-empty (backend-main/ecommerce/checkout_orders.py).
Custom lines
In EcommerceCheckoutView, is_custom products:
quantity = 1(client quantity ignored)- Not added to
stock_items - No
get_product_stockcheck
POS and links
- POS product lists filter by
WarehouseStockfor the POS warehouses so out-of-stock SKUs may not appear. POSOrderCreateSerializer.create(backend-main/pos/serializers.py) writesPOSOrder/POSOrderItemonly — noWarehouseStockupdate.- Customer-link and catalog submit persist line snapshots and payment proof; they do not call
allocate_and_decrement_stock.
Any warehouse correction for POS/link sales must happen via warehouse admin adjust/transfer (or future workflow hooks) — not automatic at order create.