Appearance
Inventory Management
Overview
Inventory Management tracks stock levels for menu items. When inventory tracking is enabled, items automatically show as "Sold Out" when stock reaches zero.
Key Purpose: Track stock levels and prevent overselling.
Purpose
This page lets you track stock levels for menu items per location, set low-stock alerts, and control whether sold-out items remain orderable.
Key Concepts
- Inventory Tracking: A per-item toggle (
track_quantity) that enables stock management; when disabled, the item is treated as always available. - Inventory History: An auditable log of every stock change (restock, depletion, bought) stored via
InventoryHistoryRepository, used to recalculate the remaining stock from the full history. - Stock Depletion Types: The system distinguishes between
Restock(adds stock),Depletion(manual removal for damage/expiry), andBought(automatic deduction when a customer order is placed). - Max Order Limit: A per-item cap on the quantity a customer can order in a single transaction, enforced at checkout time independently from stock levels.
- D1 Stock Sync: After every stock change, the updated stock level is pushed to a Cloudflare D1 edge database so customer-facing menus reflect availability in real time.
Actions
Enable Inventory Tracking for an Item
Turn on the track_quantity flag for a specific menu item to start monitoring its stock level per location.
Restock or Adjust Stock
Add stock (restock) or set stock to a specific value (adjustment). Each change is recorded in the inventory history with the appropriate type and reason.
Delete Inventory Record
Remove inventory tracking for an item at a location. This deletes the D1 stock entry and triggers a menu reload so the item appears as always available again.
Review Inventory Overview
View a paginated overview of all tracked items and their current stock levels for a given location, including timezone-adjusted timestamps.
Location
- Backoffice Route:
/inventory - Backend Controller:
app/Http/Controllers/Api/InventoryController.php - Vue Component:
src/views/inventory/index.vue
Concepts
Stock Level
Current quantity of an item available.
Low Stock Alert
Warning when stock falls below threshold.
Stock Tracking
Per-item setting to enable/disable tracking.
Stock Reservation
Temporary hold on stock during checkout.
Fields
Track Inventory
| Property | Value |
|---|---|
| Field ID | track_inventory |
| Label | Track Inventory |
| Type | Toggle |
| Default | false |
| Required | No |
| Scope | Per item |
Description: Whether to track stock for this item.
Business Logic:
- Enabled: Stock decremented on order, "Sold Out" when 0
- Disabled: Item always available (unlimited)
Customer Impact:
- Stock = 0: Item shows "Sold Out"
- Stock > 0: Item available
Current Stock
| Property | Value |
|---|---|
| Field ID | stock |
| Label | Current Stock |
| Type | Number |
| Required | Yes (if tracking enabled) |
| Validation | min: 0 |
Description: Current quantity available.
Business Logic:
- Decremented when order placed
- Incremented when order cancelled/refunded
- Can be manually adjusted
Low Stock Threshold
| Property | Value |
|---|---|
| Field ID | low_stock_threshold |
| Label | Low Stock Alert |
| Type | Number |
| Default | 10 |
| Required | No |
| Validation | min: 0 |
Description: Stock level that triggers low stock warning.
Business Logic:
- When stock <= threshold → Alert shown in backoffice
- Optional notification sent
Examples:
- 10: Alert when 10 or fewer left
- 5: Alert when 5 or fewer left
- 0: Only alert when out of stock
Allow Backorders
| Property | Value |
|---|---|
| Field ID | allow_backorders |
| Label | Allow Backorders |
| Type | Toggle |
| Default | false |
| Required | No |
Description: Allow orders even when stock is 0.
Business Logic:
- Enabled: Item available even at 0 stock
- Disabled: Item unavailable at 0 stock
Use Cases:
- Items that can be quickly restocked
- Made-to-order items
- Pre-orders
Stock Location
| Property | Value |
|---|---|
| Field ID | stock_location_id |
| Label | Stock Location |
| Type | Select |
| Required | No |
| Default | Per-location tracking |
Description: Which location's stock to track.
Business Logic:
- Stock can be tracked per-location
- Or shared across locations (central inventory)
Stock Operations
Restock
| Property | Value |
|---|---|
| Operation | Add stock |
| Field | quantity |
| Type | Number |
| Validation | min: 1 |
Description: Add inventory when receiving new stock.
Example:
- Current: 5
- Restock: +20
- New stock: 25
Adjust Stock
| Property | Value |
|---|---|
| Operation | Set stock |
| Field | quantity |
| Type | Number |
| Validation | min: 0 |
Description: Set stock to specific value (inventory count).
Example:
- Current: 15
- Adjust to: 12 (3 items lost/damaged)
- New stock: 12
Stock Reason
| Property | Value |
|---|---|
| Field ID | reason |
| Label | Reason |
| Type | Select/Text |
| Options | Restock, Damaged, Expired, Count Adjustment, Other |
Description: Reason for stock change (for audit trail).
Business Logic
Order Stock Flow
Customer places order
│
▼
For each item in order:
├── Track inventory enabled?
│ ├── No → Skip
│ └── Yes → Continue
│
├── Check current stock
│ ├── Stock >= Quantity → Reserve stock
│ └── Stock < Quantity →
│ ├── Allow backorders? → Reserve (negative stock)
│ └── No backorders → Error: "Item sold out"
│
└── Order confirmed → Deduct stockStock Reservation
Customer adds to cart
│
▼
Reserve stock (temporary hold)
│
├── Checkout completed → Confirm deduction
│
├── Cart abandoned → Release reservation
│
└── Timeout (e.g., 15 min) → Release reservationLow Stock Alert
Stock updated
│
▼
Check if stock <= low_stock_threshold
│
├── Yes → Trigger alert
│ - Show in backoffice
│ - Send notification (if configured)
│
└── No → No actionSold Out Display
Customer views menu
│
▼
For each item:
├── Track inventory = false → Show as available
│
└── Track inventory = true
├── Stock > 0 → Show as available
└── Stock = 0
├── Allow backorders → Show as available
└── No backorders → Show "Sold Out"Customer Impact
Online Ordering
| Stock Status | Customer Sees |
|---|---|
| In stock | Normal item display |
| Low stock | Normal (no indication) |
| Out of stock | "Sold Out" badge, cannot add |
| Backorders allowed | Normal (may show "Pre-order") |
Kiosk
- Same behavior as Online Ordering
- "Sold Out" items grayed out or hidden
Cart Behavior
- If item goes out of stock while in cart → Warning shown
- Customer must remove item to proceed
- Or item auto-removed with notification
Relations
Depends On
- Menu Items: Stock tracked per item
- Locations: Stock can be per-location
Affects
- Online Ordering: Item availability
- Kiosk: Item availability
- Transactions: Stock deducted
- Reports: Inventory reports
Related Features
Business Rules
- Remaining stock is recalculated by replaying the full inventory history (all restock, depletion, and bought entries); if the calculated value goes below zero, the system aborts with a "Not enough remaining stock" error.
- When a customer places an order, the system checks
track_quantityfor each item; if stock is insufficient and backorders are not allowed, a 400 error is returned before the order is created. - Stock adjustments that result in zero change (quantity delta of 0) are silently skipped and no history entry is created.
- Deleting an inventory record also removes the corresponding D1 edge database entry and fires a
ReloadMenuevent so all ordering channels reflect the change immediately. - Inventory expiry dates are calculated relative to the location's timezone and are set to end-of-day for future dates or start-of-day for same-day expiry.
FAQs
- Does stock update automatically when a customer places an order? Yes, the
manageLocationStocksmethod automatically creates a "Bought" history entry and decrements stock for each tracked item in the order. - Can I track stock differently per location? Yes, inventory records are scoped per item and per location, so each location maintains independent stock levels.
- What happens if two customers order the last item at the same time? The system checks stock at order creation time; the first order to be processed will succeed, and the second will receive a "Not enough remaining stock" error.
- Is there an undo for stock adjustments? There is no direct undo, but you can create a new restock or depletion entry to correct the stock level. All changes are recorded in the history for auditability.
- How quickly do stock changes appear on the customer menu? Stock changes are pushed to the Cloudflare D1 edge database immediately after the update, and a
ReloadMenuevent is fired, so changes typically appear within seconds.
Troubleshooting
Problem: Item showing "Sold Out" but has stock
Causes:
- Stock not updated after restock
- Wrong location's stock
- Cache not refreshed
Solutions:
- Update stock in inventory
- Check correct location
- Refresh/clear cache
Problem: Item sold when out of stock
Causes:
- Inventory tracking not enabled
- Allow backorders enabled
- Race condition (simultaneous orders)
Solutions:
- Enable inventory tracking
- Disable backorders if not wanted
- Stock reservation should prevent this
Problem: Stock count incorrect
Causes:
- Manual adjustments not recorded
- Cancelled orders not restocking
- Sync issues
Solutions:
- Do physical count and adjust
- Check cancelled order handling
- Review stock history
Problem: Low stock alerts not working
Causes:
- Threshold set to 0
- Notifications disabled
- Item not tracked
Solutions:
- Set appropriate threshold
- Enable notifications
- Enable inventory tracking
Examples
Simple Stock Tracking
json
{
"item": {
"name": "Special Burger",
"track_inventory": true,
"stock": 50,
"low_stock_threshold": 10,
"allow_backorders": false
}
}Behavior:
- 50 available
- Alert at 10 remaining
- "Sold Out" at 0
High-Demand Limited Item
json
{
"item": {
"name": "Chef's Special (Limited)",
"track_inventory": true,
"stock": 20,
"low_stock_threshold": 5,
"allow_backorders": false
}
}Behavior:
- Only 20 available per day
- Alert at 5 remaining
- Creates urgency for customers
Pre-Order Item
json
{
"item": {
"name": "Holiday Special Box",
"track_inventory": true,
"stock": 0,
"low_stock_threshold": 0,
"allow_backorders": true
}
}Behavior:
- Available for pre-order
- Stock goes negative (tracks demand)
- Fulfill when stock arrives
No Tracking (Always Available)
json
{
"item": {
"name": "French Fries",
"track_inventory": false
}
}Behavior:
- Always available
- No stock management needed
- Good for items that never run out
Multi-Location Stock
json
{
"item": {
"name": "Signature Dish",
"track_inventory": true,
"stock_by_location": {
"location-amsterdam": 30,
"location-rotterdam": 25,
"location-utrecht": 20
},
"low_stock_threshold": 5
}
}Behavior:
- Different stock per location
- Each location manages own inventory
- Alerts per location
Stock History
Track all stock changes for audit:
json
{
"stock_history": [
{
"date": "2024-01-15 09:00",
"type": "restock",
"quantity": +50,
"reason": "Weekly delivery",
"user": "Manager"
},
{
"date": "2024-01-15 12:30",
"type": "order",
"quantity": -2,
"reason": "Order #1234",
"user": "System"
},
{
"date": "2024-01-15 14:00",
"type": "adjustment",
"quantity": -3,
"reason": "Damaged items",
"user": "Staff"
}
]
}