Skip to content

QR Table Ordering

Overview

QR Table Ordering allows dine-in customers to scan a QR code at their table to view the menu and place orders directly from their phone.

Key Purpose: Enable contactless table ordering via QR codes.

Purpose

This page lets you configure QR code table ordering so dine-in customers can scan, browse the menu, and place orders from their phone without waiting for staff.

Key Concepts

  • Table Section: A grouping of tables (e.g., Terrace, Bar) defined by a name (max 25 chars) and a table_name_type of either Automatic or Custom; the section's tables are stored as a list of table names, not as individual table records.
  • Table Name Type: Automatic Tables Names generates names from a table_label (max 10 chars) and a count (table_numbers); Custom Tables Name lets you enter each table name yourself (table_names, each max 20 chars).
  • Order Session: A session linking orders placed at a table; an order binds to it only when its dining option is "For Here", payment is Complete, and the order is not already Complete.
  • Custom Availability: An optional per-day schedule (custom_availability + schedule) that restricts when QR ordering is available, validated to prevent overlapping time ranges.
  • QR Code Generation: QR codes are generated asynchronously via a background job and stored in Cloudflare R2 as downloadable ZIP (image) or PDF (ordering card) files; section resources expose qr_code_zip_path and qr_code_pdf_path.
  • Kassanet Integration: When a Hendrickx or Vanhoutte POS is connected and the table section is a matching Kassanet section, table QR orders can be forwarded to the POS bill for that table automatically.

Actions

Get Started

On a location that hasn't been set up yet (first_time_setup), a "Get Started" screen is shown. Clicking Get Started opens the setup form with sections for QR Code Ordering Hours, Sections & Tables, Menus, and Checkout.

Manage Table Sections and Tables

Create table sections (e.g., "Terrace", "Bar Area"). For each section choose a Table Name Type: Automatic (set a label and number of tables) or Custom (enter each table name). Tables are stored as a list of names; there is no per-table active/inactive toggle.

Download QR Codes

Download generated QR codes for one or more table sections. Choose "Ordering Card with QR Code" (a pre-designed instruction card, PDF) or "QR Code Only" (codes for your own design, ZIP). If codes have not been generated yet, the system dispatches a generation job and returns a 400 error prompting you to retry.

Configure Ordering Settings

Set the ordering hours / custom availability, when orders are accepted relative to closing (accept_orders_until), the default and extra menus, and the checkout requirements (require_name, require_email).

Location

  • Backoffice Route: /in-house/qr-ordering
  • Backend Controller: app/Http/Controllers/Api/BackOffice/QrOrderingController.php (table sections: app/Http/Controllers/Api/BackOffice/TableSectionController.php)
  • Backoffice Page: src/pages/in-house/qr-ordering/index.vue
  • Settings Form: src/views/in-house/components/qr-ordering/QROrderingForm.vue
  • Customer App: Table QR web application (controller app/Http/Controllers/Api/TableQrOrderingController.php)

Fields

These are the QR ordering settings persisted on the location (validated by StoreQrOrderingRequest, defaulted by Constants::$DEFAULT_QR_ORDERING_SETTING). There is no master enabled toggle — the feature is gated by setup state (first_time_setup).

Sections

PropertyValue
Field IDsections
LabelSections & Tables
TypeArray of section IDs (strings)
RequiredNo (nullable)
Default[]

Description: The table sections selected for this location's QR ordering. Sections themselves are created/edited via the Table Section endpoints (see Table Section Fields below).


Custom Availability

PropertyValue
Field IDcustom_availability
LabelCustomize availability for QR Code Ordering
TypeToggle (boolean)
RequiredYes
Defaultfalse

Description: When on, QR ordering follows the schedule below instead of the location's normal business hours.


Schedule

PropertyValue
Field IDschedule
LabelOrdering Hours
TypePer-day object (schedule.{day}.is_available, schedule.{day}.times.*.from/.to as H:i)
RequiredOnly when custom_availability is on
Defaultnull

Description: Per-day availability windows. Overlapping time ranges within a day are rejected server-side.


Accept Orders Until

PropertyValue
Field IDaccept_orders_until
LabelAccept Orders Until
TypeSelect (enum AcceptOrdersUntil)
OptionsClosing Time Minus Prep Time, Closing Time
RequiredYes
DefaultClosing Time

Description: How late QR orders are accepted relative to closing.


Custom Default Menu

PropertyValue
Field IDcustom_default_menu
LabelUse a custom menu for QR ordering
TypeToggle (boolean)
RequiredNo (nullable)

Description: When on, QR ordering uses a dedicated menu instead of the location's normal menu, enabling default_menu_id and extra_menu_ids below.


Default Menu

PropertyValue
Field IDdefault_menu_id
LabelDefault Menu
TypeString (menu ID)
RequiredRequired when custom_default_menu is on
Defaultnull

Description: The primary menu shown for QR ordering. (Note: the field is default_menu_id, not menu_id.)


Extra Menus

PropertyValue
Field IDextra_menu_ids
LabelExtra Menus
TypeArray of menu IDs (strings)
RequiredNo (only relevant when custom_default_menu is on)
Default[]

Description: Additional menus offered alongside the default menu for QR ordering.


Require Name

PropertyValue
Field IDrequire_name
LabelRequire name
TypeToggle (boolean)
RequiredYes
Defaultfalse

Description: Whether a customer name is required at checkout. When off, the table name is used as the customer name.


Require Email

PropertyValue
Field IDrequire_email
LabelRequire email
TypeToggle (boolean)
RequiredYes
Defaultfalse

Description: Whether a customer email is required at checkout. When off, the location's contact email is used.


Table Section Fields

Sections and their tables are created/updated via StoreAndUpdateTableSectionRequest.

Section Name

PropertyValue
Field IDname
TypeText
RequiredYes
Validationmax: 25 characters

Table Name Type

PropertyValue
Field IDtable_name_type
TypeSelect (enum TableNameType)
OptionsAutomatic Tables Names, Custom Tables Name
RequiredYes

Table Label (Automatic only)

PropertyValue
Field IDtable_label
TypeText
RequiredNo (Automatic mode)
Validationmax: 10 characters

Description: Used to build automatic names as "{section} {label} {n}" (or "{section} {n}" when blank).


Table Numbers (Automatic only)

PropertyValue
Field IDtable_numbers
TypeInteger
RequiredYes in Automatic mode
Validationmin: 1

Description: How many tables to auto-generate.


Table Names (Custom only)

PropertyValue
Field IDtable_names
TypeArray of strings
RequiredYes in Custom mode
Validationeach name max: 20 characters

Description: The explicit list of table names. (There is no per-table qr_code or active field.)


Generated QR Paths (read-only)

PropertyValue
Field IDsqr_code_zip_path, qr_code_pdf_path
TypeString (R2 path)

Description: Paths to the generated downloadable QR files for the section, populated by the background generation job.


Business Logic

QR Ordering Flow

Customer scans QR code


Open table ordering page


Table identified from QR


Browse menu


Add items to cart


Review order


Checkout (name/email per require_name & require_email)


Pay online → Order confirmed


Order sent to KDS


Staff prepares and delivers to table

Table Session Binding

Order placed via QR at a table


Bind to table session if ALL true:
├── Dining option = "For Here"
├── Payment status = Complete
└── Order status ≠ Complete


If Kassanet section (Hendrickx/Vanhoutte):
├── POS bill total = 0  → bind to POS bill
└── POS bill total > 0  → binding rejected

Customer Impact

Customer Experience

  1. Scan: Scan QR code with phone camera
  2. Open: Link opens ordering page
  3. Browse: View menu, see item details
  4. Order: Add items, customize with modifiers
  5. Checkout: Provide name/email if required, then pay online
  6. Submit: Place order
  7. Wait: Order prepared and delivered
  8. Repeat: Scan again to order more items

Benefits

  • No waiting for waiter to take order
  • Browse menu at own pace
  • See full item descriptions and images
  • Easy reordering
  • Contactless experience

Relations

Depends On

  • Locations: QR ordering per location
  • Menus: Menu displayed
  • Payments: If payment required

Affects

  • Transactions: Orders created
  • KDS: Orders sent to kitchen
  • Reports: QR ordering analytics

Business Rules

  • Custom availability schedules are validated server-side; overlapping time ranges within a single schedule are rejected with an "invalid time range" error.
  • QR codes are stored in Cloudflare R2 storage; if the file is missing or not yet generated, the system dispatches a GenerateQrCodesForSection job and returns a 400 error asking the user to retry.
  • An order can only be bound to a table session if the order's dining option is "For Here", the payment status is "Complete", and the order status is not already "Complete".
  • When a Kassanet POS (Hendrickx/Vanhoutte) is integrated and the table section is linked to it, the system checks the POS bill total before binding; if the bill total is greater than zero, binding is rejected.
  • After updating QR ordering settings, the system automatically triggers a D1 constants update and a location update push so changes are reflected in real time.

FAQs

  • Can I use different menus for QR ordering and online ordering? Yes. Enable custom_default_menu and set a default_menu_id (plus optional extra_menu_ids); this menu is independent from the online ordering menu.

  • What happens if a customer scans a QR code for a table that no longer exists? The system returns a "Table not found" error because the table is not present in the location's active table sections lookup.

  • Are QR codes regenerated when I rename or change a section? No, QR codes are generated on demand via the background job; you need to trigger a new download/regeneration after changing table names or sections.

  • Can QR ordering work with a Hendrickx POS? Yes, when Hendrickx integration is active and the table section is linked to it, orders placed via QR are automatically forwarded to the POS for that table.

  • What file formats are available for QR code downloads? QR codes can be downloaded as either a ZIP archive of individual images or a single PDF file, selectable at download time.

  • "How do I get started with Table QR Code Ordering for the first time?" Go to In-House → Table QR Code Ordering. On a location that hasn't been set up you'll see a "Get Started" screen; click Get Started to open the setup form with QR Code Ordering Hours, Sections & Tables, Menus, and Checkout.

  • "How do I add tables? Do I have to name each one manually?" When creating a table section you choose a Table Name Type: Automatic (set a table label and a number of tables; names are generated as "{section} {label} {n}") or Custom (enter each table name yourself).

  • "What's the maximum length for a section name?" A table section name is required and limited to 25 characters. Automatic table labels are max 10 characters; custom table names are max 20.

  • "How do I restrict the hours when QR ordering is available?" In the QR Code Ordering Hours section, turn on "Customize availability for QR Code Ordering" and set per-day from/to times. If the toggle is off, QR ordering follows the location's normal availability. Overlapping time ranges in a day are rejected.

  • "What does the 'Accept Orders Until' setting do?" It controls how late QR orders are accepted relative to closing. Two options: "Closing Time Minus Prep Time" and "Closing Time".

  • "Can I show a different menu for QR ordering than my main menu?" Yes. In the Menus section you can enable a custom default menu and pick a default menu, plus optionally add extra menus, specifically for QR ordering.

  • "What information can I require from customers at checkout?" In Checkout you can toggle "Require name" and "Require email". When "Require name" is off, the table name is used as the customer name; when "Require email" is off, the location's contact email is used.

  • "How do I download the printable QR codes, and what designs are available?" Click Get QR Codes (you must Save first, or the button is disabled). Pick a design — "Ordering Card with QR Code" (a pre-designed instruction card, downloaded as PDF) or "QR Code Only" (codes for your own design, downloaded as ZIP) — then choose which sections to download.

  • "I clicked Get QR Codes but it says the files are still generating. What's happening?" QR generation runs in the background. If a section's codes aren't ready, the system starts generating them and asks you to retry in a few minutes. A progress bar shows status, and PDFs can only be generated after the QR (image) generation finishes.

  • "Why is the 'Get QR Codes' button greyed out?" You need to save your settings first. Until the location's QR codes have been generated, the button stays disabled with a tooltip telling you to click Save, then wait a few minutes.

  • "An order placed via QR isn't attaching to the right table — what conditions must be met?" An order only binds to a table session when its dining option is "For Here", its payment is Complete (paid), and the order isn't already marked Complete. Unpaid or already-completed orders are rejected.

  • "We use a Hendrickx/Vanhoutte (Kassanet) POS — will QR orders go onto the table's POS bill?" Yes, but only when the table section is a Kassanet section matching the order's POS provider. Before binding, the system checks the table's POS bill total; if that bill total is greater than zero, binding is rejected to avoid mixing with an existing open bill.

Troubleshooting

Problem: QR code not scanning

Causes:

  1. QR code damaged/dirty
  2. Poor lighting
  3. Camera issue
  4. QR code too small

Solutions:

  1. Replace QR code
  2. Improve lighting
  3. Try different phone
  4. Print larger QR code

Problem: "Table not found" error

Causes:

  1. Table/section deleted
  2. Section removed from this location's QR settings
  3. Wrong location
  4. QR code outdated

Solutions:

  1. Check the section and table still exist
  2. Re-add the section to the location's QR settings
  3. Verify location
  4. Regenerate QR code

Problem: Orders not appearing on KDS

Causes:

  1. KDS not configured
  2. Order not submitted
  3. Payment pending
  4. Network issue

Solutions:

  1. Configure KDS
  2. Verify order submitted
  3. Check payment status
  4. Check network

Problem: Order not attaching to the right table

Causes:

  1. QR code moved to a different table
  2. Order dining option is not "For Here"
  3. Payment not Complete, or order already Complete
  4. Kassanet section already has an open POS bill (total > 0)

Solutions:

  1. Ensure QR codes are fixed to their tables
  2. Confirm the order is "For Here" and paid
  3. For Kassanet sections, settle/clear the existing POS bill first
  4. Verify the table with the customer

Examples

Table Section Setup (Automatic)

json
{
  "name": "Terrace",
  "table_name_type": "Automatic Tables Names",
  "table_label": "T",
  "table_numbers": 5,
  "location_id": "loc-123"
}

This auto-generates table names: "Terrace T 1" … "Terrace T 5".

Table Section Setup (Custom)

json
{
  "name": "Bar Area",
  "table_name_type": "Custom Tables Name",
  "table_names": ["Bar 1", "Bar 2", "Window Seat"],
  "location_id": "loc-123"
}

QR Ordering Settings

json
{
  "sections": ["section-terrace", "section-bar"],
  "custom_availability": false,
  "schedule": null,
  "accept_orders_until": "Closing Time",
  "custom_default_menu": true,
  "default_menu_id": "menu-dine-in",
  "extra_menu_ids": ["menu-drinks"],
  "require_name": false,
  "require_email": false
}

QR Code URL Structure

https://table.restaurant.com/order?
  location=loc-123
  &table=t1
  &token=abc123xyz

Table Tent Design

╔═══════════════════════════════════════╗
║                                       ║
║         SCAN TO ORDER                 ║
║                                       ║
║         ┌─────────────┐               ║
║         │             │               ║
║         │   [QR CODE] │               ║
║         │             │               ║
║         └─────────────┘               ║
║                                       ║
║         TABLE 5                       ║
║                                       ║
║   1. Scan with your phone camera      ║
║   2. Browse our menu                  ║
║   3. Place your order                 ║
║   4. We'll bring it to you!           ║
║                                       ║
║         MARIO'S RESTAURANT            ║
╚═══════════════════════════════════════╝

Customer App Interface

┌─────────────────────────────────────┐
│ MARIO'S RESTAURANT          Table 5 │
├─────────────────────────────────────┤
│                                     │
│ [Starters] [Mains] [Drinks] [Desserts]
│                                     │
│ ┌─────────────────────────────────┐ │
│ │ 🍕 Margherita Pizza             │ │
│ │ Fresh mozzarella, tomato, basil │ │
│ │                          €12.50 │ │
│ │                      [Add to Cart]│
│ └─────────────────────────────────┘ │
│                                     │
│ ┌─────────────────────────────────┐ │
│ │ 🍝 Spaghetti Carbonara          │ │
│ │ Creamy pasta with pancetta      │ │
│ │                          €14.50 │ │
│ │                      [Add to Cart]│
│ └─────────────────────────────────┘ │
│                                     │
├─────────────────────────────────────┤
│ 🛒 Cart (2 items)           €27.00  │
│ [View Cart]                         │
└─────────────────────────────────────┘