Skip to content

Receipts

Overview

Receipt settings control what appears on customer receipts and how the receipt footer is customized. You pick a location, then toggle item/total display options, fill in business contact details, configure a footer QR code, write custom footer text, and add BCC email addresses that get a copy of emailed receipts.

Key Purpose: Customize receipt content (item/total options, business contact, footer QR code, footer text) per location, and CC additional emails on receipt mails.

Purpose

This page lets you customize the receipt for a selected location. It is a per-location settings area, not a per-receipt-type editor. The settings persist on the Location model under a receipt_setting object and are applied when receipts are generated and sent.

Key Concepts

  • Per-location setting: All receipt options are stored as a receipt_setting object on the Location model (app/RawModels/Location.php getReceiptSetting()). The form always starts from Constants::$DEFAULT_RECEIPT_SETTING merged with the location's saved values.
  • Location selector: The page requires a location to be selected first; it loads/saves settings for that one location (ReceiptsComponent.vue).
  • Footer QR code: A QR code can be placed in the receipt footer pointing either at the location's online-ordering page or a custom link (ReceiptQRCodeAppliesTo enum).
  • Custom footer text: An optional footer title + long text, each stored as a per-language map and auto-translated when enabled.
  • Auto-translation: When custom footer fields change and auto-translate is on for that field, ReceiptSettingService translates them into every configured language via TranslationService; if the value is unchanged and was previously auto-translated, translation is skipped (app/Services/BackOffice/Settings/ReceiptSettingService.php).
  • BCC receipt emails: A list of extra email addresses that receive a copy whenever a receipt is emailed. The stored key is cc_receipt_emails, but delivery is BCC, not CC — EmailService::sendLocalOrderReceipt passes getCcReceiptEmails() into the mail job as $bccReceiptEmails (EmailService.php:144-150) and SendGridMail applies addBcc() per address (SendGridMail.php:135-137), so these recipients are not visible to the customer. The back office labels the section BCC Receipt Emails.
  • Receipt delivery: ReceiptService::send() emails the receipt to the customer's email if present, otherwise SMS to the customer's phone; if neither exists on the transaction it falls back to the linked customer record (email, then phone).
  • Menu reload: Saving receipt settings fires a ReloadMenu event so connected devices pick up the change.

Actions

Select Location

Choose which location's receipt settings to edit. Settings are loaded and saved per location.

Edit Item & Total Options

Toggle whether order-level discounts are shown at item level, and whether item prices are shown.

Edit Business Contact

Set the restaurant name and website shown on the receipt, and toggle whether the address and contact information are displayed. (The phone/email values themselves come from the location's contact information and are read-only here.)

Turn the footer QR code on/off, choose whether it links to online ordering or a custom link, and (for custom link) enter the URL.

Turn custom footer text on/off, and set a footer title (max 35 chars) and long text (max 150 chars), each with its own auto-translate toggle.

Manage BCC Emails

Add or remove email addresses that receive a blind copy of emailed receipts (back office: BCC Receipt Emails).

Resend a Receipt

From the Transactions area, a completed transaction's receipt can be resent. This re-sends to the original customer contact via ReceiptService::send(); it is not configured on this settings page. See Transactions.

A back-office resend also emails a copy to the merchant's vendor-owner. TransactionService::resendReceipt() calls ReceiptService::send($transaction, includeMerchantOwner: true), which resolves Merchant::getOwnerContact()['email'] independently of the customer contact — so a guest order with no customer email still reaches the owner. This owner copy is unique to resend; kiosk and online-ordering receipts do not send it.

Location

  • Backoffice Route: /settings/receipts (route name settings-receipts; src/plugins/1.router/additional-routes.ts)
  • Backend Routes (routes/api/backoffice/settings/receipts.php, mounted under /back-office/settings):
    • GET /back-office/settings/receipts/{locationId} -> ReceiptSettingController@show
    • PUT /back-office/settings/receipts/{locationId} -> ReceiptSettingController@update
  • Backend Controller: app/Http/Controllers/Api/BackOffice/ReceiptSettingController.php (constructor-injects and delegates directly to ReceiptSettingService — there is no ReceiptSettingOrchestrator)
  • Backend Service: app/Services/BackOffice/Settings/ReceiptSettingService.php
  • Backend Request: app/Http/Requests/BackOffice/Settings/Payment/StoreReceiptSettingRequest.php
  • Backend Resource: app/Http/Resources/BackOffice/Settings/Payments/ShowReceiptSettingResource.php
  • Backend Model: App\RawModels\SubModels\ReceiptSetting (stored on Location.receipt_setting)
  • Vue Page: src/views/settings/ReceiptsComponent.vue with section components under src/views/settings/Receipts/ (ItemsTotalSection.vue, BusinessContactSection.vue, FooterSection.vue, CCEmailSection.vue, ReceiptPreview.vue)
  • Frontend store: src/store/modules/receipt.ts

Fields

Field IDs below are the keys validated by StoreReceiptSettingRequest and stored in receipt_setting.

Show Order-Level Discounts on Item Level

PropertyValue
Field IDshow_order_level_discounts_on_item_level
TypeToggle (boolean)
RequiredYes (`required
Defaulttrue

Description: When on, order-level discounts are distributed onto individual line items on the receipt.


Show Tax Summary

PropertyValue
Field IDshow_tax_summary
TypeToggle (boolean)
RequiredYes (`required
Defaulttrue (Constants)

Description: Show a tax summary block. Validated and stored, but the UI toggle for it is currently commented out in ItemsTotalSection.vue (the frontend default state sets it to false).


Show Price

PropertyValue
Field IDshow_price
TypeToggle (boolean)
RequiredYes (`required
Defaultfalse

Description: Show item prices on the receipt.


Show Address

PropertyValue
Field IDshow_address
TypeToggle (boolean)
RequiredYes (`required
Defaulttrue

Description: Display the location's address on the receipt.


Display Contact Information

PropertyValue
Field IDdisplay_contact_information
TypeToggle (boolean)
RequiredYes (`required
Defaulttrue

Description: Display contact info (phone/email) on the receipt. When on, contact_information_phone is required and validated against Constants::PHONE_REGEX. The phone/email values come from the location's contact information (returned read-only as contact_information_phone / contact_information_email).


Display QR Code

PropertyValue
Field IDdisplay_qr_code
TypeToggle (boolean)
RequiredYes (`required
Defaulttrue

Description: Show a QR code in the receipt footer. When on, display_qr_code_applies_to becomes required.


QR Code Applies To

PropertyValue
Field IDdisplay_qr_code_applies_to
TypeSelect (enum ReceiptQRCodeAppliesTo)
Optionsonline_ordering, custom_link
RequiredNullable, but required when display_qr_code is on
Defaultonline_ordering

Description: Whether the footer QR code points at the location's online-ordering page or a custom link. Enum: App\Enums\ReceiptQRCodeAppliesTo = ONLINE_ORDERING (online_ordering), CUSTOM_LINK (custom_link).


PropertyValue
Field IDcustom_link
TypeURL
RequiredRequired only when display_qr_code is on and applies-to is custom_link (`required
Defaultnull

Description: The URL encoded into the footer QR code when "custom link" is selected. UI input is capped at 150 chars (maxlength="150" in FooterSection.vue).


PropertyValue
Field IDcustom_footer_text
TypeToggle (boolean)
RequiredYes (`required
Defaulttrue

Description: Master toggle for the custom footer block. When on, custom_footer_title and custom_footer_long_text become required.


PropertyValue
Field IDcustom_footer_title
TypeText (stored as per-language map)
RequiredRequired when custom_footer_text is on (`required
ValidationUI max 35 characters (FooterSection.vue)
Defaultnull

Description: Footer title. Stored internally as a map of language -> string; the show resource returns the value for the current locale. Auto-translated when auto_translate.custom_footer_title is on.


PropertyValue
Field IDcustom_footer_long_text
TypeTextarea (stored as per-language map)
RequiredRequired when custom_footer_text is on (`required
ValidationUI max 150 characters (FooterSection.vue)
Defaultnull

Description: Footer body text. Stored as a per-language map; returned for the current locale. Auto-translated when auto_translate.custom_footer_long_text is on.


Auto-Translate

PropertyValue
Field IDauto_translate (object)
Sub-fieldsauto_translate.custom_footer_title (boolean), auto_translate.custom_footer_long_text (boolean)
TypeToggle per field
RequiredNullable
Defaultboth true

Description: Per-field switches controlling whether footer title / long text are auto-translated into all configured languages on save.


BCC Receipt Emails (cc_receipt_emails)

PropertyValue
Field IDcc_receipt_emails (array of email)
TypeList of email addresses
RequiredNullable; each entry `required
Default[]

Description: Additional email addresses that receive a copy when a receipt is emailed.


Restaurant Name

PropertyValue
Field IDrestaurant_name
TypeText
RequiredNo (`nullable
Defaultnull

Description: Business name shown on the receipt.


Restaurant Website

PropertyValue
Field IDrestaurant_website
TypeText
RequiredNo (`nullable
Defaultnull

Description: Website shown on the receipt.


Status (system-managed)

PropertyValue
Field IDstatus
TypeEnum ReceiptSettingStatuses (DRAFT, PUBLISHED)
DefaultDRAFT (Constants) / forced to PUBLISHED on save

Description: Set automatically. StoreReceiptSettingRequest::prepareForValidation() always merges status = PUBLISHED on update; it is not a user-facing field.


Read-only fields returned by the show endpoint

These are returned by ShowReceiptSettingResource for display/preview but are not editable receipt settings:

FieldSource
contact_information_phone / contact_information_emailLocation's contact information
display_qr_code_titleLocalized default phrase ("Order online too!" etc.) from ReceiptSetting::getDisplayQrCodeTitle()
addressLocation::getFullAddress()
online_ordering_urlLocation::getOnlineOrderingUrl(true)
image_receipt_urlBranding profile receipt logo URL
is_loyalty_subscribedWhether loyalty is subscribed for the location
branding_profileThe location's branding profile
branding_profile_idFrom DEFAULT_RECEIPT_SETTING / stored value

Business Logic

Save flow

PUT /back-office/settings/receipts/{locationId}


StoreReceiptSettingRequest (validates; forces status = PUBLISHED)


ReceiptSettingController@update -> ReceiptSettingService::update()

        ├── genReceiptSetting(): for custom footer keys, auto-translate
        │   into all configured languages (unless field's auto_translate is off
        │   or value unchanged + was previously auto-translated)
        ├── LocationRepository::save(receipt_setting)
        └── event(new ReloadMenu(locationId))

Receipt sending (delivery)

ReceiptService::send($transaction) (app/Services/Common/ReceiptService.php):

  1. If a contact type/address was not passed in, it derives one: transaction customer email -> transaction customer phone -> linked customer email -> linked customer phone.
  2. Email -> EmailService::sendLocalOrderReceipt() (also passes the location's cc_receipt_emails).
  3. Phone -> SMSService::sendReceipt().

Customer Impact

Email Receipt

  • Sent to the customer's email; addresses in cc_receipt_emails are blind-copied (BCC).
  • Footer can include the QR code (online-ordering or custom link) and custom footer text.

SMS Receipt

  • Sent to the customer's phone when no email is available.

Note: The exact rendered layout of the printed/emailed receipt (logo placement, fonts, paper width, kitchen tickets, etc.) is produced by mail templates / device/printer firmware and is not verified here — those renderers live outside these two repositories. There is no paper-width, font-size, kitchen-ticket, or delivery-receipt configuration in the receipt settings code.


Relations

Depends On

  • Locations: Receipt settings are stored on the Location; address and contact info come from the location.
  • Branding: Receipt logo (image_receipt_url) and branding profile come from branding.
  • Languages: Footer text auto-translation uses the configured languages.

Affects

  • Transactions: Receipts are generated/sent for completed transactions; a receipt can be resent from a transaction.
  • Devices / Device Profiles: Device profiles have their own receipt_options (print / email / phone) and auto_print_receipt toggle controlling per-device delivery/printing — separate from this settings page (see Device Profiles).

Business Rules

  • Receipt settings are stored per location as a receipt_setting object on the Location model; each location is edited independently after selecting it on the page.
  • On save, status is always forced to PUBLISHED by the request's prepareForValidation().
  • When display_qr_code is on, display_qr_code_applies_to is required; if it is custom_link, custom_link must be a valid URL.
  • When custom_footer_text is on, both custom_footer_title and custom_footer_long_text are required.
  • When display_contact_information is on, contact_information_phone is required and validated against Constants::PHONE_REGEX.
  • Custom footer title/long text are stored as per-language maps and auto-translated on save when their auto_translate flag is on; translation is skipped when the value is unchanged and was previously auto-translated.
  • Saving fires a ReloadMenu event so connected devices refresh.
  • cc_receipt_emails only apply to emailed receipts, and are added as BCC on sendLocalOrderReceipt (SendGridMail.php:135-137) despite the cc_ key name.
  • Receipt delivery channel is chosen automatically: customer email first, then customer phone, then the linked customer record (email, then phone).

FAQs

  • "Can I have different receipt settings per location?" Yes. Settings are stored on each location, and the page edits one selected location at a time.
  • "Are the footer title and message translated automatically?" Yes, when the auto-translate toggle for that field is on, the system translates it into all configured languages on save via TranslationService. Unchanged previously-auto-translated values are not re-translated.
  • "What does the footer QR code link to?" Either the location's online-ordering page (online_ordering) or a custom URL you enter (custom_link).
  • "How are receipts sent to customers?" ReceiptService emails the receipt if a customer email is available, otherwise sends an SMS to the phone; if neither is on the transaction it falls back to the linked customer record (email, then phone).
  • "Can I copy someone on receipts?" Yes — add addresses under BCC Receipt Emails. They are blind-copied on emailed receipts only, so the customer does not see them.
  • "Can I set paper width, font size, or kitchen-ticket layout here?" No. The receipt settings page has no print-format options. Per-device print/email behavior (and auto-print) lives in Device Profiles; the printed layout itself is handled outside these repositories.
  • "Can I resend a receipt?" Yes, from a completed transaction in the Transactions area. It re-sends to the original customer contact and emails a copy to the merchant's vendor-owner. It is not on this settings page.

Troubleshooting

Causes:

  1. Auto-translate toggle for that field is off.
  2. The value was unchanged from a previously auto-translated value (translation is skipped).

Solutions:

  1. Enable the field's auto-translate switch and re-save.
  2. Change the text so it differs from the stored value.

Causes:

  1. QR code is on but no "applies to" option selected, or custom-link selected without a valid URL.
  2. Custom footer is on but title or long text is empty.
  3. Contact information is on but no valid phone is set on the location.

Solutions:

  1. Choose online ordering or enter a valid custom-link URL.
  2. Fill in both the footer title and long text.
  3. Ensure the location has a valid contact phone.

Examples

Receipt settings payload (PUT)

json
{
  "show_order_level_discounts_on_item_level": true,
  "show_tax_summary": true,
  "show_price": false,
  "show_address": true,
  "display_contact_information": true,
  "contact_information_phone": "+31201234567",
  "display_qr_code": true,
  "display_qr_code_applies_to": "online_ordering",
  "custom_footer_text": true,
  "custom_footer_title": "Thank you!",
  "custom_footer_long_text": "We hope to see you again soon.",
  "cc_receipt_emails": ["owner@example.com"],
  "restaurant_name": "Mario's Restaurant",
  "restaurant_website": "www.marios.example",
  "auto_translate": {
    "custom_footer_title": true,
    "custom_footer_long_text": true
  }
}
json
{
  "display_qr_code": true,
  "display_qr_code_applies_to": "custom_link",
  "custom_link": "https://example.com/restaurant-y/location-x"
}