Appearance
Backoffice → Online Ordering Relations
How back-office settings flow to the Online Ordering storefront.
Scope & verification: This doc maps which back-office settings drive Online Ordering, verified against the backend (
upvendo-backend) and back office (upvendo-backoffice). The customer-facing storefront app is a separate codebase and is out of scope; anything describing how the storefront renders a setting is tagged (storefront — not verified here). Field names, defaults, and enums below are taken fromConstants::$DEFAULT_ONLINE_ORDERING_SETTING,Constants::getDefaultOnlineSettings(),StoreOnlineOrderingRequest, andStoreOnlineSettingsRequest.
Overview
Online Ordering for a location is driven by two separate settings objects on the Location record, plus the location's own profile, business hours, menus, and assigned payment profile:
online_ordering_setting— the channel configuration: pickup/delivery toggles, delays, cut-offs, scheduling, delivery region/fee, minimum order amounts, pickup instructions/fee, customer-info requirements, payment methods, idle timeout, send-to-POS, snooze. Edited at Online → Online Ordering (/online/online-ordering), validated byStoreOnlineOrderingRequest.online_settings— operational settings: order capacity, delivery/pickup available days, tip collection, checkout notes, and menu assignment. Edited at Online Settings (/online-settings), validated byStoreOnlineSettingsRequest.
There is no enabled toggle and no accepting_orders field for online ordering. A location turns the channel on by subscribing to the Online Ordering channel (a Stripe subscription created on save), and pauses orders with Snooze (snoozed_until + the SnoozeOptions enum). See the Online Ordering feature doc.
┌─────────────────────────────────────────────────────────────────────────┐
│ BACKOFFICE │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Locations │ │ Menus │ │ Online │ │ Payments │ │
│ │ + Bus.Hours │ │ (visibility)│ │ Settings │ │ (Stripe) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ ┌────────┴────────┐ │ │
│ │ │ │ Online Ordering │ │ │
│ │ │ │ setting │ │ │
│ │ │ └────────┬────────┘ │ │
└─────────┼───────────────┼───────────────┼───────────────┼────────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────────┐
│ ONLINE ORDERING STOREFRONT (out of scope) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Location │ │ Menu │ │ Time Slot │ │ Checkout │ │
│ │ Header │ │ Display │ │ Selection │ │ Payment │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘Settings Impact Matrix
Storefront-rendering effects in the "Online Ordering Impact" columns are the intended effect of each setting; the storefront app is not verified here.
Location Profile
The location record holds profile fields and the base preparation time. Online ordering is configured per location.
| Backoffice Setting | Field | Online Ordering Impact |
|---|---|---|
| Location Name | name (Location) | Identifies the location in the back office and storefront |
| Address | location address fields | Used for delivery distance (Radius/Distance region modes) |
| Timezone | getTimezone() / TimezoneService | Open/closed checks and slot times resolved in this timezone |
| Average Preparation Time | average_prep_time (Location; default 20) | Base prep time added to the earliest available slot for both channels |
| Payment Profile | location's assigned payment profile | Which Stripe connected account processes online payments |
Notes:
average_prep_timeis a location-level field (getAveragePrepTime()returnsintval), not part ofonline_ordering_setting. It is shown read-only on the Online Ordering page and set under Settings → Locations.- There is no per-location "enabled" or "currency" online-ordering toggle. Subscription state (channel subscribed) controls availability; currency is a location/tenant property, not an online-ordering field.
Business Hours
Business hours (business_hours, labelled "Operating hours") live on the location, keyed by capitalized day names Monday–Sunday, each with is_available and a times array of { from, to } (H:i).
| Backoffice Setting | Field | Online Ordering Impact |
|---|---|---|
| Day available | business_hours.{Day}.is_available | Day is open/closed for ordering |
| Time ranges | business_hours.{Day}.times[] | Times within which the location is open |
| Online-ordering custom availability | custom_availability + schedule (online_ordering_setting) | When on, online ordering uses this schedule instead of business hours |
| Restricted dates | restricted_dates (online_ordering_setting) / location restricted dates | Specific dates closed regardless of the weekly schedule |
| Temporary closure | temporarily_closed_until (online_ordering_setting) | Location closed until a reopening date; future orders still allowed for dates on/after it |
| Show location hours only | show_location_hours_only (online_ordering_setting; default false) | Display-only. The channel payload always carries hours.location; the separate hours.online_ordering schedule is sent only when custom_availability is on and this flag is off, otherwise null. Does not change ordering availability (RawModels/Location.php lines 1518, 1616) |
Note: show_location_hours_only lives in online_ordering_setting but is read for both channels when the ordering payload is built, so it also suppresses the hours.qr_ordering key for table QR (RawModels/Location.php line 1616 — $hoursKey, set at :1508, is online_ordering or qr_ordering, both gated by the same flag).
Customer Experience (storefront — not verified here):
- The open/closed check (
checkForBusinessHours) resolves the requested time in the location's timezone, picks the online-ordering schedule (custom availability when enabled, else business hours), and rejects restricted dates, the temporarily-closed-until date, and same-/next-day cut-offs. - Time comparison is
time >= from && time <= toon theH:istrings (no past-midnight wrap handling).
Online Ordering Setting (channel configuration)
All fields below live in online_ordering_setting (validated by StoreOnlineOrderingRequest, defaults from Constants::$DEFAULT_ONLINE_ORDERING_SETTING).
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Enable Pickup | takeout.enabled | true | Pickup option shown/hidden |
| Pickup Delay | takeout.delay | 0 | Added to earliest pickup time |
| Enable Delivery | delivery.enabled | false | Delivery option shown/hidden (needs a delivery region) |
| Delivery Delay | delivery.delay | 0 | Added to earliest delivery time |
| Same-/Next-day cut-offs | takeout/delivery.same_day_cutoff/next_day_cutoff | enabled:false, time:null | Close same-/next-day ordering after the set time |
| Minimum Order Amount | minimum_order_amount {enabled, amount} | false / 10 | Orders below amount blocked at checkout when enabled |
| Pickup Minimum Order Amount | pickup_minimum_order_amount {enabled, amount} | false / 10 | Separate pickup-only minimum |
| Pickup Transaction Fee | pickup_transaction_fee {enabled, fee} | false / 0 | Extra fee on pickup orders |
| Pickup Instructions | pick_up_instructions {enabled, placeholder} | false / "Add some instructions..." | Free-text pickup guidance at checkout |
| Send to POS | send_to_pos (SendToPosOptions) | pickup_delivery_time | Order sent to POS/KDS at the scheduled time vs immediately when placed |
| Order Number Display | order_number_display (OrderNumberDisplayOptions) | Both | Order number, queue number, or both |
| Idle Timeout | idle_timeout_type / idle_timeout_seconds / show_warning_for_seconds | Standard / 120 / 15 | Session idle handling |
| Menu Layout | menu_item_columns (in:2,3,4) | 2 | Number of columns in the storefront menu-item grid (storefront rendering — see note) |
There is no enabled, accepting_orders, or preparation_time field in this object. Prep time is the location's average_prep_time; pausing is via Snooze.
menu_item_columns is not the kiosk field of the same name. Online ordering validates nullable|integer|in:2,3,4 (StoreOnlineOrderingRequest.php line 222, default 2 at Constants.php:739) and the back office offers 2/3/4 Columns (src/views/online/online-ordering/forms/OnlineOrdering.vue lines 155-166, options at 776-780). The kiosk device profile has a separate menu_item_columns still restricted to in:2,3 (StoreDeviceProfileRequest.php line 211) — see Backoffice → Kiosk. The two settings are independent; do not reconcile them.
Storefront grid rendering, verified for this entry only: the storefront falls back to 2 columns for any other value, keeps a single column on the narrowest screens, and maps 4 to a responsive ladder (2 across at small → 3 at medium → 4 at extra-large) rather than a hard 4-up (zestidoo-online-ordering src/stores/app.ts lines 259-262; src/components/menu/MenuSection.vue lines 11, 57-65). All other storefront-rendering claims in this doc remain (storefront — not verified here).
Scheduling (online_ordering_setting)
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Scheduled Pickup | schedule_order_for_future_days.takeout.enabled | true | Allow scheduling pickup for future days |
| Pickup Days Ahead | schedule_order_for_future_days.takeout.days_in_advance | 30 (max 365) | How far ahead pickup can be scheduled |
| Scheduled Delivery | schedule_order_for_future_days.delivery.enabled | false | Allow scheduling delivery for future days |
| Delivery Days Ahead | schedule_order_for_future_days.delivery.days_in_advance | 30 (max 365) | How far ahead delivery can be scheduled |
| Scheduled Eat In | schedule_order_for_future_days.eat_in.enabled | false | Allow scheduling eat-in for future days |
| Eat In Days Ahead | schedule_order_for_future_days.eat_in.days_in_advance | 30 (max 365) | How far ahead eat-in can be scheduled |
| Enable Eat In | eat_in.enabled | false | Shows the "Eat in" (For Here) option at checkout |
| Eat In Delay | eat_in.delay | 0 | Extra minutes on top of prep time for eat-in |
| Last pickup slot at closing time | takeout.last_slot_at_closing_time | true | Last pickup slot is the closing time (on) or closing − prep (off); pickup only |
| Blocked times | blocked_periods[] {from, to, active_days} | [] | Recurring weekly windows that hide pickup/delivery slots |
| Custom Scheduled Orders | custom_scheduled_orders | false | Exposes hours_in_advance + minutes_before_pickup_delivery_time thresholds |
| Hours in Advance | hours_in_advance | (none; only present when custom_scheduled_orders is on) | Threshold for delayed kitchen send |
| Minutes Before Pickup/Delivery | minutes_before_pickup_delivery_time | (none; only present when custom_scheduled_orders is on) | When to send a far-ahead order to the kitchen |
Note: hours_in_advance and minutes_before_pickup_delivery_time are not seeded in the default array — they are conditional request fields added to validation only when custom_scheduled_orders is true.
Note on accept_orders_until: it is not a back-office control for online ordering. There is no UI for it on the Online Ordering page — the only occurrence in the backoffice for this channel is a form default (upvendo-backoffice src/store/modules/onlineOrdering.ts line 74). It remains in the save payload and in the backend default (Closing Time, app/Constants.php line 590), is still validated (StoreOnlineOrderingRequest.php line 169) and is still read when computing slot cut-offs (app/Services/OrderCapacity/OrderCapacityService.php lines 2133, 2292) — merchants simply cannot edit it. The editable closing-edge control is takeout.last_slot_at_closing_time; see Scheduled Orders. The editable accept_orders_until selector belongs to table-QR ordering only (StoreQrOrderingRequest.php line 27, default Closing Time Minus Prep Time at Constants.php line 306).
Back-office UI for the rows above: src/views/online/online-ordering/forms/FullfilmentAndScheduling.vue (last pickup slot line 130; blocked times lines 151-165 and 512-518; scheduled eat-in lines 304-329) and src/views/online/online-ordering/forms/OnlineOrdering.vue (eat-in enable/delay lines 375-394).
Order Capacity (online_settings)
Order capacity lives in online_settings.order_capacity (validated by StoreOnlineSettingsRequest, defaults from $DEFAULT_ORDER_CAPACITY_SETTINGS). Enforcement at order time is handled by OrderCapacityService (runtime enforcement not detailed here).
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Capacity master toggle | order_capacity.enabled | false | When off, slots fall back to 30-min slots, all available |
| Time Slot Duration | order_capacity.time_slot_duration_min | 15 | Slot interval for time picker |
| Limit Orders per Slot | order_capacity.limit_orders_per_time_slot + number_of_orders_per_time_slot | false / null | Caps orders per slot; full slots filtered out |
| Limit Items per Slot | order_capacity.limit_items_per_time_slot + number_of_items_per_time_slot | false / null | Caps items per slot |
| Flexible Capacity | enable_flexible_limit_order_per_time_slot + value_threshold_per_time_slot + allow_up_to | false | Allow extra orders above the limit when value threshold is met |
| Category Limits | enable_limit_specific_categories + limit_specific_categories[] | false / [] | Per-category item caps per slot |
| Time-Specific Rules | order_capacity.time_specific_rules[] | [] | Named overrides (time range + active days) of the global limits |
Customer Experience (storefront — not verified here):
- Slots are generated per day from the online-ordering schedule, then (when capacity is on) batch-checked against limits; past and full slots are filtered out, and the result is cached ~60s per location/channel/day.
- Booking a slot uses a cache lock with retry to avoid double-booking.
Delivery Region (online_ordering_setting)
Stored as a single delivery_region object (not multiple named zones). See Delivery Zones.
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Region Type | delivery_region.type (DeliveryRegionOptions) | Radius | Selects Postal Code / Radius / Distance eligibility method |
| Postal Codes | delivery_region.postal_codes | [] | Eligible postal codes (Postal Code mode) |
| Radius | delivery_region.radius | 10 | Straight-line km (Radius mode) |
| Max Distance | delivery_region.max_distance | 10 | Driving-route km (Distance mode) |
Delivery Fee & Minimums (online_ordering_setting)
Stored as a single delivery_fee object. See Delivery Settings.
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Fee Type | delivery_fee.type (DeliveryFeeTypes) | Free delivery | Free / charge-all / free-over-threshold |
| Base Fee | delivery_fee.fee | 0 | Fee charged at checkout |
| Free-delivery Threshold | delivery_fee.minimum_order_amount_for_free_delivery | 0 | Order amount that qualifies for free delivery |
| Custom Fees by Postal Code | delivery_fee.custom_fees[] | [] | Per-postal-code fee overrides (Postal Code mode) |
| Distance Pricing | delivery_fee.distance_pricing_enabled + distance_pricing_type + distance_fees/flat_rate_per_km | false / tiered | Tiered or flat-rate-per-km pricing (Radius/Distance mode) |
| Delivery Minimum | minimum_order_amount {enabled, amount} | false / 10 | Delivery minimum (this is the shared minimum_order_amount) |
Customer Experience (storefront — not verified here): address in region → fee resolved by mode (custom postal-code fee or distance pricing); address outside region → delivery unavailable.
Menu & Visibility (Menus + Online Settings)
A menu appears in Online Ordering when its visibility array includes the Online Ordering channel (ChannelOptions::OnlineOrdering = 'Online Ordering'). Which menu(s) the storefront shows is set in Online Settings (default_menu_id + extra_menu_ids).
| Backoffice Setting | Field ID | Online Ordering Impact |
|---|---|---|
| Menu visibility includes "Online Ordering" | visibility (Menu) | Menu eligible to appear on the channel |
| Menu status Published | status (Menu) | Draft/Archive menus excluded |
| Menu availability | availability_type (always-available / location-default / specific-day-time) | When the menu is offered |
| Default menu | online_settings.default_menu_id | Primary menu shown |
| Extra menus | online_settings.extra_menu_ids | Additional menus, shown per their own schedules (no schedule overlap allowed) |
Items/prices/modifiers live on display groups and items within the menu, not on the menu itself. (Modifier UI enforcement — required/min/max — is storefront behavior, not verified here.)
Item Stock (online_ordering_setting)
Two toggles on the Online Ordering page's Fulfillment and Scheduling tab. Both are rendered only when the location has at least one inventory-tracked item (v-if="hasInventoryTracked", fed by GET /back-office/inventories/has-tracked — src/views/online/online-ordering/forms/FullfilmentAndScheduling.vue lines 343, 449-460; routes/api/backoffice/inventories.php line 9). See Stock Management and Inventory.
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Continue selling items when out of stock | sell_without_stock | false | Items stay orderable at zero/negative tracked stock; passed to InventoryService::manageLocationStocks(sellWithoutStock: …) when an online order is placed (OnlineOrderingOrchestrator.php lines 462-463) |
| Show remaining item stock to customers | show_item_stock | false | Display-only — reveals the remaining count on inventory-tracked items; does not change availability or stock enforcement |
Notes:
sell_without_stockis resolved per channel at payment capture: kiosk transactions read the device profile's ownsell_without_stock, online-ordering transactions read this location setting (PaymentCaptureService::resolveSellWithoutStock,PaymentCaptureService.php:662).- The two interact: with
sell_without_stockon, available stock is treated as unlimited, so no count is displayed even whenshow_item_stockis on (verified for this entry:zestidoo-online-orderingsrc/stores/app.tslines 266, 292-297;src/components/FoodCard.vuelines 176-182). Items are also still blocked by their own Inactive / Unavailable / Hidden status regardless ofsell_without_stock(src/stores/app.tslines 339-344).
Tips & Notes (online_settings)
These live in online_settings, not online_ordering_setting.
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Collect Tips | collect_tips.enabled | false | Tip selection shown at checkout |
| Tip Options | collect_tips.options (3 values, 1–100) | [10, 15, 20] | Suggested tip percentages |
| Calculate Tips | collect_tips.calculate_tips (CalculateTipsOptions) | "After taxes" | Before/after-taxes basis |
| Checkout Notes | allow_notes {enabled, placeholder} | false | "Add a note" field at checkout |
| Delivery/Pickup Days | delivery_available_days / pickup_available_days | all 7 days | Days each channel is offered |
Customer Info (online_ordering_setting)
Customer-info requirements are two enum fields, not independent require-name/phone/email booleans.
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Full name requirement | customer_information_full_name (CustomerInformationFullNameOptions) | first_last_name | Require first+last (first_last_name) or first only (first_name) |
| Contact requirement | customer_information_contact_details (CustomerInformationContactDetailsOptions) | phone_email | Require phone+email (phone_email) or email only (email) |
Customer Experience (storefront — not verified here): the chosen options determine which name/contact fields are required at checkout.
Payment Methods (online_ordering_setting + Payment Profile)
Online-ordering payments run through Stripe (the location's assigned payment profile's Stripe connected account) when Square is not connected; the channel→provider match maps Online Ordering → stripe (config('upvendo.zestidoo_payment_provider'), default stripe) and Kiosk → viva. See Payments.
| Backoffice Setting | Field ID | Default | Online Ordering Impact |
|---|---|---|---|
| Card / local methods | Stripe connected-account capabilities | — | Card, iDEAL, Bancontact, Klarna, etc. shown per the account's enabled capabilities (not per-method back-office toggles) |
| Invoice (Pay by Invoice) | payment_methods.invoice_enabled (+ mplus_invoice_payment_code) | false | Invoice option at checkout, Mplus tenants only; billed later via Invoice Collection |
| Cash on Delivery | payment_methods.cod_enabled (+ pos_cod_payment_code) | false | COD field exists but is not currently offered in production |
Notes:
- There are no per-method "iDEAL Enabled" / "Bancontact Enabled" back-office toggles — local methods follow the Stripe connected account's capabilities for the country.
- When Square POS is connected (
Merchant::isSquareIntegrated()), Square handles payments at the merchant-integration level; Stripe/Viva are bypassed. Square is not a branch in the per-channel provider match. - Free orders (total = 0) skip the payment provider entirely.
Snooze (pause without unsubscribing)
There is no "Accepting Orders" toggle. Pausing uses Snooze, written to online_ordering_setting.snoozed_until.
| Snooze Action | SnoozeOptions value | Effect |
|---|---|---|
| Accept online orders | accept | Resume; clears the snooze |
| Snooze 20 / 40 / 60 min | 20 / 40 / 60 | Pause until a timestamp; snoozed_until = Unix timestamp |
| Rest of the day | rest_of_the_day | Pause until the start of the next day |
| Do not accept | dont_accept | Indefinite pause; snoozed_until stores the literal string dont_accept |
snoozed_until is a runtime-written key on online_ordering_setting (not in the default array), holding either a Unix timestamp, the string dont_accept, or null. Snooze uses the location's timezone.
Detailed Field Mappings
Location Profile → Online Ordering
Location: name
→ storefront location identity / header (storefront — not verified here)
Location: average_prep_time (default 20)
→ base preparation time for the earliest available slot
Location: assigned payment profile (Stripe connected account)
→ which account processes online-ordering paymentsBranding (logo, cover image, colors) is configured under Branding profiles, not the Online Ordering page; how it renders on the storefront is not verified here.
Preparation Time → Earliest Available Slot
average_prep_time (Location, default 20 min)
+
takeout.delay (pickup) OR delivery.delay (delivery)
=
Earliest available time = Now + average_prep_time + channel delay
Example (current time 12:00, average_prep_time 20, delivery.delay 15):
- Earliest pickup = 12:00 + 20 + 0 = 12:20
- Earliest delivery = 12:00 + 20 + 15 = 12:35The slot-check prep time is max(average_prep_time, largest item prep time) + channel delay, clamped to 0-1440 minutes — the largest item prep time is compared against the location average, not added to it, so it can only raise a quote above the location baseline, never lower it. The channel delay may be negative, which shortens the lead time; it is added as-is and only the final result is clamped. The item term is 0 today: it is gated by ONLINE_ORDERING_INCLUDE_ITEM_PREP_TIME, which defaults to false and is not set in production, staging or testing, so the calculation reduces to average_prep_time + channel delay. The nearby-restaurants list (prep_time.from / prep_time.to on GET /online-ordering/restaurant-suggestions/nearby) runs the same rule, with two differences worth knowing. It passes no cart, so $maxItemPrep takes its default 0 (:2074-2077) — browse and checkout therefore agree only while the item-prep gate stays off; switching ONLINE_ORDERING_INCLUDE_ITEM_PREP_TIME on would make a cart-laden checkout quote exceed the browse quote by design. And it maps only over getOnlineOrderingDiningOptions() (:1956-1968), which is Pickup and Delivery — never ForHere — so an eat-in-only location advertises nothing while browsing. (Verified: app/RawModels/Location.php:2001-2018 — getDiningOptionPrepTime(), the single definition; getOnlineOrderingPrepTime() at :2072-2087 and OrderCapacityService::effectivePrepMinutes at app/Services/OrderCapacity/OrderCapacityService.php:86-89 both call it; maxItemPrepFromSnapshot at :101-115; config/upvendo.php line 26.)
A location with neither takeout nor delivery enabled still appears in that list with prep_time {from: 0, to: 0} — that is "nothing to promise", not "ready immediately". The sibling dining_options is empty in exactly the same case and tells the two apart. Note the shared trigger: both are driven by takeout.enabled and delivery.enabled only, so a location offering online eat-in and nothing else has eat_in.enabled = true yet still reports an empty dining_options and a zero prep_time. Do not read an empty dining_options as "this location takes no online orders". (Verified: app/RawModels/Location.php:1956-1968 and :2079-2081.)
Menu Visibility → Storefront Menu
Menu.visibility includes "Online Ordering" (ChannelOptions::OnlineOrdering)
AND Menu.status = Published
AND menu assigned in Online Settings (default_menu_id / extra_menu_ids)
→ menu appears on the Online Ordering channel (storefront — not verified here)Real-Time Updates
Saving the relevant settings dispatches a ReloadMenu event so ordering channels can pick up changes:
- Online Ordering update →
event(new ReloadMenu($locationId, ChannelOptions::OnlineOrdering->value))(OnlineOrderingService). - Online Settings update →
event(new ReloadMenu($locationId))(OnlineSettingsService). - Menu update / display-group reorder →
ReloadMenu(andMenuUpdatedfor Uber Eats sync) fromMenuService.
Snooze writes snoozed_until and propagates the pause state. Exactly how/when the storefront reflects each change is (storefront — not verified here).
Error Messages
These describe the intended customer-facing outcomes of back-office settings. The exact storefront copy is (storefront — not verified here); the cause column is grounded in back-office settings.
| Cause | Setting |
|---|---|
| Channel not subscribed | No active Online Ordering subscription for the location |
| Orders paused | snoozed_until set (Snooze active) |
| Outside business hours | business_hours / online-ordering custom availability + cut-offs |
| Restricted / temporarily closed | restricted_dates / temporarily_closed_until |
| Slot full | order_capacity limits reached |
| Below minimum order | minimum_order_amount / pickup_minimum_order_amount |
| Outside delivery region | delivery_region (postal codes / radius / max_distance) |
| Pickup/Delivery disabled | takeout.enabled / delivery.enabled |
| Payment failed | Stripe (or Square if connected) |