Appearance
Table Sections
Overview
Table sections organize a location's tables into named groups (e.g. "Dining Room", "Bar", "Terrace") used for Table QR ordering and in-house management.
Key Purpose: Group a location's tables into named sections, each generating downloadable QR codes for table-based QR ordering.
Purpose
This page lets you define the areas of a venue as named sections and, optionally, the tables within each section. Each section can generate QR codes (an image ZIP and an ordering-card PDF) for table-based QR ordering.
Key Concepts
- Table Section: A named group belonging to a single location, stored in the tenant
settingscollection (modelTableSection) with soft-delete support. A section holds aname, atable_name_type, and a list of table names — not individual table records. - Table Name Type: An enum (
TableNameType) with two values:Automatic Tables NamesandCustom Tables Name. Automatic generates names from a label plus a count; Custom takes an explicit list of names. - Tables as names only: A section's tables are stored as a flat array of name strings (
table_names). There are no per-tableseats,table_number,qr_code, or active/inactive fields. - Include Tables: A per-section toggle (
include_tables). When off, the section has no tables (the section can still exist as an area). When on, tables are defined per the naming type. - QR Code Generation: QR files are generated asynchronously via the
GenerateQrCodesForSectionjob and stored in Cloudflare R2; the section exposes read-only pathsqr_code_zip_path(image ZIP) andqr_code_pdf_path(ordering-card PDF). - MplusKassa Tables section: The auto-created section named exactly
MplusKassa Tablesis protected — it is skipped from deletion and from UI updates when saving in-house settings. - Lightspeed K-Series sections are flagged read-only:
TableSection::getUneditableFields()returns['name', 'tableNameType', 'tableLabel', 'tableNumbers', 'tableNames', 'details']for any section carryingexternal_ids.lightspeedand for any manual section at a Lightspeed K-Series-mapped location (external_data.lightspeed_locked). This is a wider lock than the MplusKassa one: at a K-Series location it covers sections the merchant created themselves, not just imported ones. Sections come back with thoseuneditable_fieldsso the UI can disable the inputs.
Actions
Create a Table Section
In In-House Settings, open the section form ("Add Section"). Enter a Section Name (required, must be unique within the location). Optionally toggle Include tables on, choose a Naming type (Automatic or Custom), and configure the tables.
Edit a Table Section
Open an existing section ("Edit Section") and change its name, naming type, or tables. When table names change on save (or QR files are missing), a GenerateQrCodesForSection job is dispatched to regenerate the QR files.
Delete a Table Section
Sections can be deleted from the section form ("Delete Section") or, via the in-house settings save, by listing the section ID in deleted_sections. Deletion is blocked when the section is in use by QR Ordering. The MplusKassa Tables section is never deleted through the in-house settings flow.
Download QR Codes
QR codes are downloaded from the QR Ordering screen, not from the section form. See QR Ordering for the download flow and formats.
Location
- Backoffice Route:
/in-house/settings(In-House Settings -> Sections & Tables) — this is where sections are created, edited and deleted (InHouseSettingsForm.vue->SectionsAndTables.vue->SectionFormDialog.vue, with deletions pushed intodeleted_sections)./in-house/qr-orderingonly selects already-existing sections (SectionsAndTablesSelected.vue); it cannot create or edit them. - Section Form Component:
src/views/in-house/components/settings/SectionFormDialog.vue - Standalone Backend: controller
app/Http/Controllers/Api/BackOffice/TableSectionController.php, requestapp/Http/Requests/BackOffice/TableSection/StoreAndUpdateTableSectionRequest.php - In-House Settings Flow: request
app/Http/Requests/BackOffice/InHouseSettings/StoreInHouseSettingsRequest.php, orchestratorapp/Services/Orchestrators/BackOffice/InHouseSettingsOrchestrator.php
Fields
Section Name
| Property | Value |
|---|---|
| Field ID | name |
| Label | Section Name |
| Type | Text |
| Required | Yes |
| Validation | unique within the location; required. The 25-character cap is enforced only by the standalone /back-office/table-sections API (max:25) — the in-house-settings save path used by this form has no max rule, and the field shows an "x/25" counter without blocking |
Description: Name of the area (placeholder "e.g. Dining Room, Bar"). Uniqueness within the location is enforced server-side (UniqueInConnectionWithModel in the in-house settings flow; max:25 in the standalone request).
Include Tables
| Property | Value |
|---|---|
| Field ID | include_tables |
| Label | Include tables |
| Type | Toggle (boolean) |
| Default | false (section form) |
Description: When off, the section has no tables and table fields are cleared on save. When on, tables are configured per the naming type below.
Table Name Type
| Property | Value |
|---|---|
| Field ID | table_name_type (frontend form field: table_naming_type) |
| Label | Naming |
| Type | Select (enum TableNameType) |
| Options | Automatic Tables Names, Custom Tables Name |
| Required | Yes |
Description: How the section's tables are named. The UI radio labels read "Automatic Table Names" and "Custom Table Names"; the stored/enum values are Automatic Tables Names and Custom Tables Name.
Table Label (Automatic only)
| Property | Value |
|---|---|
| Field ID | table_label |
| Label | Label |
| Type | Text |
| Required | No |
| Validation | max 10 characters (Automatic mode) |
Description: Optional prefix used to build automatic names (placeholder "e.g. Table"). Names become "{section} {label} {n}", or "{section} {n}" when blank.
Number of Tables (Automatic only)
| Property | Value |
|---|---|
| Field ID | table_numbers |
| Label | Number of Tables |
| Type | Integer |
| Required | Yes in Automatic mode |
| Validation | min 1 (Automatic mode); generally nullable|integer|min:0 |
Description: How many tables to auto-generate. In Custom mode this is set to the count of provided names.
Table Names (Custom only)
| Property | Value |
|---|---|
| Field ID | table_names (frontend form field: tables, an array of { name }) |
| Label | Tables |
| Type | Array of strings |
| Required | Yes in Custom mode |
| Validation | each name required, max 20 characters (Custom mode) |
Description: The explicit list of table names. There is no per-table seats, table_number, qr_code, or active field — tables are plain name strings.
Generated QR Paths (read-only)
| Property | Value |
|---|---|
| Field IDs | qr_code_zip_path, qr_code_pdf_path |
| Type | String (R2 path) |
Description: Paths to the generated downloadable QR files for the section, populated by the background generation job.
Business Logic
Section Organization
Location
├── Section: Dining Room (Automatic, label "Table", 4 tables)
│ ├── Dining Room Table 1
│ ├── Dining Room Table 2
│ ├── Dining Room Table 3
│ └── Dining Room Table 4
│
├── Section: Terrace (Automatic, no label, 3 tables)
│ ├── Terrace 1
│ ├── Terrace 2
│ └── Terrace 3
│
└── Section: Bar (Custom)
├── Bar 1
├── Bar 2
└── Window SeatSave & QR Regeneration Flow
Save in-house settings (sections + deleted_sections)
│
▼
Skip the "MplusKassa Tables" section (delete + update)
│
▼
For each deleted_section id (non-MplusKassa):
├── In use by QR Ordering? → abort 400
└── otherwise → delete section
│
▼
For each section:
├── include_tables off / no tables → clear table fields
├── Automatic → build table_names from label + count
└── Custom → table_numbers = count(table_names)
│
▼
If table_names changed or QR files missing
│
▼
Dispatch GenerateQrCodesForSection (ZIP + PDF → R2)Business Rules
- Section names are required and must be unique within the location. The 25-character limit is not enforced on the path the back office actually uses:
StoreInHouseSettingsRequestvalidatessections.{i}.nameas onlyrequired|stringplus a uniqueness and adistinctrule, with nomax. The counter in the UI is cosmetic. Only the standalone/back-office/table-sectionsAPI appliesmax:25. - A section needs the Include tables toggle on to define tables. With it off (or with zero tables), the table fields are cleared on save.
- For Automatic naming,
table_numbers(min 1) is required andtable_labelis optional (max 10 chars). For Custom naming,table_namesis required and each name must be a non-empty string of at most 20 characters. - Automatic names are generated as
"{section} {label} {n}"(or"{section} {n}"when the label is blank). - A section in use by QR Ordering cannot be deleted via the in-house settings flow (returns a 400 prompting you to remove it from QR Ordering first).
- The section named exactly
MplusKassa Tablesis protected: it is skipped from both deletion and UI updates in the in-house settings flow. - QR files (image ZIP + ordering-card PDF) are regenerated by the
GenerateQrCodesForSectionjob when a section's table names change or its R2 paths are missing.
FAQs
- "Do tables have seat counts or table numbers as separate fields?" No. A section's tables are stored only as a list of name strings (
table_names). There are noseats,table_number, or per-tableqr_codefields. - "How are table names generated in Automatic mode?" As
"{section} {label} {n}"(e.g. "Dining Room Table 1"). If no label is set, names are"{section} {n}"(e.g. "Dining Room 1"). - "What's the difference between Automatic and Custom naming?" Automatic generates a numbered set from a label and a count; Custom lets you type each table name (each up to 20 characters).
- "What is the 'Include tables' toggle for?" It controls whether the section has tables at all. A section can exist as an area with no tables when the toggle is off.
- "Why can't I delete a section?" It is in use by QR Ordering (remove it there first), or it is the protected
MplusKassa Tablessection, which is managed by the MplusKassa integration and skipped from UI deletion. - "What happens to QR codes when I change table names?" A background job (
GenerateQrCodesForSection) regenerates the section's image ZIP and ordering-card PDF; this is asynchronous, so allow a short time before downloading.
Troubleshooting
- Section not saving → Verify the name is unique within the location (the 25-character counter does not block saving through In-House Settings). In Custom mode each table name must be filled in and 20 characters or fewer; in Automatic mode the number of tables must be at least 1.
- Cannot delete a section → The section is in use by QR Ordering (remove it there first), or it is the protected
MplusKassa Tablessection. - QR codes not generating → Generation runs as a background job (
GenerateQrCodesForSection). Ensure the queue worker is running and allow a few minutes after the table names change. (QR file generation is verified server-side; storefront QR rendering is not verified here.) - Table names not updating on QR codes → QR files regenerate only when the section's table names change or its R2 paths are missing. Confirm the save succeeded and check for background-job failures.
Relations
Depends On
- Locations: Sections belong to one location
- QR Ordering: Sections are selected for a location's QR ordering
Affects
- QR Ordering: Table QR codes and table identification
- Transactions: Orders bind to a table session (see QR Ordering)
Related Features
Examples
Section Resource (API response)
json
{
"id": "section-1",
"location_id": "loc-123",
"name": "Dining Room",
"details": {},
"table_name_type": "Automatic Tables Names",
"table_label": "Table",
"table_numbers": 4,
"table_names": [
"Dining Room Table 1",
"Dining Room Table 2",
"Dining Room Table 3",
"Dining Room Table 4"
],
"qr_code_zip_path": "...",
"qr_code_pdf_path": "..."
}Automatic Section (request payload)
json
{
"name": "Terrace",
"table_name_type": "Automatic Tables Names",
"table_label": "T",
"table_numbers": 3,
"location_id": "loc-123"
}This auto-generates table names "Terrace T 1", "Terrace T 2", "Terrace T 3".
Custom Section (request payload)
json
{
"name": "Bar",
"table_name_type": "Custom Tables Name",
"table_names": ["Bar 1", "Bar 2", "Window Seat"],
"location_id": "loc-123"
}