Appearance
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_settingobject on the Location model (app/RawModels/Location.phpgetReceiptSetting()). The form always starts fromConstants::$DEFAULT_RECEIPT_SETTINGmerged 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 (
ReceiptQRCodeAppliesToenum). - 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,
ReceiptSettingServicetranslates them into every configured language viaTranslationService; 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::sendLocalOrderReceiptpassesgetCcReceiptEmails()into the mail job as$bccReceiptEmails(EmailService.php:144-150) andSendGridMailappliesaddBcc()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
ReloadMenuevent 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.)
Configure Footer QR Code
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.
Edit Custom Footer Text
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()callsReceiptService::send($transaction, includeMerchantOwner: true), which resolvesMerchant::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 namesettings-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@showPUT /back-office/settings/receipts/{locationId}->ReceiptSettingController@update
- Backend Controller:
app/Http/Controllers/Api/BackOffice/ReceiptSettingController.php(constructor-injects and delegates directly toReceiptSettingService— there is noReceiptSettingOrchestrator) - 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 onLocation.receipt_setting) - Vue Page:
src/views/settings/ReceiptsComponent.vuewith section components undersrc/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
| Property | Value |
|---|---|
| Field ID | show_order_level_discounts_on_item_level |
| Type | Toggle (boolean) |
| Required | Yes (`required |
| Default | true |
Description: When on, order-level discounts are distributed onto individual line items on the receipt.
Show Tax Summary
| Property | Value |
|---|---|
| Field ID | show_tax_summary |
| Type | Toggle (boolean) |
| Required | Yes (`required |
| Default | true (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
| Property | Value |
|---|---|
| Field ID | show_price |
| Type | Toggle (boolean) |
| Required | Yes (`required |
| Default | false |
Description: Show item prices on the receipt.
Show Address
| Property | Value |
|---|---|
| Field ID | show_address |
| Type | Toggle (boolean) |
| Required | Yes (`required |
| Default | true |
Description: Display the location's address on the receipt.
Display Contact Information
| Property | Value |
|---|---|
| Field ID | display_contact_information |
| Type | Toggle (boolean) |
| Required | Yes (`required |
| Default | true |
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
| Property | Value |
|---|---|
| Field ID | display_qr_code |
| Type | Toggle (boolean) |
| Required | Yes (`required |
| Default | true |
Description: Show a QR code in the receipt footer. When on, display_qr_code_applies_to becomes required.
QR Code Applies To
| Property | Value |
|---|---|
| Field ID | display_qr_code_applies_to |
| Type | Select (enum ReceiptQRCodeAppliesTo) |
| Options | online_ordering, custom_link |
| Required | Nullable, but required when display_qr_code is on |
| Default | online_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).
Custom Link
| Property | Value |
|---|---|
| Field ID | custom_link |
| Type | URL |
| Required | Required only when display_qr_code is on and applies-to is custom_link (`required |
| Default | null |
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).
Custom Footer Text (toggle)
| Property | Value |
|---|---|
| Field ID | custom_footer_text |
| Type | Toggle (boolean) |
| Required | Yes (`required |
| Default | true |
Description: Master toggle for the custom footer block. When on, custom_footer_title and custom_footer_long_text become required.
Custom Footer Title
| Property | Value |
|---|---|
| Field ID | custom_footer_title |
| Type | Text (stored as per-language map) |
| Required | Required when custom_footer_text is on (`required |
| Validation | UI max 35 characters (FooterSection.vue) |
| Default | null |
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.
Custom Footer Long Text
| Property | Value |
|---|---|
| Field ID | custom_footer_long_text |
| Type | Textarea (stored as per-language map) |
| Required | Required when custom_footer_text is on (`required |
| Validation | UI max 150 characters (FooterSection.vue) |
| Default | null |
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
| Property | Value |
|---|---|
| Field ID | auto_translate (object) |
| Sub-fields | auto_translate.custom_footer_title (boolean), auto_translate.custom_footer_long_text (boolean) |
| Type | Toggle per field |
| Required | Nullable |
| Default | both 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)
| Property | Value |
|---|---|
| Field ID | cc_receipt_emails (array of email) |
| Type | List of email addresses |
| Required | Nullable; each entry `required |
| Default | [] |
Description: Additional email addresses that receive a copy when a receipt is emailed.
Restaurant Name
| Property | Value |
|---|---|
| Field ID | restaurant_name |
| Type | Text |
| Required | No (`nullable |
| Default | null |
Description: Business name shown on the receipt.
Restaurant Website
| Property | Value |
|---|---|
| Field ID | restaurant_website |
| Type | Text |
| Required | No (`nullable |
| Default | null |
Description: Website shown on the receipt.
Status (system-managed)
| Property | Value |
|---|---|
| Field ID | status |
| Type | Enum ReceiptSettingStatuses (DRAFT, PUBLISHED) |
| Default | DRAFT (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:
| Field | Source |
|---|---|
contact_information_phone / contact_information_email | Location's contact information |
display_qr_code_title | Localized default phrase ("Order online too!" etc.) from ReceiptSetting::getDisplayQrCodeTitle() |
address | Location::getFullAddress() |
online_ordering_url | Location::getOnlineOrderingUrl(true) |
image_receipt_url | Branding profile receipt logo URL |
is_loyalty_subscribed | Whether loyalty is subscribed for the location |
branding_profile | The location's branding profile |
branding_profile_id | From 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):
- If a contact type/address was not passed in, it derives one: transaction customer email -> transaction customer phone -> linked customer email -> linked customer phone.
- Email ->
EmailService::sendLocalOrderReceipt()(also passes the location'scc_receipt_emails). - Phone ->
SMSService::sendReceipt().
Customer Impact
Email Receipt
- Sent to the customer's email; addresses in
cc_receipt_emailsare 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) andauto_print_receipttoggle controlling per-device delivery/printing — separate from this settings page (see Device Profiles).
Related Features
Business Rules
- Receipt settings are stored per location as a
receipt_settingobject on the Location model; each location is edited independently after selecting it on the page. - On save,
statusis always forced toPUBLISHEDby the request'sprepareForValidation(). - When
display_qr_codeis on,display_qr_code_applies_tois required; if it iscustom_link,custom_linkmust be a valid URL. - When
custom_footer_textis on, bothcustom_footer_titleandcustom_footer_long_textare required. - When
display_contact_informationis on,contact_information_phoneis required and validated againstConstants::PHONE_REGEX. - Custom footer title/long text are stored as per-language maps and auto-translated on save when their
auto_translateflag is on; translation is skipped when the value is unchanged and was previously auto-translated. - Saving fires a
ReloadMenuevent so connected devices refresh. cc_receipt_emailsonly apply to emailed receipts, and are added as BCC onsendLocalOrderReceipt(SendGridMail.php:135-137) despite thecc_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?"
ReceiptServiceemails 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
Problem: Footer text didn't translate
Causes:
- Auto-translate toggle for that field is off.
- The value was unchanged from a previously auto-translated value (translation is skipped).
Solutions:
- Enable the field's auto-translate switch and re-save.
- Change the text so it differs from the stored value.
Problem: Can't save with QR code or footer enabled
Causes:
- QR code is on but no "applies to" option selected, or custom-link selected without a valid URL.
- Custom footer is on but title or long text is empty.
- Contact information is on but no valid phone is set on the location.
Solutions:
- Choose online ordering or enter a valid custom-link URL.
- Fill in both the footer title and long text.
- 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
}
}Custom-link QR code
json
{
"display_qr_code": true,
"display_qr_code_applies_to": "custom_link",
"custom_link": "https://example.com/restaurant-y/location-x"
}