Appearance
In-House Settings
Overview
In-House Settings configure dine-in operations for a location: table sections, tip collection, checkout notes, and the menus shown for in-house ordering.
Key Purpose: Configure dine-in / in-house ordering settings for a location.
The page requires a POS to be connected. If no POS channel is connected for the selected location, the form redirects to the home screen (
InHouseSettingsForm.vuemounted()).
QR code generation, ordering hours, customer name/email requirements, and the customer-facing table-ordering flow are configured on a separate page — see QR Table Ordering. This doc covers only the in-house dining settings cluster.
Purpose
This page lets you configure dine-in ordering for a location: organize tables into sections, optionally collect tips, optionally allow checkout notes, and choose the default and extra menus used for in-house ordering.
Key Concepts
- In-House Setting: Configuration stored per location as
in_house_settingon the Location model. The persisted object stores onlycollect_tips,allow_notes,allow_order_notes,default_menu_id, andextra_menu_ids(InHouseSettingsService::update). Table sections are stored separately asTableSectionmodels, not insidein_house_setting. - Table Sections: Named groups of tables (e.g. "Dining Room", "Bar") with a
table_name_typeof either Automatic or Custom. Sections are created/updated/deleted asTableSectionrecords and are shared with QR Ordering (see QR Table Ordering). - Tip Collection: Optional gratuity collection with three percentage options (default
[10, 15, 20]) and a choice of calculating tips before or after taxes (default: After taxes). - Checkout Notes: Optional free-text note field; when enabled you set the placeholder shown to customers. The placeholder is validated as a string by the backend; the back-office editor caps it at 150 characters.
- Menus: A required default menu (
default_menu_id) and optional extra menus (extra_menu_ids) with scheduled availability. Extra menus cannot duplicate the default or each other, and their schedules must not overlap (InHouseSettingsService::update).
Actions
Manage Table Sections
Add, edit, or delete table sections. Each section has a name and a Naming type (Automatic or Custom — see Fields). Deletions are queued in deleted_sections and applied on save; sections can't be deleted while in use by QR Ordering, and the MplusKassa Tables section is skipped from UI updates and deletion.
Enable Tip Collection
Toggle Collect Tips, set three tip percentage options, and choose whether tips are calculated before or after taxes. A POS warning is shown: tips must be enabled in the POS before they can be collected.
Enable Checkout Notes
Toggle Allow Notes and set the placeholder text shown in the "add note" field.
Assign Menus
Set a default menu (must be eligible for in-house visibility) and optionally add extra menus with scheduled availability. Extra menus cannot duplicate the default or each other, and schedules cannot overlap.
Location
- Backoffice Route:
/in-house/settings(file-based router;src/pages/in-house/settings.vue, registered intyped-router.d.tsasin-house-settings) - Backoffice View:
src/views/in-house/InHouseSettingsForm.vue - Form Components:
src/views/in-house/components/forms/SectionsAndTables.vue,CollectTips.vue,CheckoutNotes.vue, andsrc/components/DefaultMenusSection.vue - Section Editor:
src/views/in-house/components/settings/SectionFormDialog.vue - Store Module:
src/store/modules/inHouse.ts(saveInHouseSettingsForm→PUT /back-office/in-house-settings/{locationId}) - Backend Controller:
app/Http/Controllers/Api/BackOffice/InHouseSettingsController.php - Backend Request:
app/Http/Requests/BackOffice/InHouseSettings/StoreInHouseSettingsRequest.php - Backend Orchestrator/Service:
app/Services/Orchestrators/BackOffice/InHouseSettingsOrchestrator.php,app/Services/BackOffice/InHouseSettingsService.php - API:
GETandPUT /back-office/in-house-settings/{locationId}(routes/api/backoffice/in-house-settings.php);GETrequires permissionview-sales-channel,PUTrequiresedit-in-house-channel.
Fields
These are the fields validated by StoreInHouseSettingsRequest (the request body of the in-house settings PUT). The back-office form sends an additional order_capacity block, but the backend request does not validate it and InHouseSettingsService::update does not persist it for in-house — order capacity belongs to Online Ordering, not the in-house setting.
Collect Tips — Enabled
| Property | Value |
|---|---|
| Field ID | collect_tips.enabled |
| Label | Collect Tips |
| Type | Boolean (toggle) |
| Default | false |
Description: Master switch for tip collection. When off, the percentage and calculation fields are nullable.
Collect Tips — Options
| Property | Value |
|---|---|
| Field ID | collect_tips.options (array of numbers) |
| Label | Tip Percentage |
| Type | Array of numeric values |
| Rules | Required when tips enabled; each value numeric, min:0, max:100 |
| Default | [10, 15, 20] |
Description: The tip percentage options offered at checkout. The back-office form exposes exactly three percentage inputs (tip_percentage_1/2/3), each requiring a value of at least 1.
Collect Tips — Calculate Tips
| Property | Value |
|---|---|
| Field ID | collect_tips.calculate_tips |
| Label | Calculate Tips |
| Type | Enum (CalculateTipsOptions) |
| Options | After taxes, Before taxes |
| Default | After taxes |
Description: Whether the tip is calculated on the amount after or before taxes. Enum values are the literal strings After taxes / Before taxes (lowercase "taxes").
Allow Notes — Enabled
| Property | Value |
|---|---|
| Field ID | allow_notes.enabled |
| Label | Allow Notes |
| Type | Boolean (toggle) |
| Default | false |
Description: Whether customers can add a free-text note to items at checkout.
Allow Notes — Placeholder
| Property | Value |
|---|---|
| Field ID | allow_notes.placeholder |
| Label | Placeholder text |
| Type | String |
| Rules | Required when notes enabled; backend rule is string (no length limit); back-office editor caps at 150 characters |
| Default | E.g. "For Oliver" or "I'm allergic to mushrooms |
Description: The placeholder shown in the "add note" field. The default string is defined in Constants::getDefaultInHouseSettings() (note: the stored default has an unbalanced closing quote in code).
Allow Order Notes — Enabled
| Property | Value |
|---|---|
| Field ID | allow_order_notes.enabled |
| Label | Allow Order Notes |
| Type | Boolean (toggle) |
| Default | false |
Description: Whether customers can add one free-text note covering the whole order, as opposed to allow_notes, which is the per-item note. The two are independent toggles on the same Checkout Notes card.
Backward compatibility: order notes were split out of
allow_notesafter launch.StoreInHouseSettingsRequestmergesallow_notesintoallow_order_notesas a fallback, so a tenant saved before the split — which sends onlyallow_notes— keeps the old combined behaviour until the merchant configures the split explicitly (StoreInHouseSettingsRequest.php:36-45).
Allow Order Notes — Placeholder
| Property | Value |
|---|---|
| Field ID | allow_order_notes.placeholder |
| Label | Placeholder text |
| Type | String |
| Rules | Required when order notes enabled; backend rule is string (no length limit); back-office editor caps at 150 characters |
| Default | Add a note for your whole order |
Description: The placeholder shown in the order-level note field (Constants::getDefaultInHouseSettings(), Constants.php:252-254).
Default Menu
| Property | Value |
|---|---|
| Field ID | default_menu_id |
| Label | Default Menu |
| Type | String (menu id) |
| Rules | `required |
| Default | null (until set) |
Description: The menu shown for in-house ordering. Must be an eligible menu (InHouseSettingsService::update calls isMenuEligible).
Extra Menus
| Property | Value |
|---|---|
| Field ID | extra_menu_ids (array of strings) |
| Label | Extra Menus |
| Type | Array of menu ids |
| Rules | `nullable |
| Default | [] |
Description: Additional menus with scheduled availability. Each must be eligible, cannot equal the default menu, cannot be duplicated, and cannot have an overlapping schedule.
Sections (table sections)
| Property | Value |
|---|---|
| Field ID | sections (array) |
| Type | Array of section objects |
| Rules | `nullable |
Description: Table sections to create or update on save. See Table Sections below for per-section fields. Deletions are sent separately via deleted_sections (array of section id strings).
Table Sections
A location's tables are organized into sections (e.g. "Dining Room", "Bar"). Each section is persisted as a TableSection model and is shared with QR Ordering. Per-section fields validated by the request:
Section Name
| Property | Value |
|---|---|
| Field ID | sections.*.name |
| Label | Section Name |
| Type | String |
| Rules | required, string, unique per location (UniqueInConnectionWithModel), and distinct across the submitted list |
Description: Section names must be unique within the location. The back-office editor shows a {count}/25 character hint, but the 25-character cap is a UI display hint only — it is not enforced by a validation rule on the field.
Naming (per section)
| Property | Value |
|---|---|
| Field ID | sections.*.table_name_type |
| Label | Naming |
| Type | Enum (TableNameType) |
| Options | Automatic Tables Names, Custom Tables Name |
Description: How a section's tables are named. Note the literal enum strings: Automatic Tables Names and Custom Tables Name (these exact strings are used by both backend and front-end).
Options:
- Automatic (
Automatic Tables Names): set atable_label(optional, max 10 chars) andtable_numbers(requiredinteger, min:1); the backend generates names like{section} {label} {n}(or{section} {n}when no label). - Custom (
Custom Tables Name): enter each table name intable_names(required array; eachstring, max:20);table_numbersis set to the count of names.
Include Tables
| Property | Value |
|---|---|
| Field ID | sections.*.include_tables |
| Type | Boolean (nullable) |
| Default | false (section editor) |
Description: When include_tables is false (or table_numbers is 0 with no custom names), the section is saved with no tables (table_names = [], table_numbers = 0, table_label = '') and the Automatic/Custom table rules are not enforced.
Order Acceptance & POS Forwarding
In-house orders placed via Kiosk, Table QR, or staff are processed automatically. There is no toggle to hold orders for manual acceptance, and no in-house setting to stop forwarding orders to a connected POS — none of these are fields on StoreInHouseSettingsRequest.
The in-house setting does not store enabled, service_mode, table_service, counter_service, show_order_number, order_number_format, starting_number, prep_time, auto_accept, send_to_kds, print_kitchen_ticket, or print_receipt — those are not real fields of this feature. It manages table sections, tip collection, checkout notes, and the default/extra menus.
To manage incoming order volume, use the channel-level controls and Order Capacity in Online Ordering / QR Ordering settings instead (not configured here).
To stop taking table QR orders temporarily, use the Snooze dropdown on the Table QR Code Ordering page (/in-house/qr-ordering) — 20 / 40 / 60 minutes, the rest of the day, or "Don't accept orders". It writes qr_ordering_setting.snoozed_until on the location and is independent of the Online Ordering snooze. There is no snooze control on the In-House settings page itself. (Verified: POST /back-office/qr-ordering/{locationId}/snooze in upvendo-backend routes/api/backoffice/qr-ordering.php line 11, QrOrderingService::snooze; UI in upvendo-backoffice src/views/in-house/components/qr-ordering/QROrderingForm.vue lines 76-87 and 229-266. See QR Ordering.)
Business Logic
Save flow
On save, the back-office form sends a PUT /back-office/in-house-settings/{locationId}. The orchestrator (InHouseSettingsOrchestrator::update):
- Loads existing table sections and partitions out the
MplusKassa Tablesintegration section. - Processes
deleted_sections, skipping the MplusKassa integration section, and aborts with HTTP 400 if a section is still in use by QR Ordering. - Creates/updates submitted
sections(skipping theMplusKassa Tablessection), generating table names for Automatic sections. - Persists
collect_tips,allow_notes,allow_order_notes,default_menu_id, andextra_menu_idstoin_house_setting(InHouseSettingsService::update) and fires aReloadMenuevent. - Dispatches
GenerateQrCodesForSectionfor any sections whose table names changed or that are missing their R2 QR path.
order_capacity is not persisted here
The back-office store includes order_capacity in the PUT payload (saveInHouseSettingsForm), but the backend request does not validate it and the service does not store it in in_house_setting. Order capacity is an Online Ordering setting (see Order Capacity), not part of the in-house setting.
Relations
Depends On
- Locations: Settings are stored per location (
in_house_setting). - Menus: The default/extra menus must be eligible menus.
- POS connection: The settings page is only accessible when a POS channel is connected.
Affects
- QR Ordering: Shares the same table sections.
- Kiosk / Table QR: In-house ordering uses these settings (storefront behavior not verified here).
- KDS / Transactions: In-house orders flow downstream (not verified here).
Related Features
Business Rules
- The default menu (
default_menu_id) is required and must be an eligible menu. - Extra menus cannot equal the default menu, cannot be duplicated, and their schedules cannot overlap (validated server-side with HTTP 400 errors).
- Section names must be unique within the location and distinct across the submitted list.
- A section currently used by QR Ordering cannot be deleted — the save aborts with HTTP 400 until it is removed from QR Ordering first.
- The
MplusKassa Tablessection (exact name) is protected: it is skipped from UI section updates and cannot be deleted through this form. - Saving fires a
ReloadMenuevent and may dispatchGenerateQrCodesForSectionjobs when section table names change. - There is no front-end "at least one section required" enforcement on this page (the only such check exists, commented out, on the QR Ordering page).
FAQs
- "What does the in-house setting actually store?" Only
collect_tips,allow_notes,allow_order_notes,default_menu_id, andextra_menu_ids. Table sections are stored separately asTableSectionmodels. It does not storeservice_mode,prep_time,auto_accept,print_kitchen_ticket, etc. - "Why is
order_capacityin the save payload but not saved?" The front-end form includes it, but the backend in-house request doesn't accept it and the service doesn't persist it. Order capacity is an Online Ordering setting. - "How does tip collection work?" When enabled, three percentage options are offered (default 10/15/20) and tips can be calculated before or after taxes (default After taxes).
- "What happens when I delete a section?" The save blocks deletion if the section is in use by QR Ordering (HTTP 400) and skips the
MplusKassa Tablesintegration section; otherwise it deletes the section and may regenerate QR codes. - "Do changes apply immediately?" Saving fires a
ReloadMenuevent; QR code regeneration runs asynchronously via background jobs.
Troubleshooting
- Can't open the In-House Settings page → A POS must be connected for the selected location; otherwise the page redirects to home.
- Table section won't save → The section name must be unique within the location and distinct from other sections in the same submission. For Custom naming each table name must be ≤ 20 characters; for Automatic naming the label is ≤ 10 characters and the number of tables must be ≥ 1.
- Cannot delete a table section → The section may be in use by QR Ordering (remove it there first), or it may be the
MplusKassa Tablesintegration section, which cannot be deleted through this form. - Default menu won't accept a menu → The menu must be eligible for in-house visibility.
- Extra menu rejected → It cannot equal the default menu, be duplicated, or have an overlapping schedule.
Examples
Tips + notes enabled, one Automatic section, one menu (PUT body)
json
{
"collect_tips": {
"enabled": true,
"options": [10, 15, 20],
"calculate_tips": "After taxes"
},
"allow_notes": {
"enabled": true,
"placeholder": "E.g. \"For Oliver\" or \"I'm allergic to mushrooms\""
},
"allow_order_notes": {
"enabled": true,
"placeholder": "Add a note for your whole order"
},
"sections": [
{
"name": "Dining Room",
"table_name_type": "Automatic Tables Names",
"table_label": "Table",
"table_numbers": 10,
"table_names": [],
"include_tables": true
}
],
"deleted_sections": [],
"default_menu_id": "menu_abc123",
"extra_menu_ids": []
}Tips disabled, Custom-named section (PUT body)
json
{
"collect_tips": {
"enabled": false
},
"allow_notes": {
"enabled": false
},
"allow_order_notes": {
"enabled": false
},
"sections": [
{
"name": "Terrace",
"table_name_type": "Custom Tables Name",
"table_names": ["T1", "T2", "Window seat"],
"include_tables": true
}
],
"deleted_sections": [],
"default_menu_id": "menu_abc123",
"extra_menu_ids": ["menu_brunch"]
}