Appearance
Online Settings
Overview
Online Settings is the location-specific configuration page for the online ordering channel. It controls operational parameters including order capacity management (how many orders and items are accepted per time slot), delivery and pickup day availability, tip collection settings, checkout note options, and menu assignments. Each location stores its own online settings on the Location document's online_settings field, allowing multi-location businesses to tailor their online ordering experience per venue.
The settings are managed by OnlineSettingsService, which validates menu eligibility and schedule overlaps and saves the validated payload to the location. The validation rules live in StoreOnlineSettingsRequest, and the defaults are sourced from Constants::getDefaultOnlineSettings().
Purpose
This page lets you configure how your online ordering channel operates for a specific location, including order capacity limits, available delivery and pickup days, tip collection preferences, checkout notes, and which menus are displayed to online customers.
Key Concepts
- Order Capacity: A system for controlling order volume per time slot. The base (global) configuration includes a master
enabledtoggle,time_slot_duration_min(the interval in minutes),limit_orders_per_time_slot(boolean toggle),number_of_orders_per_time_slot(maximum orders),limit_items_per_time_slot(boolean toggle), andnumber_of_items_per_time_slot(maximum items). These global settings apply by default to all time slots unless overridden by time-specific rules. - Flexible Capacity: A capacity mode that allows exceeding the base order limit when order value meets a threshold. Enabled via
enable_flexible_limit_order_per_time_slot, configured withvalue_threshold_per_time_slot(minimum order value to qualify) andallow_up_to(number of extra orders allowed). NOTE: the back office defines and validates these fields; the storefront enforcement behavior is not verified here. - Time-Specific Rules: Named override rules stored under
order_capacity.time_specific_rules. Each rule has a uniquename, atime_range(withfromandtotimes), anactive_daysarray (full day names, e.g. "Monday"), optionalnumber_of_orders_per_time_slotandnumber_of_items_per_time_slot, optional flexible capacity settings, and optional category-specific limits. ThehasOverlappingTimeRangesvalidation fromSchedulingTraitrejects rules whose time ranges overlap on the same day. - Menu Assignment: Online settings define a
default_menu_id(the primary menu) and optionalextra_menu_ids(additional menus with schedule-based availability). Extra menus are validated for eligibility, non-duplication, not matching the default, internal schedule self-overlap (isSingleScheduleOverlap), and cross-menu schedule non-overlap (isScheduleOverlap). Schedules are resolved per location viaMenu::getSchedule($location). - Collect Tips: A tipping object with
enabled(boolean),options(array of up to 3 percentage values, each 1-100, default[10, 15, 20]), andcalculate_tips(aCalculateTipsOptionsenum value:"After taxes"or"Before taxes"). - Checkout Notes (two independent settings): The checkout notes UI (
CheckoutNotes.vue, shared with In-House settings) exposes two separate note toggles:allow_notes-- per-item notes (UI label "Allow Item Notes"). Lets customers add a note to an individual line item.allow_order_notes-- a whole-order note (UI label "Allow Order Notes"). Lets customers add a single instruction for the entire order (e.g. "Please ring the doorbell"). Both share the same shape ({enabled, placeholder}) and the same required/nullable validation pattern. For backward compatibility with locations saved beforeallow_order_notesexisted, the backend and the back-office store both fall back toallow_noteswhenallow_order_notesis absent (see Technical Details).
Route
- Backoffice Route:
/online-settings(page atsrc/pages/online-settings/index.vue) - Backend Controller:
app/Http/Controllers/Api/BackOffice/OnlineSettingsController.php - Service:
app/Services/BackOffice/OnlineSettingsService.php - Request Validator:
app/Http/Requests/BackOffice/OnlineSettings/StoreOnlineSettingsRequest.php - Resource:
app/Http/Resources/BackOffice/OnlineSettings/ShowOnlineSettingsResource.php - Route File:
routes/api/backoffice/online-settings.php(mounted under the/back-officeprefix) - Constants:
app/Constants.php--getDefaultOnlineSettings()and the$DEFAULT_ORDER_CAPACITY_SETTINGSstatic property - Vue Component:
src/views/online-settings/OnlineSettingsForm.vue - Store Module:
src/store/modules/onlineSettings.ts - Types:
src/types/onlineSettings.ts - Related Components (shared with In-House settings):
src/views/in-house/components/forms/OrderCapacityManagement.vue,src/views/in-house/components/forms/CollectTips.vue,src/views/in-house/components/forms/CheckoutNotes.vue,src/components/DefaultMenusSection.vue(all rendered withmode="online-settings")
Actions
View Online Settings
Retrieve the current online settings for a specific location. OnlineSettingsService::show() resolves the Location, reads its online_settings, and enriches it by fetching the full Menu objects for the default menu (default_menu) and any extra menus (extra_menus). The resource (ShowOnlineSettingsResource) reads getOnlineSettings(alsoRetrieveCategoryName: true) (so category names are resolved for any category-specific limits), then strips raw default_menu_id and extra_menu_ids and replaces them with expanded default_menu / extra_menus objects (each with id, name, description, schedule).
- Endpoint:
GET /api/back-office/online-settings/{locationId} - Response: JSON
ShowOnlineSettingsResourcecontainingid, the spreadonline_settings(order_capacity, delivery_available_days, pickup_available_days, collect_tips, allow_notes), an explicitly computedallow_order_notes(see below), plusdefault_menu(or null) andextra_menus(array, defaults to[]) - Backward compatibility for
allow_order_notes:ShowOnlineSettingsResourcealways returnsallow_order_notesexplicitly: it uses the storedallow_order_notesif present, else falls back to the storedallow_notes, else falls back to{enabled: false, placeholder: 'Add a note for your whole order'}. This lets locations saved before order notes were split into their own setting keep working without a migration.
Update Online Settings
Save updated online settings for a specific location. The request is validated through StoreOnlineSettingsRequest. In prepareForValidation() the request:
- Merges
Constants::getDefaultOnlineSettings()defaults intoorder_capacity,collect_tips,allow_notes, andallow_order_notes(and defaultsdelivery_available_days/pickup_available_daysto[]if absent). Forallow_order_notesspecifically, the merge order is: defaults, then the request'sallow_notesvalue (backward-compat fallback for callers that only sendallow_notes), then the request's ownallow_order_notesvalue (if sent, it wins). - Applies "Guardrail A" normalization: if
enable_limit_specific_categoriesis true butlimit_specific_categoriesis empty, the toggle is forced off; ifenable_flexible_limit_order_per_time_slotis true butvalue_threshold_per_time_slot/allow_up_toare not valid positive numbers, the flexible toggle is forced off (same normalization is applied per time-specific rule).
After validation, OnlineSettingsService::update() performs business-logic validation:
- Validates the default menu via
isMenuEligible($settings['default_menu_id']). - For each extra menu: aborts 400 if it equals the default menu; resolves it via
getEligibleMenu($extraMenuId, locationId: ...); aborts 400 if its own schedule self-overlaps (isSingleScheduleOverlap); within a nested loop aborts 400 on duplicate extra menus and on cross-menu schedule overlap (isScheduleOverlap). - Saves the validated payload to the location's
online_settingsfield viaLocationRepository::save(). - Clears both timeslot caches for the location --
OrderCapacityService::clearAvailableTimeslotsCache($locationId)andOrderCapacityService::clearAllTimeSlotStatsCacheForLocation($locationId)-- so a capacity change is visible on the storefront immediately instead of after the cache TTL. (Verified:app/Services/BackOffice/OnlineSettingsService.phplines 106-113.) - Dispatches a
ReloadMenu($locationId)event.
- Endpoint:
PUT /api/back-office/online-settings/{locationId} - Request Body: Full settings object (see Fields section)
- Response: Standard success response (
sendSuccess())
Fields
Order Capacity - Global Settings
| Field | ID | Type | Required | Validation |
|---|---|---|---|---|
| Order Capacity Enabled (master toggle) | order_capacity.enabled | Boolean | No | nullable|boolean |
| Time Slot Duration (min) | order_capacity.time_slot_duration_min | Number | Yes | required|numeric|gt:0 |
| Limit Orders per Slot | order_capacity.limit_orders_per_time_slot | Boolean | Yes | required|boolean |
| Max Orders per Slot | order_capacity.number_of_orders_per_time_slot | Number | Conditional | nullable by default; becomes required|numeric|gt:0 when limit_orders_per_time_slot is true |
| Limit Items per Slot | order_capacity.limit_items_per_time_slot | Boolean | Yes | required|boolean |
| Max Items per Slot | order_capacity.number_of_items_per_time_slot | Number | Conditional | nullable by default; becomes required|numeric|gt:0 when limit_items_per_time_slot is true |
Order Capacity - Flexible Capacity
| Field | ID | Type | Required | Validation |
|---|---|---|---|---|
| Enable Flexible Capacity | order_capacity.enable_flexible_limit_order_per_time_slot | Boolean | Yes | required|boolean |
| Value Threshold per Slot | order_capacity.value_threshold_per_time_slot | Number | Conditional | nullable|numeric|gt:0 by default; becomes required|numeric|gt:0 when flexible enabled |
| Allow Up To (extra orders) | order_capacity.allow_up_to | Integer | Conditional | nullable|integer|gt:0 by default; becomes required|integer|gt:0 when flexible enabled |
Order Capacity - Category-Specific Limits
| Field | ID | Type | Required | Validation |
|---|---|---|---|---|
| Enable Category Limits | order_capacity.enable_limit_specific_categories | Boolean | Yes | required|boolean |
| Category Limits | order_capacity.limit_specific_categories | Array | Conditional | array; required only when both enable_limit_specific_categories AND a non-empty limit_specific_categories are present, else nullable. Each entry's category_id must exist via ExistsInConnectionArrayWithModel (Category, tenant/settings collection) |
| Category ID | order_capacity.limit_specific_categories.*.category_id | String | Yes | required|distinct|string |
| Items per Slot per Category | order_capacity.limit_specific_categories.*.number_of_items_per_time_slot | Number | Yes | required|numeric|gt:0 |
Order Capacity - Time-Specific Rules
All paths below are nested under order_capacity.time_specific_rules.*. The array itself is nullable|array with a closure that rejects overlapping ranges (hasOverlappingTimeRanges).
| Field | ID | Type | Required | Validation |
|---|---|---|---|---|
| Rule Name | ...time_specific_rules.*.name | String | Yes | required|string|distinct -- unique among rules |
| Time Range | ...time_specific_rules.*.time_range | Object | Yes | required|array |
| Time Range From | ...time_specific_rules.*.time_range.from | String | Yes | required|string |
| Time Range To | ...time_specific_rules.*.time_range.to | String | Yes | required|string |
| Active Days | ...time_specific_rules.*.active_days | Array | Yes | required|array; each entry required|Rule::in(Carbon::getDays()) (full day names, e.g. "Monday") |
| Orders per Slot | ...time_specific_rules.*.number_of_orders_per_time_slot | Number | No | nullable|numeric|gt:0 |
| Items per Slot | ...time_specific_rules.*.number_of_items_per_time_slot | Number | No | nullable|numeric|gt:0 |
| Enable Flexible (per rule) | ...time_specific_rules.*.enable_flexible_limit_order_per_time_slot | Boolean | No | nullable|boolean |
| Value Threshold (per rule) | ...time_specific_rules.*.value_threshold_per_time_slot | Number | Conditional | becomes required|numeric|gt:0 when that rule's flexible toggle is true |
| Allow Up To (per rule) | ...time_specific_rules.*.allow_up_to | Integer | Conditional | becomes required|integer|gt:0 when that rule's flexible toggle is true |
| Category Limits (per rule) | ...time_specific_rules.*.limit_specific_categories | Array | No | nullable|array + ExistsInConnectionArrayWithModel; entries *.category_id required|distinct|string, *.number_of_items_per_time_slot required|numeric|gt:0 |
Delivery and Pickup
| Field | ID | Type | Required | Validation |
|---|---|---|---|---|
| Delivery Available Days | delivery_available_days | Array | No | nullable|array; each entry required|Rule::in(Carbon::getDays()) (full day names) |
| Pickup Available Days | pickup_available_days | Array | No | nullable|array; each entry required|Rule::in(Carbon::getDays()) (full day names) |
Tips
| Field | ID | Type | Required | Validation |
|---|---|---|---|---|
| Collect Tips (object) | collect_tips | Object | Yes | required|array |
| Enable Tips | collect_tips.enabled | Boolean | Yes | required|boolean |
| Tip Options | collect_tips.options | Array | Conditional | nullable|array (becomes required when collect_tips.enabled is true); each value numeric|min:1|max:100. Front office sends exactly 3 values |
| Calculate Tips Method | collect_tips.calculate_tips | Enum | Conditional | nullable (becomes required when enabled) + Rule::enum(CalculateTipsOptions::class); valid values are the enum's string values "After taxes" / "Before taxes" |
Notes
There are two independent note settings, both rendered by the shared CheckoutNotes.vue component: per-item notes (allow_notes, UI label "Allow Item Notes") and a whole-order note (allow_order_notes, UI label "Allow Order Notes").
| Field | ID | Type | Required | Validation |
|---|---|---|---|---|
| Allow Notes (object) -- per-item | allow_notes | Object | Yes | required|array |
| Enable Item Notes | allow_notes.enabled | Boolean | Yes | required|boolean |
| Item Notes Placeholder | allow_notes.placeholder | String | Conditional | nullable|string (becomes required|string when allow_notes.enabled is true) |
| Allow Order Notes (object) -- whole order | allow_order_notes | Object | Yes | required|array |
| Enable Order Notes | allow_order_notes.enabled | Boolean | Yes | required|boolean |
| Order Notes Placeholder | allow_order_notes.placeholder | String | Conditional | nullable|string (becomes required|string when allow_order_notes.enabled is true) |
Menu Assignment
| Field | ID | Type | Required | Validation |
|---|---|---|---|---|
| Default Menu ID | default_menu_id | String | Yes | required|string (request-level); the service then enforces eligibility via isMenuEligible |
| Extra Menu IDs | extra_menu_ids | Array | No | nullable|array, each entry required|string. Uniqueness, not-equal-to-default, eligibility, and schedule-overlap checks are enforced in the service (not in the request rules) |
Business Rules
- The default menu must pass eligibility validation via
isMenuEligiblefrom theMenuTrait, ensuring it is a valid, active menu that can serve the online ordering channel. - Extra menus cannot be the same as the default menu. The service checks
$extraMenuId === $settings['default_menu_id']and aborts with a 400 error and message "Extra menu cannot be the same as default menu" if they match. - Extra menus cannot be duplicated. The service uses a nested loop comparing
$extraMenuId === $extraMenuId2(skipping self-comparison) and aborts with "Extra menu cannot be duplicated" if a duplicate is found. - Extra menu schedules must not overlap with each other. The service calls
isScheduleOverlapfor each pair of extra menus, passing their schedules resolved viagetSchedule($location). A descriptive error naming both conflicting menus is returned: "There is a schedule overlap between :extraMenuName and :extraMenu2Name". - Each extra menu's schedule is also checked for internal self-overlap via
isSingleScheduleOverlap, returning "There is a time overlap in the schedule" if the menu's own time windows conflict. - Time-specific rules within order capacity must not have overlapping time ranges for the same day. The
hasOverlappingTimeRangesvalidation (fromSchedulingTrait) is applied as a custom validation closure on thetime_specific_rulesarray. StoreOnlineSettingsRequest::prepareForValidation()merges default values fromConstants::getDefaultOnlineSettings()intoorder_capacity,collect_tips,allow_notes, andallow_order_notesbefore validation. Defaults include all seven days (Sunday through Saturday) for delivery and pickup, tips disabled with[10, 15, 20]options andcalculate_tipsset to theAFTER_TAXESenum value (string"After taxes"), item notes (allow_notes) disabled with a placeholder string, and order notes (allow_order_notes) disabled with the placeholder"Add a note for your whole order".- Guardrail A normalization runs in
prepareForValidation()before the rules: an enabled-but-emptyenable_limit_specific_categoriesis forced off, and an enabled-but-invalidenable_flexible_limit_order_per_time_slot(missing/invalid threshold or allow_up_to) is forced off -- both globally and per time-specific rule. - Conditional validation rules are dynamically computed:
number_of_orders_per_time_slotbecomes required only whenlimit_orders_per_time_slotis true;number_of_items_per_time_slotonly whenlimit_items_per_time_slotis true;value_threshold_per_time_slot/allow_up_toonly whenenable_flexible_limit_order_per_time_slotis true (global, and re-evaluated per time-specific rule);limit_specific_categoriesonly when both the toggle and a non-empty list are present; tipoptions/calculate_tipsonly whencollect_tips.enabledis true;allow_notes.placeholderonly whenallow_notes.enabledis true; andallow_order_notes.placeholderonly whenallow_order_notes.enabledis true.
Customer Impact
- Online Ordering: These settings configure the online ordering experience for the location: order capacity limits, available delivery/pickup days, tip options, and checkout notes. (Storefront/proxy enforcement of these settings is not verified here.)
- Delivery: The
delivery_available_daysarray configures which days delivery is offered. Defaults to all seven days (Sunday through Saturday). - Pickup: The
pickup_available_daysarray configures which days pickup is available. Same shape as delivery availability. Defaults to all seven days. - Kitchen Operations: Order capacity limits are intended to bound the orders/items accepted per time slot; flexible capacity allows configured value-based exceptions, and category-specific limits target specific categories. (Actual order-time enforcement is handled by
OrderCapacityService, not verified in detail here.) - Revenue: Tip collection settings (enabled, options, before/after-taxes calculation) feed the storefront checkout tip display. The precise checkout effect is not verified here.
FAQs
What are the default online settings for a new location?
New locations use defaults from Constants::getDefaultOnlineSettings(): all seven days available for both delivery and pickup; tips disabled with [10, 15, 20] option presets and calculate_tips = "After taxes"; item notes (allow_notes) disabled with a sample placeholder string; order notes (allow_order_notes) disabled with placeholder "Add a note for your whole order"; default_menu_id null; and extra_menu_ids empty. Order capacity also has defaults from $DEFAULT_ORDER_CAPACITY_SETTINGS: enabled false, time_slot_duration_min 15, all limit/flexible/category toggles false, numeric fields null, and empty limit_specific_categories / time_specific_rules.
What is the difference between "Allow Item Notes" and "Allow Order Notes"?
These are two independent checkout note settings, both configured in the same Notes section of Online Settings:
- Allow Item Notes (
allow_notes) lets customers add a note to an individual line item (e.g. "no onions" on a specific burger). - Allow Order Notes (
allow_order_notes) lets customers add one note that applies to the whole order (e.g. "please ring the doorbell").
Each has its own enabled toggle and placeholder text, and both can be turned on independently. If a location was saved before allow_order_notes existed, the back office shows the old allow_notes value for both fields until the merchant configures order notes separately.
How do time-specific rules work?
Time-specific rules override the global order capacity settings during their defined time windows on their specified active days. For example, you can create a "Lunch Rush" rule for 11:00-14:00 with a higher order limit, and a "Dinner" rule for 17:00-21:00 with different limits. Each rule requires a unique name, a time_range (from/to), and at least one active_days entry (full day names like "Monday"); the per-rule number_of_orders_per_time_slot and number_of_items_per_time_slot are optional (nullable). Time ranges must not overlap for the same day (enforced by hasOverlappingTimeRanges). Each rule can also enable its own flexible capacity (then value_threshold_per_time_slot and allow_up_to become required) and define category-specific limits. The exact runtime enforcement of these rules is handled by OrderCapacityService and is not detailed here.
Can I have different online settings per location?
Yes. Online settings are stored on each Location document independently. Each location can have completely different order capacity limits, available days, tip settings, menu assignments, and all other configurations. Changes to one location do not affect others.
What is flexible capacity?
Flexible capacity allows exceeding the base order limit when the total order value meets a minimum threshold. For example, if the limit is 10 orders per slot and flexible capacity is enabled with a threshold of 50 and "allow up to" 5, then up to 5 additional orders can be accepted if each meets the value threshold. This is useful for not turning away high-value orders during busy periods.
How do extra menus with schedules work?
The default menu is always available during operating hours. Extra menus have their own schedules (configured on the menu itself, resolved per location) and are only shown during their configured time windows. This allows offering different menus for breakfast, lunch, and dinner on the online ordering channel. Schedules across extra menus must not overlap with each other.
What does the "calculate tips" option control?
The calculate_tips field determines how suggested tip amounts are calculated: either before taxes or after taxes. The CalculateTipsOptions enum defines the two valid values, whose stored string values are "After taxes" and "Before taxes" (the default is "After taxes"). NOTE: exactly how this affects the amounts shown at the storefront checkout is not verified here.
Troubleshooting
"Extra menu cannot be the same as default menu" error
You have added the same menu as both the default and an extra menu. Remove the duplicate from the extra menus list, or choose a different menu as the default. The service compares IDs directly.
"There is a schedule overlap between X and Y" error
Two extra menus have overlapping availability schedules at the current location. The error message names both conflicting menus. Review their schedules (configured on each menu, resolved per location via getSchedule) and adjust time windows so they do not conflict.
"There is a time overlap in the schedule" error for an extra menu
A single extra menu has overlapping time ranges within its own schedule at this location. The isSingleScheduleOverlap check found conflicting time windows. Review and fix the menu's schedule configuration.
Order capacity limits are not being enforced
Verify that limit_orders_per_time_slot or limit_items_per_time_slot is set to true and the corresponding numeric value is greater than zero. Check that time_slot_duration_min is configured with a sensible value. If using time-specific rules, verify the rule's active days and time range cover the period in question. The OrderCapacityService reads these settings from the location's online_settings at order time.
Time-specific rules validation fails
Ensure each time-specific rule has: a unique name (enforced by distinct validation), a time_range with valid from/to strings, and at least one valid active_days entry (full day names like "Monday", validated against Carbon::getDays()). The per-rule number_of_orders_per_time_slot and number_of_items_per_time_slot are optional, but when present must be > 0. Also ensure no two rules' time ranges overlap on the same day (hasOverlappingTimeRanges). If flexible capacity is enabled per rule, value_threshold_per_time_slot and allow_up_to become required and must be positive.
Saved settings do not appear on the online ordering frontend
After saving, a ReloadMenu event is dispatched and both timeslot caches for the location are cleared, so order-capacity changes should be reflected on the very next storefront request -- there is no propagation delay to wait out for settings saved on this page. If changes still do not appear, verify the menu cache has been refreshed for the location. Check that the default menu is correctly assigned and that its display groups have Online Ordering in their visibility arrays.
Note that this does not cover the scheduling settings on the separate Online Ordering page (blocked times, custom availability, days-in-advance, last pickup slot). That save path does not clear the timeslot caches, so those changes can take up to 60 seconds to appear. (Verified: app/Services/BackOffice/OnlineOrderingService.php::update() lines 223-280 has no cache-clear call; contrast OnlineSettingsService.php lines 106-113.)
Technical Details
Default Settings Initialization
The Constants::getDefaultOnlineSettings() method returns the default online settings structure:
order_capacity: the$DEFAULT_ORDER_CAPACITY_SETTINGSstatic property --{enabled: false, time_slot_duration_min: 15, limit_orders_per_time_slot: false, number_of_orders_per_time_slot: null, limit_items_per_time_slot: false, number_of_items_per_time_slot: null, enable_flexible_limit_order_per_time_slot: false, value_threshold_per_time_slot: null, allow_up_to: null, enable_limit_specific_categories: false, limit_specific_categories: [], time_specific_rules: []}delivery_available_days: All seven days (Sunday through Saturday)pickup_available_days: All seven days (Sunday through Saturday)collect_tips:{enabled: false, options: [10, 15, 20], calculate_tips: "After taxes"}(the value ofCalculateTipsOptions::AFTER_TAXES)allow_notes(per-item notes):{enabled: false, placeholder: "E.g. \"For Oliver\" or \"I'm allergic to mushrooms"}allow_order_notes(whole-order note):{enabled: false, placeholder: "Add a note for your whole order"}default_menu_id: nullextra_menu_ids: empty array
StoreOnlineSettingsRequest::prepareForValidation() merges these defaults into order_capacity, collect_tips, allow_notes, and allow_order_notes, defaults delivery_available_days/pickup_available_days to [] if absent, and applies Guardrail A normalization (see Update Online Settings). Note: it does NOT merge a default_menu_id/extra_menu_ids default -- default_menu_id is required and supplied by the caller.
allow_order_notes backward compatibility: allow_order_notes was split out of allow_notes as its own setting. Both the backend (ShowOnlineSettingsResource, StoreOnlineSettingsRequest::prepareForValidation()) and the back-office store (onlineSettings.ts) fall back to the value of allow_notes whenever allow_order_notes is missing, so locations saved before the split continue to behave as before (item notes and order notes both reflect the old single allow_notes value) until the merchant explicitly configures the two settings independently.
Backoffice Store Module
The Vue store module (src/store/modules/onlineSettings.ts) transforms the API response (SET_ONLINE_SETTINGS_FORM) into a form-friendly structure:
collect_tips.options[0..2]->tip_percentage_1,tip_percentage_2,tip_percentage_3collect_tips.enabled->is_collect_tipscollect_tips.calculate_tips->calculate_tips_type(only kept if it is one of the knownInHouseSettingsSectionCalculateTipsTypevalues, else null)allow_notes.enabled->is_allow_notes;allow_notes.placeholder->notesallow_order_notes.enabled->is_allow_order_notes;allow_order_notes.placeholder->order_notes. If the API response has noallow_order_notes, the store first falls back toallow_notesbefore readingenabled/placeholder(backward compatibility, see above).default_menu+extra_menus-> a unifiedmenusarray, each entry{is_default: boolean, data: menu}order_capacityis spread over the default form shape, then locally normalized (category toggle off if no entries; flexible toggle off if no threshold/allow_up_to)
The saveOnlineSettingsForm action reverses these: it rebuilds collect_tips ({enabled, options: [tip_percentage_1, tip_percentage_2, tip_percentage_3], calculate_tips: calculate_tips_type}), allow_notes ({enabled, placeholder: notes}), allow_order_notes ({enabled: is_allow_order_notes, placeholder: order_notes}), default_menu_id/extra_menu_ids from menus, plus order_capacity, delivery_available_days, and pickup_available_days, and PUTs them to the endpoint.
Schedule Overlap Detection
Two traits provide the validation methods used during online settings update:
MenuTrait::isMenuEligible($menuId, ...)andMenuTrait::getEligibleMenu($id, locationId, ...): validate that a menu exists and is eligible (and resolve theMenufor an extra menu).SchedulingTrait::isSingleScheduleOverlap($schedule): checks a single schedule for internal time-range conflicts (and aborts 400 on an invalid time range wherefrom >= to).SchedulingTrait::isScheduleOverlap($schedule1, $schedule2): compares two schedules for cross-schedule time-range conflicts (an all-day availability always overlaps).SchedulingTrait::hasOverlappingTimeRanges($rules): used as a closure onorder_capacity.time_specific_rulesto reject rules whose ranges overlap on the same day.
Assistant Guidance
When users ask about online settings, first determine which aspect they need help with: order capacity, delivery/pickup days, tips, notes, or menu assignment. For order capacity questions, explain the three-tier hierarchy: global settings apply by default, time-specific rules override during their configured periods, and flexible capacity provides value-based exceptions. Emphasize that online settings are per-location and changes only affect the selected location. If users report issues with menu display in online ordering, check both the online settings menu assignment and the individual display group visibility settings. For tip configuration, explain the difference between calculating tips before versus after taxes (calculate_tips enum values "Before taxes" / "After taxes") and that up to three percentage options are configured; how they render at customer checkout is a storefront concern not detailed here. For notes questions, always clarify which of the two independent settings the user means: "Allow Item Notes" (allow_notes, a note per line item) versus "Allow Order Notes" (allow_order_notes, one note for the whole order) -- they have separate toggles and placeholders. If a merchant reports their order notes toggle unexpectedly matches their item notes value, mention the backward-compatibility fallback: locations saved before allow_order_notes existed show the allow_notes value for both until the merchant saves the order notes setting explicitly.
Relations
Depends On
- Locations: Online settings are stored on the
Locationdocument'sonline_settingsfield. A valid location must exist. - Menus: Default and extra menus must exist and pass eligibility checks. Menu schedules are resolved per location for overlap validation.
- Categories: Category-specific order limits reference category IDs that must exist in the
settingscollection. - Constants: Default values are sourced from
Constants::getDefaultOnlineSettings(). - SchedulingTrait: Provides
isScheduleOverlap,isSingleScheduleOverlap, andhasOverlappingTimeRangesvalidation methods. - MenuTrait: Provides
isMenuEligibleandgetEligibleMenumethods for menu validation.
Affects
- Online Ordering Channel: Directly controls order capacity, available days, tip options, note collection, and menu display for the customer-facing online ordering experience.
- Order Processing: Order capacity limits (managed by
OrderCapacityService) determine whether new orders are accepted or rejected during specific time slots. - Menu Cache: Updating online settings dispatches a
ReloadMenuevent, triggering a refresh of cached menus for the affected location. - Timeslot Availability Cache: Updating online settings also clears the location's available-timeslots cache (60-second TTL) and slot-stats cache (30-second TTL), so changed capacity limits apply to the very next storefront availability request. (Verified:
app/Services/BackOffice/OnlineSettingsService.phplines 106-113; TTLs atapp/Services/OrderCapacity/OrderCapacityService.phplines 32-35 and 1789-1800.) - Kitchen Operations: Order and item limits per time slot directly impact kitchen workload, order throughput, and preparation scheduling.
- Transaction Processing: Tip settings (enabled/options/calculate_tips) feed downstream tip handling at order time. (The exact runtime tip calculation/application is outside this settings page and not verified here.)
- Revenue: Tip collection settings and calculation method affect the tip revenue collected per order (storefront behavior not verified here).