Skip to content

Stock Management

Overview

Stock management tracks item availability in real-time. When items run out, they're automatically hidden or marked as unavailable on Online Ordering and Kiosk.

Key Purpose: Track and manage item stock levels.

Purpose

This page lets you enable stock tracking per item, set stock levels and low-stock thresholds, configure out-of-stock snooze behavior, and view inventory history across locations.

Key Concepts

  • Inventory Record: A per-item, per-location record created via InventoryService.createOrGetExistingInventory that stores the current quantity; soft-deleted records can be restored if the item is re-tracked.
  • Inventory History: Every stock change (restock, depletion, purchase) is recorded as a separate InventoryHistory entry with type Restock, Depletion, or Bought, enabling full traceability.
  • Remaining Stock Calculation: The updateRemainingStock method recalculates the current quantity by summing all history entries (restocks add, depletions and purchases subtract); if the result is negative, a 400 error is returned.
  • Snooze Options: When stock reaches zero, the location-level snooze_time_out_of_stock_items setting controls visibility: options include do_not_snooze, 30/60/120/180/360/720/1440 minutes, or infinite (hidden until manually restocked).
  • Cloudflare D1 Sync: After every stock update, the system syncs the new quantity to Cloudflare D1 via CloudflareD1Helper.updateStock for edge-level availability checks, and fires a ReloadMenu event.

Actions

Enable Stock Tracking

Turn on the track_stock toggle for an item to begin monitoring its quantity at a specific location.

Restock or Adjust Inventory

Add or remove stock manually; the system creates the appropriate history entry (Restock or Depletion) and recalculates the remaining quantity.

Configure Snooze Behavior

Set the location-level snooze duration that determines how long an out-of-stock item is hidden from customers before reappearing.

View Inventory Overview

Browse a paginated list of all tracked items with their current stock levels, filterable by location.

Set Expiry Days

Optionally set an expiry period on inventory records; the system calculates the expiry date based on the location's timezone.

Location

  • Backoffice Route: /inventory
  • Backend Controller: app/Http/Controllers/Api/InventoryController.php
  • Vue Component: src/views/inventory/InventoryComponent.vue

Stock Tracking

Track Stock

PropertyValue
Field IDtrack_stock
LabelTrack Stock
TypeToggle
Defaultfalse

Description: Enable stock tracking for this item.


Current Stock

PropertyValue
Field IDstock
LabelStock Level
TypeNumber
Default0
Depends Ontrack_stock = true

Description: Current available quantity.


Low Stock Threshold

PropertyValue
Field IDlow_stock_threshold
LabelLow Stock Alert
TypeNumber
Default5

Description: Alert when stock falls below this level.


Snooze Settings

Snooze When Out of Stock

PropertyValue
Field IDsnooze_time_out_of_stock_items
LabelSnooze Duration
TypeSelect
Optionsdo_not_snooze, 30, 60, 120, 240, infinite

Description: How long to hide item when out of stock.

Options:

  • Do not snooze: Item stays visible (shows "Out of stock")
  • 30 minutes: Hide for 30 minutes
  • 1 hour: Hide for 1 hour
  • 2 hours: Hide for 2 hours
  • 4 hours: Hide for 4 hours
  • Infinite: Hide until manually restocked

Stock Operations

Add Stock

Increase stock level.

Current stock: 10
Add: 20
New stock: 30

Remove Stock

Decrease stock level (manual adjustment).

Current stock: 30
Remove: 5
New stock: 25

Order Deduction

Automatic deduction when order placed.

Customer orders 2x Pizza
Current stock: 10
After order: 8

Stock Reservation

How It Works

When a customer adds an item to cart, stock is temporarily reserved:

Customer adds item to cart


Reserve stock (temporary hold)


Customer completes order?
├── Yes → Confirm reservation (stock deducted)

└── No (timeout/abandon) → Release reservation
                           (stock returned)

Reservation Timeout

Based on idle timeout setting:

  • Standard: 2 minutes
  • Extended: 5 minutes
  • Custom: Configurable

Business Logic

Stock Check Flow

Customer views item


Stock tracking enabled?
├── No → Item always available

└── Yes → Check stock level
          ├── Stock > 0 → Show as available
          │               Allow add to cart

          └── Stock = 0 → Check snooze setting
                          ├── Do not snooze → Show "Out of stock"
                          └── Snooze → Hide item

Order Processing

Order placed


For each item:
├── Stock tracked?
│   ├── Yes → Deduct from stock
│   └── No → Skip


Stock now 0?
├── Yes → Apply snooze setting
└── No → Continue

Customer Impact

Online Ordering

  • Out of stock items hidden or marked
  • Real-time stock updates
  • Cart validation before checkout
  • "Only X left" warnings

Kiosk

  • Same as Online Ordering
  • Immediate stock updates
  • Prevents ordering unavailable items

Relations

Depends On

  • Menu Items: Stock per item
  • Locations: Stock per location

Affects

  • Online Ordering: Item availability
  • Kiosk: Item availability
  • Transactions: Stock deduction
  • Reports: Stock reports

Business Rules

  • Remaining stock is calculated by summing all inventory history entries: Restock adds, Depletion and Bought subtract; if the result goes below zero, the operation is rejected with "Not enough remaining stock for [item name]."
  • Items with track_quantity enabled enforce a per-order maximum via maxOrderLimit; exceeding it returns a 400 error with the maximum allowed quantity.
  • Deleting an inventory record soft-deletes it and also removes the corresponding Cloudflare D1 stock entry; re-enabling tracking restores the soft-deleted record.
  • Every stock change (manual adjustment or order purchase) triggers both a CloudflareD1Helper.updateStock call for edge caching and a ReloadMenu event so connected devices reflect the new availability instantly.
  • The snooze options for out-of-stock items are: do_not_snooze, 30, 60, 120, 180, 360, 720, 1440 minutes, or infinite; the infinite option hides the item until stock is manually replenished.

FAQs

  • "What happens when a customer orders the last unit?" The stock is deducted via a Bought history entry, and if the quantity reaches zero, the snooze setting determines whether the item is hidden or shown as "Out of stock."
  • "Can I track stock for the same item across multiple locations?" Yes, inventory records are per-item per-location; each location maintains its own stock level independently.
  • "What is the difference between Depletion and Bought?" Bought is automatically created when a customer places an order; Depletion is used for manual downward adjustments (e.g., waste, breakage).
  • "Why does deleting inventory also affect Cloudflare D1?" The system syncs stock data to Cloudflare D1 at the edge for fast availability checks; deleting inventory removes the D1 record to prevent stale data.
  • "Can I set an expiry date on inventory?" Yes, when updating inventory you can set expiry_days; the system calculates the expiry date based on the location's timezone using Carbon.

Troubleshooting

Problem: Item showing out of stock incorrectly

Causes:

  1. Stock not updated after restock
  2. Reservation not released
  3. Sync issue

Solutions:

  1. Update stock manually
  2. Wait for reservation timeout
  3. Refresh inventory

Problem: Stock not deducting

Causes:

  1. Stock tracking disabled
  2. Item not linked correctly
  3. System error

Solutions:

  1. Enable stock tracking
  2. Verify item configuration
  3. Check system logs

Examples

Item with Stock Tracking

json
{
  "item": {
    "id": "item-123",
    "name": "Special Burger",
    "track_stock": true,
    "stock": 25,
    "low_stock_threshold": 5
  }
}

Location Snooze Setting

json
{
  "location": {
    "snooze_time_out_of_stock_items": "60"
  }
}

Stock Reservation

json
{
  "reservation": {
    "id": "res-456",
    "item_id": "item-123",
    "quantity": 2,
    "reserved_at": "2024-01-15T12:30:00Z",
    "expires_at": "2024-01-15T12:32:00Z",
    "session_id": "session-789"
  }
}

Stock Update Event

json
{
  "event": "stock_updated",
  "item_id": "item-123",
  "previous_stock": 10,
  "new_stock": 8,
  "reason": "order_placed",
  "order_id": "order-456"
}