Skip to content

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.vue mounted()).

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_setting on the Location model. The persisted object stores only collect_tips, allow_notes, allow_order_notes, default_menu_id, and extra_menu_ids (InHouseSettingsService::update). Table sections are stored separately as TableSection models, not inside in_house_setting.
  • Table Sections: Named groups of tables (e.g. "Dining Room", "Bar") with a table_name_type of either Automatic or Custom. Sections are created/updated/deleted as TableSection records 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 in typed-router.d.ts as in-house-settings)
  • Backoffice View: src/views/in-house/InHouseSettingsForm.vue
  • Form Components: src/views/in-house/components/forms/SectionsAndTables.vue, CollectTips.vue, CheckoutNotes.vue, and src/components/DefaultMenusSection.vue
  • Section Editor: src/views/in-house/components/settings/SectionFormDialog.vue
  • Store Module: src/store/modules/inHouse.ts (saveInHouseSettingsFormPUT /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: GET and PUT /back-office/in-house-settings/{locationId} (routes/api/backoffice/in-house-settings.php); GET requires permission view-sales-channel, PUT requires edit-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

PropertyValue
Field IDcollect_tips.enabled
LabelCollect Tips
TypeBoolean (toggle)
Defaultfalse

Description: Master switch for tip collection. When off, the percentage and calculation fields are nullable.


Collect Tips — Options

PropertyValue
Field IDcollect_tips.options (array of numbers)
LabelTip Percentage
TypeArray of numeric values
RulesRequired 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

PropertyValue
Field IDcollect_tips.calculate_tips
LabelCalculate Tips
TypeEnum (CalculateTipsOptions)
OptionsAfter taxes, Before taxes
DefaultAfter 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

PropertyValue
Field IDallow_notes.enabled
LabelAllow Notes
TypeBoolean (toggle)
Defaultfalse

Description: Whether customers can add a free-text note to items at checkout.


Allow Notes — Placeholder

PropertyValue
Field IDallow_notes.placeholder
LabelPlaceholder text
TypeString
RulesRequired when notes enabled; backend rule is string (no length limit); back-office editor caps at 150 characters
DefaultE.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

PropertyValue
Field IDallow_order_notes.enabled
LabelAllow Order Notes
TypeBoolean (toggle)
Defaultfalse

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_notes after launch. StoreInHouseSettingsRequest merges allow_notes into allow_order_notes as a fallback, so a tenant saved before the split — which sends only allow_notes — keeps the old combined behaviour until the merchant configures the split explicitly (StoreInHouseSettingsRequest.php:36-45).


Allow Order Notes — Placeholder

PropertyValue
Field IDallow_order_notes.placeholder
LabelPlaceholder text
TypeString
RulesRequired when order notes enabled; backend rule is string (no length limit); back-office editor caps at 150 characters
DefaultAdd a note for your whole order

Description: The placeholder shown in the order-level note field (Constants::getDefaultInHouseSettings(), Constants.php:252-254).


Default Menu

PropertyValue
Field IDdefault_menu_id
LabelDefault Menu
TypeString (menu id)
Rules`required
Defaultnull (until set)

Description: The menu shown for in-house ordering. Must be an eligible menu (InHouseSettingsService::update calls isMenuEligible).


Extra Menus

PropertyValue
Field IDextra_menu_ids (array of strings)
LabelExtra Menus
TypeArray 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)

PropertyValue
Field IDsections (array)
TypeArray 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

PropertyValue
Field IDsections.*.name
LabelSection Name
TypeString
Rulesrequired, 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)

PropertyValue
Field IDsections.*.table_name_type
LabelNaming
TypeEnum (TableNameType)
OptionsAutomatic 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 a table_label (optional, max 10 chars) and table_numbers (required integer, min:1); the backend generates names like {section} {label} {n} (or {section} {n} when no label).
  • Custom (Custom Tables Name): enter each table name in table_names (required array; each string, max:20); table_numbers is set to the count of names.

Include Tables

PropertyValue
Field IDsections.*.include_tables
TypeBoolean (nullable)
Defaultfalse (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):

  1. Loads existing table sections and partitions out the MplusKassa Tables integration section.
  2. Processes deleted_sections, skipping the MplusKassa integration section, and aborts with HTTP 400 if a section is still in use by QR Ordering.
  3. Creates/updates submitted sections (skipping the MplusKassa Tables section), generating table names for Automatic sections.
  4. Persists collect_tips, allow_notes, allow_order_notes, default_menu_id, and extra_menu_ids to in_house_setting (InHouseSettingsService::update) and fires a ReloadMenu event.
  5. Dispatches GenerateQrCodesForSection for 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).

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 Tables section (exact name) is protected: it is skipped from UI section updates and cannot be deleted through this form.
  • Saving fires a ReloadMenu event and may dispatch GenerateQrCodesForSection jobs 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, and extra_menu_ids. Table sections are stored separately as TableSection models. It does not store service_mode, prep_time, auto_accept, print_kitchen_ticket, etc.
  • "Why is order_capacity in 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 Tables integration section; otherwise it deletes the section and may regenerate QR codes.
  • "Do changes apply immediately?" Saving fires a ReloadMenu event; 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 Tables integration 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"]
}