Introduction
If you use Shopify POS Pro, you can customise two printed receipts: your sales receipt and a gift receipt. POS Cafe provides prebuilt receipt code that turns one of these into a clean Order Ticket for your barista/kitchen.
Our Order Ticket code will:
- Print only products created via POS Cafe (or optionally print all products)
- Group items by Prep Area so you can cut/torn sections for different stations
Setting up Order Tickets
Step 1
In your Shopify admin, go to Sales channels » Point of Sale » Settings.
Step 2
Choose Receipts.
Step 3
Select Customize your receipts.
Step 4
Click Edit code.
Step 5
In the code editor, update the four files highlighted below. Open each file, select all, and paste in the matching snippet from the Code Snippets section.
Step 6
Click Save. Use Preview options to test different order examples, then print a test order from your POS to verify layout at your printer width.
Code Snippets
Which option should I choose?
- Sales receipt as Order Ticket — the default sales receipt in Shopify will print the formatted order ticket (this is the receipt that can be set to autoprint after every order); the gift receipt prints your normal sales receipt;
- Gift receipt as Order Ticket — Your sales receipt remains the normal customer receipt; your cashier will need to tap the gift receipt button to print the formatted order ticket.
Select the accordion that matches your choice, then copy each snippet into the corresponding file.
Use this option if you would like your sales receipt to print as an order ticket, and your gift receipt to print as your sales receipt.
{% comment %}
POS Cafe - Receipts 4.1
Receipts/sales-receipt.liquid
Order ticket header section.
It is your responsibility to ensure that the printed receipts comply with all the applicable laws.
{% endcomment %}
{% assign location_id = location.id | append: "" %}
{% assign display_total_header_1 = "76500435181" | split: "," %}
{% # Default value %}
{% assign display_total_header = true %}
{% # Location overrides %}
{% if display_total_header_1 contains location_id %}
{% assign display_total_header = true %}
{% endif %}
{% # Display order note %}
{% assign display_order_note = true %}
{% # End of the settings definition %}
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
<meta
name='viewport'
content='user-scalable=no'
>
<style>
:root {
--font-smallest: 0.6875rem;
--font-small: 0.875rem;
--font-medium: 1rem;
--font-large: 1.5rem;
--font-largest: 3rem;
--font-family: system-ui;
}
* {
box-sizing: border-box;
}
body {
margin: 2rem 1rem 2.5rem 1rem;
font-family: var(--font-family);
font-weight: 400;
font-size: var(--font-large);
background: white;
}
p {
margin: 0;
}
.receipt-box {
border-color: black;
border-radius: 0.7rem;
border: 0.3rem solid;
margin: 2.5rem 0.3125rem;
padding: 1.75rem 1.25rem;
text-align: center;
font-weight: bold;
font-size: var(--font-large);
}
.receipt-box .channel-label {
font-weight: bold;
font-size: var(--font-large);
}
.note {
padding-top: 1.35rem;
border-top: 0.25rem dotted black;
font-size: var(--font-large);
}
.note-title {
font-weight: bold;
padding-bottom: 0.3125rem;
font-size: var(--font-large);
}
</style>
</head>
<body>
{% render 'line-items' %}
{% if display_order_note %}
{% if order.note != nil and order.note != blank %}
<section class='note'>
<p class='note-title'>{{ 'receipt.order_note' | t }}</p>
<p>{{ order.note | escape }}</p>
</section>
{% endif %}
{% endif %}
</body>
</html>
{% comment %}
POS Cafe - Receipts 4.1
Sections/line-items.liquid
Order ticket line items section.
It is your responsibility to ensure that the printed receipts comply with all the applicable laws.
{% endcomment %}
<style>
.variant-name,
.line-item-quantity,
.line-item-group { font-size: var(--font-large); }
.line-items-header {
width: 100%;
border-bottom: 0.3rem solid black;
display: flex;
justify-content: space-between;
padding: 0 0.3125rem;
}
.line-item-row { padding: 1.35rem 0; display: flex; justify-content: space-between; }
.line-item-row-bottom-border { border-bottom: 0.25rem dotted black; }
.line-item-title, .line-item-quantity { padding: 0 0.3125rem; }
.line-item-title .product-name,
.line-item-quantity,
.line-items-header { font-size: 3rem; }
.line-item-title .prep-area,
.line-item-quantity,
.line-items-header {
font-size: 3rem;
font-weight:bold;
text-align:center;
margin-bottom:0.5rem;
}
.dine-option {
font-size: 2rem;
font-weight: 700;
text-transform: uppercase;
margin-top: 0.25rem;
}
li { font-size: 2rem; }
hr.cut-here { border-top: 10px dashed black; }
</style>
<div>
<section>
{% # Set variables %}
{% assign poscafe = "POS Cafe" %}
{% assign poscafe_norm = poscafe | downcase %}
{% assign unique_prep_areas = '' %}
{% assign has_order_name = false %}
{% assign order_name = '' %}
{% assign has_channel = false %}
{% assign channel = "Online" %}
{% assign show_channel = false %} {% # toggle: show/hide the channel line in header %}
{% comment %} Toggle: include non–POS Cafe items in the “no prep area” section {% endcomment %}
{% assign show_non_poscafe_items = false %}
{% comment %} Keys to hide from attributes (normalized: downcase + spaces->underscores) {% endcomment %}
{% assign hidden_keys = 'item_type,modifier_variants,_modifiervariants,prep_area,channel,service_type' | split: ',' %}
{% assign modifier_keys = 'item_type,itemtype' | split: ',' %}
{% comment %} First pass: capture order name/channel, and collect unique prep areas for POS Cafe items (never include modifiers) {% endcomment %}
{% for line_item in order.line_items %}
{% assign item_type_norm = '' %}
{% assign any_poscafe_value = false %}
{% assign is_modifier = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if key_norm == 'item_type' %}{% assign item_type_norm = val_norm %}{% endif %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}{% assign is_modifier = true %}{% endif %}
{% if val_norm == poscafe_norm %}{% assign any_poscafe_value = true %}{% endif %}
{% endfor %}
{% assign is_cafe_item = false %}
{% if item_type_norm == poscafe_norm or any_poscafe_value %}{% assign is_cafe_item = true %}{% endif %}
{% if has_order_name == false %}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'name' %}
{% assign has_order_name = true %}
{% assign order_name = attribute[1] | strip_newlines | strip %}
{% break %}
{% endif %}
{% endfor %}
{% endif %}
{% if has_channel == false %}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'channel' %}
{% assign has_channel = true %}
{% assign channel = attribute[1] | strip_newlines | strip %}
{% break %}
{% endif %}
{% endfor %}
{% endif %}
{% if is_cafe_item and is_modifier == false %}
{%- capture item_prep_area -%}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'prep_area' %}
{{ attribute[1] | strip_newlines | strip }}
{% endif %}
{% endfor %}
{%- endcapture -%}
{% assign item_prep_area = item_prep_area | strip %}
{% if item_prep_area != blank %}
{% assign prep_area_exists = false %}
{% if unique_prep_areas != '' %}
{% assign existing_areas = unique_prep_areas | split: ',' %}
{% for existing_area in existing_areas %}
{% if existing_area == item_prep_area %}{% assign prep_area_exists = true %}{% break %}{% endif %}
{% endfor %}
{% endif %}
{% if prep_area_exists == false %}
{% if unique_prep_areas == '' %}
{% assign unique_prep_areas = item_prep_area %}
{% else %}
{% assign unique_prep_areas = unique_prep_areas | append: ',' | append: item_prep_area %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% assign unique_prep_areas_array = unique_prep_areas | split: ',' | sort %}
{% comment %} Count items for the “no prep area” section {% endcomment %}
{% assign items_without_prep_area_count = 0 %}
{% for line_item in order.line_items %}
{% assign item_type_norm = '' %}
{% assign any_poscafe_value = false %}
{% assign is_modifier = false %}
{% assign has_prep_area = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if key_norm == 'item_type' %}{% assign item_type_norm = val_norm %}{% endif %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}{% assign is_modifier = true %}{% endif %}
{% if key_norm == 'prep_area' and attribute[1] != blank %}{% assign has_prep_area = true %}{% endif %}
{% if val_norm == poscafe_norm %}{% assign any_poscafe_value = true %}{% endif %}
{% endfor %}
{% assign is_cafe_item = false %}
{% if item_type_norm == poscafe_norm or any_poscafe_value %}{% assign is_cafe_item = true %}{% endif %}
{% assign include_non_cafe = false %}
{% if show_non_poscafe_items and is_cafe_item == false %}
{% assign include_non_cafe = true %}
{% endif %}
{% assign include_in_no_prep = false %}
{% if is_modifier == false %}
{% if is_cafe_item and has_prep_area == false %}
{% assign include_in_no_prep = true %}
{% elsif include_non_cafe %}
{% assign include_in_no_prep = true %}
{% endif %}
{% endif %}
{% if include_in_no_prep %}
{% assign items_without_prep_area_count = items_without_prep_area_count | plus: 1 %}
{% endif %}
{% endfor %}
{% comment %} Items WITHOUT prep area (incl. non–POS Cafe when enabled) {% endcomment %}
{% if items_without_prep_area_count > 0 %}
<div class='receipt-box'>
{% if has_order_name %}
<p class='gift-receipt' style="font-size: 3rem;">{{ order_name }}</p>
<p>{{ order.name }}</p>
<p style="font-weight: normal;margin-top:10px;"><small>{{ order.created_at | date: "%b %d, %Y – %I:%M %p" }}</small></p>
{% if show_channel %}<p class="channel-label" style="font-weight: normal;margin-top:10px;">{{ channel }}</p>{% endif %}
{% else %}
<p class='gift-receipt' style="font-size: 3rem;">{{ order.name }}</p>
<p style="font-weight: normal;margin-top:10px;"><small>{{ order.created_at | date: "%b %d, %Y – %I:%M %p" }}</small></p>
{% if show_channel %}<p class="channel-label" style="font-weight: normal;margin-top:10px;">{{ channel }}</p>{% endif %}
{% endif %}
</div>
{% for line_item in order.line_items %}
{% assign item_type_norm = '' %}
{% assign any_poscafe_value = false %}
{% assign is_modifier = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if key_norm == 'item_type' %}{% assign item_type_norm = val_norm %}{% endif %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}{% assign is_modifier = true %}{% endif %}
{% if val_norm == poscafe_norm %}{% assign any_poscafe_value = true %}{% endif %}
{% endfor %}
{% assign is_cafe_item = false %}
{% if item_type_norm == poscafe_norm or any_poscafe_value %}{% assign is_cafe_item = true %}{% endif %}
{%- capture current_item_prep_area -%}
{% if is_cafe_item %}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'prep_area' %}{{ attribute[1] | strip_newlines | strip }}{% endif %}
{% endfor %}
{% endif %}
{%- endcapture -%}
{% assign current_item_prep_area = current_item_prep_area | strip %}
{% assign include_non_cafe = false %}
{% if show_non_poscafe_items and is_cafe_item == false %}
{% assign include_non_cafe = true %}
{% endif %}
{% assign should_render = false %}
{% if is_modifier == false %}
{% if is_cafe_item and current_item_prep_area == blank %}
{% assign should_render = true %}
{% elsif include_non_cafe %}
{% assign should_render = true %}
{% endif %}
{% endif %}
{% if should_render %}
<div class='line-item-row'>
<div class='line-item-title'>
<p class='product-name'>{{ line_item.quantity }} x {{ line_item.name | escape }}</p>
{% comment %} First variant description (if any) {% endcomment %}
{% assign variant_description = '' %}
{% for vd in line_item.variant_descriptions %}
{% if vd != blank %}
{% assign variant_description = vd %}
{% break %}
{% endif %}
{% endfor %}
{% assign service_type_value = '' %}
{% if line_item.product %}
{% assign prod_title_norm = line_item.product.title | strip | downcase %}
{% else %}
{% assign prod_title_norm = line_item.name | split: ' - ' | first | strip | downcase %}
{% endif %}
{% assign seen_values = '||' %}
{% capture attributes_html %}
{% if variant_description != blank %}
{% assign v_clean = variant_description | strip | escape %}
{% assign v_norm = v_clean | downcase %}
{% assign v_key = '|' | append: v_norm | append: '|' %}
{% unless seen_values contains v_key %}
<li>{{ v_clean }}</li>
{% assign seen_values = seen_values | append: v_key %}
{% endunless %}
{% endif %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm_raw = attribute[0] | strip | downcase %}
{% assign key_norm = key_norm_raw | replace: ' ', '_' %}
{% assign key_words = key_norm_raw | replace: '_', ' ' %}
{% if service_type_value == '' and key_norm == 'service_type' %}
{% assign service_type_value = attribute[1] | strip | escape %}
{% endif %}
{% assign first_char = key_norm | slice: 0, 1 %}
{% if first_char == '_' %}{% continue %}{% endif %}
{% if hidden_keys contains key_norm or key_words == prod_title_norm %}{% continue %}{% endif %}
{% assign value_clean = attribute[1] | split: '@' | first | strip | escape %}
{% if value_clean != blank %}
{% assign val_norm = value_clean | downcase %}
{% assign needle = '|' | append: val_norm | append: '|' %}
{% unless seen_values contains needle %}
<li>{{ value_clean }}</li>
{% assign seen_values = seen_values | append: needle %}
{% endunless %}
{% endif %}
{% endfor %}
{% endcapture %}
{% if service_type_value != blank %}<p class="dine-option">{{ service_type_value }}</p>{% endif %}
{% assign attributes_trimmed = attributes_html | strip %}
{% if attributes_trimmed != blank %}<ul>{{ attributes_trimmed }}</ul>{% endif %}
</div>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% comment %} Group POS Cafe items BY prep area (modifiers never shown) {% endcomment %}
{% for area in unique_prep_areas_array %}
{% unless forloop.first %}<div class='line-item-row-bottom-border'></div>{% endunless %}
<div class='receipt-box'>
{% if has_order_name %}
<p class='gift-receipt' style="font-size: 3rem;">{{ order_name }}</p>
<p>{{ order.name }}</p>
<p style="font-weight: normal;margin-top:10px;"><small>{{ order.created_at | date: "%b %d, %Y – %I:%M %p" }}</small></p>
{% if show_channel %}<p class="channel-label" style="font-weight: normal;margin-top:10px;">{{ channel }}</p>{% endif %}
{% else %}
<p class='gift-receipt' style="font-size: 3rem;">{{ order.name }}</p>
<p style="font-weight: normal;margin-top:10px;"><small>{{ order.created_at | date: "%b %d, %Y – %I:%M %p" }}</small></p>
{% if show_channel %}<p class="channel-label" style="font-weight: normal;margin-top:10px;">{{ channel }}</p>{% endif %}
{% endif %}
</div>
<div class='line-item-title'>
<p class='prep-area'>{{ area }}</p>
</div>
{% for line_item in order.line_items %}
{% assign item_type_norm = '' %}
{% assign any_poscafe_value = false %}
{% assign is_modifier = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if key_norm == 'item_type' %}{% assign item_type_norm = val_norm %}{% endif %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}{% assign is_modifier = true %}{% endif %}
{% if val_norm == poscafe_norm %}{% assign any_poscafe_value = true %}{% endif %}
{% endfor %}
{% assign is_cafe_item = false %}
{% if item_type_norm == poscafe_norm or any_poscafe_value %}{% assign is_cafe_item = true %}{% endif %}
{% if is_cafe_item and is_modifier == false %}
{%- capture current_item_prep_area -%}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'prep_area' %}{{ attribute[1] | strip_newlines | strip }}{% endif %}
{% endfor %}
{%- endcapture -%}
{% assign current_item_prep_area = current_item_prep_area | strip %}
{% if current_item_prep_area == area %}
<div class='line-item-row'>
<div class='line-item-title'>
<p class='product-name'>{{ line_item.quantity }} x {{ line_item.name | escape }}</p>
{% comment %} First variant description (if any) {% endcomment %}
{% assign variant_description = '' %}
{% for vd in line_item.variant_descriptions %}
{% if vd != blank %}
{% assign variant_description = vd %}
{% break %}
{% endif %}
{% endfor %}
{% assign service_type_value = '' %}
{% if line_item.product %}
{% assign prod_title_norm = line_item.product.title | strip | downcase %}
{% else %}
{% assign prod_title_norm = line_item.name | split: ' - ' | first | strip | downcase %}
{% endif %}
{% assign seen_values = '||' %}
{% capture attributes_html %}
{% if variant_description != blank %}
{% assign v_clean = variant_description | strip | escape %}
{% assign v_norm = v_clean | downcase %}
{% assign v_key = '|' | append: v_norm | append: '|' %}
{% unless seen_values contains v_key %}
<li>{{ v_clean }}</li>
{% assign seen_values = seen_values | append: v_key %}
{% endunless %}
{% endif %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm_raw = attribute[0] | strip | downcase %}
{% assign key_norm = key_norm_raw | replace: ' ', '_' %}
{% assign key_words = key_norm_raw | replace: '_', ' ' %}
{% if service_type_value == '' and key_norm == 'service_type' %}
{% assign service_type_value = attribute[1] | strip | escape %}
{% endif %}
{% assign first_char = key_norm | slice: 0, 1 %}
{% if first_char == '_' %}{% continue %}{% endif %}
{% if hidden_keys contains key_norm or key_words == prod_title_norm %}{% continue %}{% endif %}
{% assign value_clean = attribute[1] | split: '@' | first | strip | escape %}
{% if value_clean != blank %}
{% assign val_norm = value_clean | downcase %}
{% assign needle = '|' | append: val_norm | append: '|' %}
{% unless seen_values contains needle %}
<li>{{ value_clean }}</li>
{% assign seen_values = seen_values | append: needle %}
{% endunless %}
{% endif %}
{% endfor %}
{% endcapture %}
{% if service_type_value != blank %}<p class="dine-option">{{ service_type_value }}</p>{% endif %}
{% assign attributes_trimmed = attributes_html | strip %}
{% if attributes_trimmed != blank %}<ul>{{ attributes_trimmed }}</ul>{% endif %}
</div>
</div>
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
</section>
</div>
{% comment %}
POS Cafe - Receipts 4.1
Receipts/gift-receipt.liquid
Customer receipt header section.
It is your responsibility to ensure that the printed receipts comply with all the applicable laws.
{% endcomment %}
{% assign location_id = location.id | append: "" %}
{% assign display_total_header_1 = "83448037594" | split: "," %}
{% # Default value %}
{% assign display_total_header = true %}
{% # Location overrides %}
{% if display_total_header_1 contains location_id %}
{% assign display_total_header = true %}
{% endif %}
{% # End of the settings definition %}
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
<meta
name='viewport'
content='user-scalable=no'
>
<style>
:root {
--font-smallest: 0.6875rem;
--font-small: 0.875rem;
--font-medium: 1rem;
--font-large: 1.5rem;
--font-largest: 3rem;
--font-family: system-ui;
}
* {
box-sizing: border-box;
}
body {
margin: 2rem 1rem 2.5rem 1rem;
font-family: var(--font-family);
font-weight: 400;
font-size: var(--font-large);
background: white;
}
p {
margin: 0;
}
.price-box {
border-radius: 0.7rem;
border: 0.3rem solid black;
margin: 2.5rem 0.3125rem;
padding: 1.75rem 1.25rem;
text-align: center;
font-weight: bold;
font-size: var(--font-large);
}
.price-box .total {
font-size: var(--font-largest);
}
</style>
</head>
<body>
{% # This section is used by POS UI extensions to show information for the header %}
{% render 'extensions', extension_blocks: extension_blocks.header %}
{% render 'header' %}
{% if display_total_header %}
<div class='price-box'>
<p class='receipt-total-header'>{{ 'receipt.total' | t }}</p>
<p class='total'>{{ order.total_price | money | escape }}</p>
</div>
{% endif %}
{% render 'gift-receipt-line-items' %}
{% render 'transactions' %}
{% render 'footer' %}
{% # This section is required in Germany %}
{% render 'kassenSichV-compliance' %}
{% # This section is used by POS UI extensions to show information for the footer %}
{% render 'extensions', extension_blocks: extension_blocks.footer %}
</body>
</html>
{% comment %}
POS Cafe - Receipts 4.1
Sections/gift-receipt-line-items.liquid
Customer receipt line items section.
It is your responsibility to ensure that the printed receipts comply with all the applicable laws.
{% endcomment %}
{% assign location_id = location.id | append: "" %}
{% comment %}
Feature toggles (adjust per merchant or per location if needed)
{% endcomment %}
{% assign display_product_sku = false %}
{% assign display_sales_attribution = false %}
{% assign display_compare_at_price = true %}
{% comment %} Hide modifiers? If true, $0.00 modifiers are hidden; priced modifiers still show {% endcomment %}
{% assign exclude_modifiers = true %}
{% comment %} NEW: If false, hide ALL modifiers even if they are priced {% endcomment %}
{% assign show_priced_modifiers = true %}
{% comment %} If true and product has tag "hidden-price", hide prices on receipt {% endcomment %}
{% assign hide_price_for_hidden_tag = false %}
{% comment %} If false, suppress the attributes list entirely {% endcomment %}
{% assign show_attributes = false %}
{% comment %} NEW: If false, do not show the product variant at all {% endcomment %}
{% assign show_variant = true %}
{% comment %} Show "Part of <bundle/group>" for non-modifier items. Default off. {% endcomment %}
{% assign show_line_item_group = false %}
{% comment %} Show "Part of <bundle/group>" on modifier items only (usually true). {% endcomment %}
{% assign show_group_on_modifiers = true %}
{% comment %}
Internal lists (normalized keys: downcase + spaces -> underscores)
{% endcomment %}
{% assign modifier_keys = 'item_type,itemtype' | split: ',' %}
{% assign hidden_attr_keys = 'item_type,modifier_variants,_modifiervariants,prep_area,channel' | split: ',' %}
<style>
.variant-name,
.line-item-quantity,
.product_sku,
.sale_attribution,
.selling-plan-name,
.line-item-group { font-size: var(--font-large); }
.line-items-header {
width: 100%;
border-bottom: 0.3rem solid black;
display: flex;
justify-content: space-between;
padding: 0 0.3125rem;
}
.line-item-row { padding: 1.35rem 0; display: flex; justify-content: space-between; }
.line-item-row-bottom-border { border-bottom: 0.25rem dotted black; }
.line-item-title { word-wrap: break-word; max-width: 70%; }
.price, .compare-at-price { padding: 0 0.3125rem; }
.line-item-title .product-name, .price, .line-items-header, .product-discount { font-weight: 700; }
.compare-at-price { text-decoration: line-through; font-size: var(--font-medium); justify-content: flex-end; }
.line-item-container { padding-left: 0.3125rem; padding-right: 0.3125rem; }
.discounts-container { padding: 0 0.3125rem; display: flex; justify-content: space-between; flex-direction: column; }
.discount-row { display: flex; flex-direction: row; }
.discount-code { width: 60%; }
.discount-price { width: 40%; text-align: right; }
.price--hidden { opacity: 0.75; }
</style>
<div class='line-items'>
<header class='line-items-header'>
<p>{{ 'receipt.item' | t }}</p>
<p>{{ 'receipt.price' | t }}</p>
</header>
<section>
{% for line_item in order.line_items %}
{%- comment -%} Identify Modifiers via line-item properties {%- endcomment -%}
{% assign is_modifier = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}
{% assign is_modifier = true %}
{% break %}
{% endif %}
{% endfor %}
{%- comment -%} Priced? (treat > 0 as priced) {%- endcomment -%}
{% assign li_total_num = line_item.total_price | plus: 0 %}
{% assign modifier_is_priced = false %}
{% if li_total_num > 0 %}
{% assign modifier_is_priced = true %}
{% endif %}
{%- comment -%} Optionally hide prices for products tagged 'hidden-price' {%- endcomment -%}
{% assign hide_price = false %}
{% if hide_price_for_hidden_tag and line_item.product and line_item.product.tags contains 'hidden-price' %}
{% assign hide_price = true %}
{% endif %}
{%- comment -%}
Render rules (no parentheses; nested ifs only):
- If NOT a modifier → render as usual.
- If a modifier:
- If show_priced_modifiers == false → skip regardless of price.
- Else if exclude_modifiers == true → skip only when total == 0.
- Else (exclude_modifiers == false) → render always.
{%- endcomment -%}
{% assign skip_item = false %}
{% if is_modifier %}
{% if show_priced_modifiers == false %}
{% assign skip_item = true %}
{% else %}
{% if exclude_modifiers %}
{% if modifier_is_priced == false %}
{% assign skip_item = true %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% unless skip_item %}
<div class='line-item'>
<div class='line-item-row line-item-container'>
<div class='line-item-title'>
<p class='product-name'>{{ line_item.name | escape }}</p>
{%- comment -%}
Variant descriptions:
- If show_attributes == false AND show_variant == true: show standard variant <p> lines (Shopify default).
- If show_attributes == true: we may insert the first variant as the first <li> instead (also guarded by show_variant).
- If show_variant == false: variant is fully suppressed.
{%- endcomment -%}
{% if show_attributes == false %}
{% if show_variant %}
{% for variant_description in line_item.variant_descriptions %}
{% if variant_description != blank %}
<p class='variant-name'>{{ variant_description }}</p>
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% if display_product_sku and line_item.sku %}
<p class='product_sku'>{{ line_item.sku }}</p>
{% endif %}
{% if line_item.quantity > 1 %}
{% if hide_price %}
<div class='line-item-quantity'>({{ line_item.quantity }} x —)</div>
{% else %}
<div class='line-item-quantity'>({{ line_item.quantity }} x {{ line_item.price | money | escape }})</div>
{% endif %}
{% endif %}
{%- comment -%}
"Part of ..." visibility:
- On modifiers: show if show_group_on_modifiers is true.
- On non-modifiers: show only if show_line_item_group is true AND show_group_on_modifiers is false
(to avoid duplicate “Part of …” on both parent and children).
{%- endcomment -%}
{% assign has_group_title = false %}
{% if line_item.line_item_group and line_item.line_item_group.title %}
{% assign has_group_title = true %}
{% endif %}
{% if is_modifier %}
{% if has_group_title and show_group_on_modifiers %}
<p class='line-item-group'>{{ 'receipt.part_of' | t }} {{ line_item.line_item_group.title }}</p>
{% endif %}
{% else %}
{% if has_group_title and show_line_item_group and show_group_on_modifiers == false %}
<p class='line-item-group'>{{ 'receipt.part_of' | t }} {{ line_item.line_item_group.title }}</p>
{% endif %}
{% endif %}
{% if display_sales_attribution and line_item.staff_member_description %}
<p class='sale_attribution'>
{{ 'receipt.sold_by_line_item' | t }} {{ line_item.staff_member_description }}
</p>
{% endif %}
{% if show_attributes %}
{%- comment -%}
Build attributes list:
- Optionally add the first variant_description at the top as <li> (when show_variant).
- Filter hidden keys and underscore-prefixed internal keys.
- Trim any "@price" suffix.
- De-duplicate values (case-insensitive).
{%- endcomment -%}
{% assign first_variant_description = '' %}
{% if show_variant %}
{% for vd in line_item.variant_descriptions %}
{% if vd != blank %}
{% assign first_variant_description = vd %}
{% break %}
{% endif %}
{% endfor %}
{% endif %}
{% if line_item.product %}
{% assign prod_title_norm = line_item.product.title | strip | downcase %}
{% else %}
{% assign prod_title_norm = line_item.name | split: ' - ' | first | strip | downcase %}
{% endif %}
{% assign seen_values = '||' %}
{% capture attributes_html %}
{% if first_variant_description != blank %}
{% assign v_clean = first_variant_description | strip | escape %}
{% assign v_norm = v_clean | downcase %}
{% assign v_key = '|' | append: v_norm | append: '|' %}
{% unless seen_values contains v_key %}
<li>{{ v_clean }}</li>
{% assign seen_values = seen_values | append: v_key %}
{% endunless %}
{% endif %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm_raw = attribute[0] | strip | downcase %}
{% assign key_norm = key_norm_raw | replace: ' ', '_' %}
{% assign key_words = key_norm_raw | replace: '_', ' ' %}
{% assign first_char = key_norm | slice: 0, 1 %}
{% if first_char == '_' %}{% continue %}{% endif %}
{% unless hidden_attr_keys contains key_norm or key_words == prod_title_norm %}
{% assign value_clean = attribute[1] | split: '@' | first | strip | escape %}
{% if value_clean != blank %}
{% assign val_norm = value_clean | downcase %}
{% assign needle = '|' | append: val_norm | append: '|' %}
{% unless seen_values contains needle %}
<li>{{ value_clean }}</li>
{% assign seen_values = seen_values | append: needle %}
{% endunless %}
{% endif %}
{% endunless %}
{% endfor %}
{% endcapture %}
{% assign attributes_trimmed = attributes_html | strip %}
{% if attributes_trimmed != blank %}
<ul>{{ attributes_trimmed }}</ul>
{% endif %}
{% endif %}
{% for selling_plan in line_item.selling_plans %}
{% if selling_plan.name != blank %}
<p class='selling-plan-name'>{{ selling_plan.name | escape }}</p>
{% endif %}
{% endfor %}
</div>
<div>
{% if hide_price %}
<div class='price price--hidden'>—</div>
{% else %}
<div class='price'>{{ line_item.total_price | money | escape }}</div>
{% if display_compare_at_price and line_item.compare_at_price_description %}
<div class='line-item-row compare-at-price'>
{{ line_item.compare_at_price_description | money | escape }}
</div>
{% endif %}
{% endif %}
</div>
</div>
{% if line_item.discounts.size > 0 %}
<div class='discounts-container'>
{% for discount in line_item.discounts %}
{% assign discount_amount_num = discount.amount | plus: 0 %}
{% if discount.description or discount_amount_num > 0 %}
<div class='discount-row'>
<p class='discount-code'>{{ discount.description | escape }}</p>
{% if discount_amount_num > 0 %}
<p class='discount-price price'>-{{ discount.amount | money | escape }}</p>
{% endif %}
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% for refund in line_item.refunds %}
<p class='refunded-product'>
{% assign created_at = refund.created_at | date %}
{{ 'receipt.refunded_on' | t: quantity: refund.refund_line_item.quantity, date: created_at }}
</p>
{% endfor %}
</div>
<div class='line-item-row-bottom-border'></div>
{% endunless %}
{% endfor %}
</section>
</div>
Use this option if you would like your gift receipt to print as an
order ticket, and your sales receipt to print as your sales receipt. Note,
in this configuration, you do not need to edit your
Receipts/sales-receipt.liquid
code snippet.
{% comment %}
POS Cafe - Receipts 4.1
Sections/line-items.liquid
Customer receipt line items section.
It is your responsibility to ensure that the printed receipts comply with all the applicable laws.
{% endcomment %}
{% assign location_id = location.id | append: "" %}
{% comment %}
Feature toggles (adjust per merchant or per location if needed)
{% endcomment %}
{% assign display_product_sku = false %}
{% assign display_sales_attribution = false %}
{% assign display_compare_at_price = true %}
{% comment %} Hide modifiers? If true, $0.00 modifiers are hidden; priced modifiers still show {% endcomment %}
{% assign exclude_modifiers = true %}
{% comment %} NEW: If false, hide ALL modifiers even if they are priced {% endcomment %}
{% assign show_priced_modifiers = true %}
{% comment %} If true and product has tag "hidden-price", hide prices on receipt {% endcomment %}
{% assign hide_price_for_hidden_tag = false %}
{% comment %} If false, suppress the attributes list entirely {% endcomment %}
{% assign show_attributes = false %}
{% comment %} NEW: If false, do not show the product variant at all {% endcomment %}
{% assign show_variant = true %}
{% comment %} Show "Part of <bundle/group>" for non-modifier items. Default off. {% endcomment %}
{% assign show_line_item_group = false %}
{% comment %} Show "Part of <bundle/group>" on modifier items only (usually true). {% endcomment %}
{% assign show_group_on_modifiers = true %}
{% comment %}
Internal lists (normalized keys: downcase + spaces -> underscores)
{% endcomment %}
{% assign modifier_keys = 'item_type,itemtype' | split: ',' %}
{% assign hidden_attr_keys = 'item_type,modifier_variants,_modifiervariants,prep_area,channel' | split: ',' %}
<style>
.variant-name,
.line-item-quantity,
.product_sku,
.sale_attribution,
.selling-plan-name,
.line-item-group { font-size: var(--font-large); }
.line-items-header {
width: 100%;
border-bottom: 0.3rem solid black;
display: flex;
justify-content: space-between;
padding: 0 0.3125rem;
}
.line-item-row { padding: 1.35rem 0; display: flex; justify-content: space-between; }
.line-item-row-bottom-border { border-bottom: 0.25rem dotted black; }
.line-item-title { word-wrap: break-word; max-width: 70%; }
.price, .compare-at-price { padding: 0 0.3125rem; }
.line-item-title .product-name, .price, .line-items-header, .product-discount { font-weight: 700; }
.compare-at-price { text-decoration: line-through; font-size: var(--font-medium); justify-content: flex-end; }
.line-item-container { padding-left: 0.3125rem; padding-right: 0.3125rem; }
.discounts-container { padding: 0 0.3125rem; display: flex; justify-content: space-between; flex-direction: column; }
.discount-row { display: flex; flex-direction: row; }
.discount-code { width: 60%; }
.discount-price { width: 40%; text-align: right; }
.price--hidden { opacity: 0.75; }
</style>
<div class='line-items'>
<header class='line-items-header'>
<p>{{ 'receipt.item' | t }}</p>
<p>{{ 'receipt.price' | t }}</p>
</header>
<section>
{% for line_item in order.line_items %}
{%- comment -%} Identify Modifiers via line-item properties {%- endcomment -%}
{% assign is_modifier = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}
{% assign is_modifier = true %}
{% break %}
{% endif %}
{% endfor %}
{%- comment -%} Priced? (treat > 0 as priced) {%- endcomment -%}
{% assign li_total_num = line_item.total_price | plus: 0 %}
{% assign modifier_is_priced = false %}
{% if li_total_num > 0 %}
{% assign modifier_is_priced = true %}
{% endif %}
{%- comment -%} Optionally hide prices for products tagged 'hidden-price' {%- endcomment -%}
{% assign hide_price = false %}
{% if hide_price_for_hidden_tag and line_item.product and line_item.product.tags contains 'hidden-price' %}
{% assign hide_price = true %}
{% endif %}
{%- comment -%}
Render rules (no parentheses; nested ifs only):
- If NOT a modifier → render as usual.
- If a modifier:
- If show_priced_modifiers == false → skip regardless of price.
- Else if exclude_modifiers == true → skip only when total == 0.
- Else (exclude_modifiers == false) → render always.
{%- endcomment -%}
{% assign skip_item = false %}
{% if is_modifier %}
{% if show_priced_modifiers == false %}
{% assign skip_item = true %}
{% else %}
{% if exclude_modifiers %}
{% if modifier_is_priced == false %}
{% assign skip_item = true %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% unless skip_item %}
<div class='line-item'>
<div class='line-item-row line-item-container'>
<div class='line-item-title'>
<p class='product-name'>{{ line_item.name | escape }}</p>
{%- comment -%}
Variant descriptions:
- If show_attributes == false AND show_variant == true: show standard variant <p> lines (Shopify default).
- If show_attributes == true: we may insert the first variant as the first <li> instead (also guarded by show_variant).
- If show_variant == false: variant is fully suppressed.
{%- endcomment -%}
{% if show_attributes == false %}
{% if show_variant %}
{% for variant_description in line_item.variant_descriptions %}
{% if variant_description != blank %}
<p class='variant-name'>{{ variant_description }}</p>
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% if display_product_sku and line_item.sku %}
<p class='product_sku'>{{ line_item.sku }}</p>
{% endif %}
{% if line_item.quantity > 1 %}
{% if hide_price %}
<div class='line-item-quantity'>({{ line_item.quantity }} x —)</div>
{% else %}
<div class='line-item-quantity'>({{ line_item.quantity }} x {{ line_item.price | money | escape }})</div>
{% endif %}
{% endif %}
{%- comment -%}
"Part of ..." visibility:
- On modifiers: show if show_group_on_modifiers is true.
- On non-modifiers: show only if show_line_item_group is true AND show_group_on_modifiers is false
(to avoid duplicate “Part of …” on both parent and children).
{%- endcomment -%}
{% assign has_group_title = false %}
{% if line_item.line_item_group and line_item.line_item_group.title %}
{% assign has_group_title = true %}
{% endif %}
{% if is_modifier %}
{% if has_group_title and show_group_on_modifiers %}
<p class='line-item-group'>{{ 'receipt.part_of' | t }} {{ line_item.line_item_group.title }}</p>
{% endif %}
{% else %}
{% if has_group_title and show_line_item_group and show_group_on_modifiers == false %}
<p class='line-item-group'>{{ 'receipt.part_of' | t }} {{ line_item.line_item_group.title }}</p>
{% endif %}
{% endif %}
{% if display_sales_attribution and line_item.staff_member_description %}
<p class='sale_attribution'>
{{ 'receipt.sold_by_line_item' | t }} {{ line_item.staff_member_description }}
</p>
{% endif %}
{% if show_attributes %}
{%- comment -%}
Build attributes list:
- Optionally add the first variant_description at the top as <li> (when show_variant).
- Filter hidden keys and underscore-prefixed internal keys.
- Trim any "@price" suffix.
- De-duplicate values (case-insensitive).
{%- endcomment -%}
{% assign first_variant_description = '' %}
{% if show_variant %}
{% for vd in line_item.variant_descriptions %}
{% if vd != blank %}
{% assign first_variant_description = vd %}
{% break %}
{% endif %}
{% endfor %}
{% endif %}
{% if line_item.product %}
{% assign prod_title_norm = line_item.product.title | strip | downcase %}
{% else %}
{% assign prod_title_norm = line_item.name | split: ' - ' | first | strip | downcase %}
{% endif %}
{% assign seen_values = '||' %}
{% capture attributes_html %}
{% if first_variant_description != blank %}
{% assign v_clean = first_variant_description | strip | escape %}
{% assign v_norm = v_clean | downcase %}
{% assign v_key = '|' | append: v_norm | append: '|' %}
{% unless seen_values contains v_key %}
<li>{{ v_clean }}</li>
{% assign seen_values = seen_values | append: v_key %}
{% endunless %}
{% endif %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm_raw = attribute[0] | strip | downcase %}
{% assign key_norm = key_norm_raw | replace: ' ', '_' %}
{% assign key_words = key_norm_raw | replace: '_', ' ' %}
{% assign first_char = key_norm | slice: 0, 1 %}
{% if first_char == '_' %}{% continue %}{% endif %}
{% unless hidden_attr_keys contains key_norm or key_words == prod_title_norm %}
{% assign value_clean = attribute[1] | split: '@' | first | strip | escape %}
{% if value_clean != blank %}
{% assign val_norm = value_clean | downcase %}
{% assign needle = '|' | append: val_norm | append: '|' %}
{% unless seen_values contains needle %}
<li>{{ value_clean }}</li>
{% assign seen_values = seen_values | append: needle %}
{% endunless %}
{% endif %}
{% endunless %}
{% endfor %}
{% endcapture %}
{% assign attributes_trimmed = attributes_html | strip %}
{% if attributes_trimmed != blank %}
<ul>{{ attributes_trimmed }}</ul>
{% endif %}
{% endif %}
{% for selling_plan in line_item.selling_plans %}
{% if selling_plan.name != blank %}
<p class='selling-plan-name'>{{ selling_plan.name | escape }}</p>
{% endif %}
{% endfor %}
</div>
<div>
{% if hide_price %}
<div class='price price--hidden'>—</div>
{% else %}
<div class='price'>{{ line_item.total_price | money | escape }}</div>
{% if display_compare_at_price and line_item.compare_at_price_description %}
<div class='line-item-row compare-at-price'>
{{ line_item.compare_at_price_description | money | escape }}
</div>
{% endif %}
{% endif %}
</div>
</div>
{% if line_item.discounts.size > 0 %}
<div class='discounts-container'>
{% for discount in line_item.discounts %}
{% assign discount_amount_num = discount.amount | plus: 0 %}
{% if discount.description or discount_amount_num > 0 %}
<div class='discount-row'>
<p class='discount-code'>{{ discount.description | escape }}</p>
{% if discount_amount_num > 0 %}
<p class='discount-price price'>-{{ discount.amount | money | escape }}</p>
{% endif %}
</div>
{% endif %}
{% endfor %}
</div>
{% endif %}
{% for refund in line_item.refunds %}
<p class='refunded-product'>
{% assign created_at = refund.created_at | date %}
{{ 'receipt.refunded_on' | t: quantity: refund.refund_line_item.quantity, date: created_at }}
</p>
{% endfor %}
</div>
<div class='line-item-row-bottom-border'></div>
{% endunless %}
{% endfor %}
</section>
</div>
{% comment %}
POS Cafe - Receipts 4.1
Receipts/gift-receipt.liquid
Order ticket header section.
It is your responsibility to ensure that the printed receipts comply with all the applicable laws.
{% endcomment %}
{% assign location_id = location.id | append: "" %}
{% assign display_total_header_1 = "76500435181" | split: "," %}
{% # Default value %}
{% assign display_total_header = true %}
{% # Location overrides %}
{% if display_total_header_1 contains location_id %}
{% assign display_total_header = true %}
{% endif %}
{% # Display order note %}
{% assign display_order_note = true %}
{% # End of the settings definition %}
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
<meta
name='viewport'
content='user-scalable=no'
>
<style>
:root {
--font-smallest: 0.6875rem;
--font-small: 0.875rem;
--font-medium: 1rem;
--font-large: 1.5rem;
--font-largest: 3rem;
--font-family: system-ui;
}
* {
box-sizing: border-box;
}
body {
margin: 2rem 1rem 2.5rem 1rem;
font-family: var(--font-family);
font-weight: 400;
font-size: var(--font-large);
background: white;
}
p {
margin: 0;
}
.receipt-box {
border-color: black;
border-radius: 0.7rem;
border: 0.3rem solid;
margin: 2.5rem 0.3125rem;
padding: 1.75rem 1.25rem;
text-align: center;
font-weight: bold;
font-size: var(--font-large);
}
.receipt-box .channel-label {
font-weight: bold;
font-size: var(--font-large);
}
.note {
padding-top: 1.35rem;
border-top: 0.25rem dotted black;
font-size: var(--font-large);
}
.note-title {
font-weight: bold;
padding-bottom: 0.3125rem;
font-size: var(--font-large);
}
</style>
</head>
<body>
{% render 'gift-receipt-line-items' %}
{% if display_order_note %}
{% if order.note != nil and order.note != blank %}
<section class='note'>
<p class='note-title'>{{ 'receipt.order_note' | t }}</p>
<p>{{ order.note | escape }}</p>
</section>
{% endif %}
{% endif %}
</body>
</html>
{% comment %}
POS Cafe - Receipts 4.1
Sections/gift-receipt-line-items.liquid
Order ticket line items section.
It is your responsibility to ensure that the printed receipts comply with all the applicable laws.
{% endcomment %}
<style>
.variant-name,
.line-item-quantity,
.line-item-group { font-size: var(--font-large); }
.line-items-header {
width: 100%;
border-bottom: 0.3rem solid black;
display: flex;
justify-content: space-between;
padding: 0 0.3125rem;
}
.line-item-row { padding: 1.35rem 0; display: flex; justify-content: space-between; }
.line-item-row-bottom-border { border-bottom: 0.25rem dotted black; }
.line-item-title, .line-item-quantity { padding: 0 0.3125rem; }
.line-item-title .product-name,
.line-item-quantity,
.line-items-header { font-size: 3rem; }
.line-item-title .prep-area,
.line-item-quantity,
.line-items-header {
font-size: 3rem;
font-weight:bold;
text-align:center;
margin-bottom:0.5rem;
}
.dine-option {
font-size: 2rem;
font-weight: 700;
text-transform: uppercase;
margin-top: 0.25rem;
}
li { font-size: 2rem; }
hr.cut-here { border-top: 10px dashed black; }
</style>
<div>
<section>
{% # Set variables %}
{% assign poscafe = "POS Cafe" %}
{% assign poscafe_norm = poscafe | downcase %}
{% assign unique_prep_areas = '' %}
{% assign has_order_name = false %}
{% assign order_name = '' %}
{% assign has_channel = false %}
{% assign channel = "Online" %}
{% assign show_channel = false %} {% # toggle: show/hide the channel line in header %}
{% comment %} Toggle: include non–POS Cafe items in the “no prep area” section {% endcomment %}
{% assign show_non_poscafe_items = false %}
{% comment %} Keys to hide from attributes (normalized: downcase + spaces->underscores) {% endcomment %}
{% assign hidden_keys = 'item_type,modifier_variants,_modifiervariants,prep_area,channel,service_type' | split: ',' %}
{% assign modifier_keys = 'item_type,itemtype' | split: ',' %}
{% comment %} First pass: capture order name/channel, and collect unique prep areas for POS Cafe items (never include modifiers) {% endcomment %}
{% for line_item in order.line_items %}
{% assign item_type_norm = '' %}
{% assign any_poscafe_value = false %}
{% assign is_modifier = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if key_norm == 'item_type' %}{% assign item_type_norm = val_norm %}{% endif %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}{% assign is_modifier = true %}{% endif %}
{% if val_norm == poscafe_norm %}{% assign any_poscafe_value = true %}{% endif %}
{% endfor %}
{% assign is_cafe_item = false %}
{% if item_type_norm == poscafe_norm or any_poscafe_value %}{% assign is_cafe_item = true %}{% endif %}
{% if has_order_name == false %}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'name' %}
{% assign has_order_name = true %}
{% assign order_name = attribute[1] | strip_newlines | strip %}
{% break %}
{% endif %}
{% endfor %}
{% endif %}
{% if has_channel == false %}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'channel' %}
{% assign has_channel = true %}
{% assign channel = attribute[1] | strip_newlines | strip %}
{% break %}
{% endif %}
{% endfor %}
{% endif %}
{% if is_cafe_item and is_modifier == false %}
{%- capture item_prep_area -%}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'prep_area' %}
{{ attribute[1] | strip_newlines | strip }}
{% endif %}
{% endfor %}
{%- endcapture -%}
{% assign item_prep_area = item_prep_area | strip %}
{% if item_prep_area != blank %}
{% assign prep_area_exists = false %}
{% if unique_prep_areas != '' %}
{% assign existing_areas = unique_prep_areas | split: ',' %}
{% for existing_area in existing_areas %}
{% if existing_area == item_prep_area %}{% assign prep_area_exists = true %}{% break %}{% endif %}
{% endfor %}
{% endif %}
{% if prep_area_exists == false %}
{% if unique_prep_areas == '' %}
{% assign unique_prep_areas = item_prep_area %}
{% else %}
{% assign unique_prep_areas = unique_prep_areas | append: ',' | append: item_prep_area %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% assign unique_prep_areas_array = unique_prep_areas | split: ',' | sort %}
{% comment %} Count items for the “no prep area” section {% endcomment %}
{% assign items_without_prep_area_count = 0 %}
{% for line_item in order.line_items %}
{% assign item_type_norm = '' %}
{% assign any_poscafe_value = false %}
{% assign is_modifier = false %}
{% assign has_prep_area = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if key_norm == 'item_type' %}{% assign item_type_norm = val_norm %}{% endif %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}{% assign is_modifier = true %}{% endif %}
{% if key_norm == 'prep_area' and attribute[1] != blank %}{% assign has_prep_area = true %}{% endif %}
{% if val_norm == poscafe_norm %}{% assign any_poscafe_value = true %}{% endif %}
{% endfor %}
{% assign is_cafe_item = false %}
{% if item_type_norm == poscafe_norm or any_poscafe_value %}{% assign is_cafe_item = true %}{% endif %}
{% assign include_non_cafe = false %}
{% if show_non_poscafe_items and is_cafe_item == false %}
{% assign include_non_cafe = true %}
{% endif %}
{% assign include_in_no_prep = false %}
{% if is_modifier == false %}
{% if is_cafe_item and has_prep_area == false %}
{% assign include_in_no_prep = true %}
{% elsif include_non_cafe %}
{% assign include_in_no_prep = true %}
{% endif %}
{% endif %}
{% if include_in_no_prep %}
{% assign items_without_prep_area_count = items_without_prep_area_count | plus: 1 %}
{% endif %}
{% endfor %}
{% comment %} Items WITHOUT prep area (incl. non–POS Cafe when enabled) {% endcomment %}
{% if items_without_prep_area_count > 0 %}
<div class='receipt-box'>
{% if has_order_name %}
<p class='gift-receipt' style="font-size: 3rem;">{{ order_name }}</p>
<p>{{ order.name }}</p>
<p style="font-weight: normal;margin-top:10px;"><small>{{ order.created_at | date: "%b %d, %Y – %I:%M %p" }}</small></p>
{% if show_channel %}<p class="channel-label" style="font-weight: normal;margin-top:10px;">{{ channel }}</p>{% endif %}
{% else %}
<p class='gift-receipt' style="font-size: 3rem;">{{ order.name }}</p>
<p style="font-weight: normal;margin-top:10px;"><small>{{ order.created_at | date: "%b %d, %Y – %I:%M %p" }}</small></p>
{% if show_channel %}<p class="channel-label" style="font-weight: normal;margin-top:10px;">{{ channel }}</p>{% endif %}
{% endif %}
</div>
{% for line_item in order.line_items %}
{% assign item_type_norm = '' %}
{% assign any_poscafe_value = false %}
{% assign is_modifier = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if key_norm == 'item_type' %}{% assign item_type_norm = val_norm %}{% endif %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}{% assign is_modifier = true %}{% endif %}
{% if val_norm == poscafe_norm %}{% assign any_poscafe_value = true %}{% endif %}
{% endfor %}
{% assign is_cafe_item = false %}
{% if item_type_norm == poscafe_norm or any_poscafe_value %}{% assign is_cafe_item = true %}{% endif %}
{%- capture current_item_prep_area -%}
{% if is_cafe_item %}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'prep_area' %}{{ attribute[1] | strip_newlines | strip }}{% endif %}
{% endfor %}
{% endif %}
{%- endcapture -%}
{% assign current_item_prep_area = current_item_prep_area | strip %}
{% assign include_non_cafe = false %}
{% if show_non_poscafe_items and is_cafe_item == false %}
{% assign include_non_cafe = true %}
{% endif %}
{% assign should_render = false %}
{% if is_modifier == false %}
{% if is_cafe_item and current_item_prep_area == blank %}
{% assign should_render = true %}
{% elsif include_non_cafe %}
{% assign should_render = true %}
{% endif %}
{% endif %}
{% if should_render %}
<div class='line-item-row'>
<div class='line-item-title'>
<p class='product-name'>{{ line_item.quantity }} x {{ line_item.name | escape }}</p>
{% comment %} First variant description (if any) {% endcomment %}
{% assign variant_description = '' %}
{% for vd in line_item.variant_descriptions %}
{% if vd != blank %}
{% assign variant_description = vd %}
{% break %}
{% endif %}
{% endfor %}
{% assign service_type_value = '' %}
{% if line_item.product %}
{% assign prod_title_norm = line_item.product.title | strip | downcase %}
{% else %}
{% assign prod_title_norm = line_item.name | split: ' - ' | first | strip | downcase %}
{% endif %}
{% assign seen_values = '||' %}
{% capture attributes_html %}
{% if variant_description != blank %}
{% assign v_clean = variant_description | strip | escape %}
{% assign v_norm = v_clean | downcase %}
{% assign v_key = '|' | append: v_norm | append: '|' %}
{% unless seen_values contains v_key %}
<li>{{ v_clean }}</li>
{% assign seen_values = seen_values | append: v_key %}
{% endunless %}
{% endif %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm_raw = attribute[0] | strip | downcase %}
{% assign key_norm = key_norm_raw | replace: ' ', '_' %}
{% assign key_words = key_norm_raw | replace: '_', ' ' %}
{% if service_type_value == '' and key_norm == 'service_type' %}
{% assign service_type_value = attribute[1] | strip | escape %}
{% endif %}
{% assign first_char = key_norm | slice: 0, 1 %}
{% if first_char == '_' %}{% continue %}{% endif %}
{% if hidden_keys contains key_norm or key_words == prod_title_norm %}{% continue %}{% endif %}
{% assign value_clean = attribute[1] | split: '@' | first | strip | escape %}
{% if value_clean != blank %}
{% assign val_norm = value_clean | downcase %}
{% assign needle = '|' | append: val_norm | append: '|' %}
{% unless seen_values contains needle %}
<li>{{ value_clean }}</li>
{% assign seen_values = seen_values | append: needle %}
{% endunless %}
{% endif %}
{% endfor %}
{% endcapture %}
{% if service_type_value != blank %}<p class="dine-option">{{ service_type_value }}</p>{% endif %}
{% assign attributes_trimmed = attributes_html | strip %}
{% if attributes_trimmed != blank %}<ul>{{ attributes_trimmed }}</ul>{% endif %}
</div>
</div>
{% endif %}
{% endfor %}
{% endif %}
{% comment %} Group POS Cafe items BY prep area (modifiers never shown) {% endcomment %}
{% for area in unique_prep_areas_array %}
{% unless forloop.first %}<div class='line-item-row-bottom-border'></div>{% endunless %}
<div class='receipt-box'>
{% if has_order_name %}
<p class='gift-receipt' style="font-size: 3rem;">{{ order_name }}</p>
<p>{{ order.name }}</p>
<p style="font-weight: normal;margin-top:10px;"><small>{{ order.created_at | date: "%b %d, %Y – %I:%M %p" }}</small></p>
{% if show_channel %}<p class="channel-label" style="font-weight: normal;margin-top:10px;">{{ channel }}</p>{% endif %}
{% else %}
<p class='gift-receipt' style="font-size: 3rem;">{{ order.name }}</p>
<p style="font-weight: normal;margin-top:10px;"><small>{{ order.created_at | date: "%b %d, %Y – %I:%M %p" }}</small></p>
{% if show_channel %}<p class="channel-label" style="font-weight: normal;margin-top:10px;">{{ channel }}</p>{% endif %}
{% endif %}
</div>
<div class='line-item-title'>
<p class='prep-area'>{{ area }}</p>
</div>
{% for line_item in order.line_items %}
{% assign item_type_norm = '' %}
{% assign any_poscafe_value = false %}
{% assign is_modifier = false %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm = attribute[0] | strip | downcase | replace: ' ', '_' %}
{% assign val_norm = attribute[1] | strip | downcase %}
{% if key_norm == 'item_type' %}{% assign item_type_norm = val_norm %}{% endif %}
{% if modifier_keys contains key_norm and val_norm == 'modifier' %}{% assign is_modifier = true %}{% endif %}
{% if val_norm == poscafe_norm %}{% assign any_poscafe_value = true %}{% endif %}
{% endfor %}
{% assign is_cafe_item = false %}
{% if item_type_norm == poscafe_norm or any_poscafe_value %}{% assign is_cafe_item = true %}{% endif %}
{% if is_cafe_item and is_modifier == false %}
{%- capture current_item_prep_area -%}
{% for attribute in line_item.custom_attributes %}
{% if attribute[0] == 'prep_area' %}{{ attribute[1] | strip_newlines | strip }}{% endif %}
{% endfor %}
{%- endcapture -%}
{% assign current_item_prep_area = current_item_prep_area | strip %}
{% if current_item_prep_area == area %}
<div class='line-item-row'>
<div class='line-item-title'>
<p class='product-name'>{{ line_item.quantity }} x {{ line_item.name | escape }}</p>
{% comment %} First variant description (if any) {% endcomment %}
{% assign variant_description = '' %}
{% for vd in line_item.variant_descriptions %}
{% if vd != blank %}
{% assign variant_description = vd %}
{% break %}
{% endif %}
{% endfor %}
{% assign service_type_value = '' %}
{% if line_item.product %}
{% assign prod_title_norm = line_item.product.title | strip | downcase %}
{% else %}
{% assign prod_title_norm = line_item.name | split: ' - ' | first | strip | downcase %}
{% endif %}
{% assign seen_values = '||' %}
{% capture attributes_html %}
{% if variant_description != blank %}
{% assign v_clean = variant_description | strip | escape %}
{% assign v_norm = v_clean | downcase %}
{% assign v_key = '|' | append: v_norm | append: '|' %}
{% unless seen_values contains v_key %}
<li>{{ v_clean }}</li>
{% assign seen_values = seen_values | append: v_key %}
{% endunless %}
{% endif %}
{% for attribute in line_item.custom_attributes %}
{% assign key_norm_raw = attribute[0] | strip | downcase %}
{% assign key_norm = key_norm_raw | replace: ' ', '_' %}
{% assign key_words = key_norm_raw | replace: '_', ' ' %}
{% if service_type_value == '' and key_norm == 'service_type' %}
{% assign service_type_value = attribute[1] | strip | escape %}
{% endif %}
{% assign first_char = key_norm | slice: 0, 1 %}
{% if first_char == '_' %}{% continue %}{% endif %}
{% if hidden_keys contains key_norm or key_words == prod_title_norm %}{% continue %}{% endif %}
{% assign value_clean = attribute[1] | split: '@' | first | strip | escape %}
{% if value_clean != blank %}
{% assign val_norm = value_clean | downcase %}
{% assign needle = '|' | append: val_norm | append: '|' %}
{% unless seen_values contains needle %}
<li>{{ value_clean }}</li>
{% assign seen_values = seen_values | append: needle %}
{% endunless %}
{% endif %}
{% endfor %}
{% endcapture %}
{% if service_type_value != blank %}<p class="dine-option">{{ service_type_value }}</p>{% endif %}
{% assign attributes_trimmed = attributes_html | strip %}
{% if attributes_trimmed != blank %}<ul>{{ attributes_trimmed }}</ul>{% endif %}
</div>
</div>
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
</section>
</div>
Shopify POS print options
In POS » Settings » Receipts, review your printing preferences for each location (e.g., whether to automatically print after checkout, and which printer to use). If you use the Gift receipt as Order Ticket option, staff will print the Order Ticket by tapping the gift receipt button on the completion screen.
Troubleshooting
Issue | Solution |
---|---|
No items appear on the Order Ticket? | Only POS Cafe items are printed. Ensure items were created in POS Cafe and (optionally) that their prep_area is set. |
Station headings look wrong? | Set/adjust Prep Areas in POS Cafe; items without a prep area print in the “no prep area” section. |
Need to revert? | Click on the undo icon |