{@com.eszes.saas.app.be.bms.ecom.model.entity.Order order} {! Print surface, NOT an email. MailService.getHtmlBody renders this for GET /order/{id}/html-body and /me; the FE drops it into a hidden iframe and calls print(). Design constraints that follow from that: - Browsers strip background colours when printing, so hierarchy is built from type, tracking and rules only. Borders and type do print. - No web fonts: print() fires ~500ms after load, so a swapping face prints as fallback. System monospace stack only. - Rules are pure ink. Thermal paper print. - Qute treats { as literal only when the next char is whitespace. Every CSS brace below is followed by a newline. A one-line rule such as .foo{margin:0} would be parsed as an expression and silently dropped. - A null amount hides its whole row. Never print a fabricated 0.00 against a label, which reads as "we charged you zero tax" rather than "not applicable". - @page has no fixed length: the FE measures the rendered body and injects @page { size: 80mm mm } before print(), so the paper stops at the content. tenant is a Map from TenantConfigResolver.resolveTenantBranding; receipt is a ReceiptRecordView (receipt printer header/footer lines and the locale's clock), see MailService.orderRecordHtml. A Register sale (order.pricesIncludeVat) prints like the till receipt the admin app builds: VAT-inclusive prices, no ex-VAT subtotal, VAT by rate. !} Bill #{order.orderNumber}

{tenant.brand.name}

{#if tenant.brand.address || tenant.brand.phone || tenant.brand.email}
{#if tenant.brand.address}
{tenant.brand.address}
{/if} {#if tenant.brand.phone}
Phone: {tenant.brand.phone}
{/if} {#if tenant.brand.email}
Email: {tenant.brand.email}
{/if}
{/if} {#if receipt?? && !receipt.headerLines.isEmpty()}
{#for line in receipt.headerLines}
{line}
{/for}
{/if}
{#if order.pricesIncludeVat}
SALES RECEIPT{#if !order.taxOff}
{#if order.gstDocument}Prices include GST{#else}Prices include VAT{/if}{/if}
{/if}
Bill No: {order.orderNumber}
Date: {#if order.createdDateTime}{order.createdDateTime.formattedDateIn(tenant.timezone)}{#else}{#if order.orderStatusActivities && !order.orderStatusActivities.isEmpty()}{order.orderStatusActivities.get(0).changedAt.formattedDateIn(tenant.timezone)}{#else}{java.time.LocalDateTime.now().formattedDateIn(tenant.timezone)}{/if}{/if}
Time: {#if order.createdDateTime}{order.createdDateTime.formatDateIn(tenant.timezone, receipt.timePattern)}{#else}{#if order.orderStatusActivities && !order.orderStatusActivities.isEmpty()}{order.orderStatusActivities.get(0).changedAt.formatDateIn(tenant.timezone, receipt.timePattern)}{#else}{java.time.LocalDateTime.now().formatDateIn(tenant.timezone, receipt.timePattern)}{/if}{/if}
{#if order.serviceModeText}
{order.serviceModeText}
{/if}
{#if order.customer || order.paymentMethod} {#if order.customer} {/if} {#if order.paymentMethod} {/if}
Customer {#if order.customer.firstName}{order.customer.firstName}{#if order.customer.lastName} {order.customer.lastName}{/if}{#else}Walk-in{/if}
Payment {order.paymentMethod}{#if order.paymentStatus} · {order.paymentStatus}{/if}
{/if} {#if order.hasAccountPrices}
Account prices applied
{/if} {#for item in order.orderProducts} {/for} {#if !order.orderProducts.isEmpty()} {/if}
Item {#if order.pricesIncludeVat}Price{#else}Rate{/if} Qty Total
{#if item.productName}{item.productName}{#else}Product #{item.productId}{/if}
{#if item.variationId}
{#if item.variationName}{item.variationName}{#else}Variation #{item.variationId}{/if}
{/if} {#for m in item.modifierNames}
+ {m}
{/for}
{#if item.receiptUnitPrice(order)}{item.receiptUnitPrice(order).plainAmount}{/if} {item.quantity} {#if item.receiptLineTotal(order)}{item.receiptLineTotal(order).plainAmount}{/if}
Total qty {order.totalQuantity}
{#if order.amount && !order.pricesIncludeVat} {/if} {#if order.shippingTotal && order.shippingTotal.isPositive} {/if} {#if order.taxTotal && order.taxTotal.isPositive && !order.pricesIncludeVat && !order.taxOff} {/if} {#if order.couponTotalDiscount && order.couponTotalDiscount.isPositive} {/if} {#if order.hasPromotions} {#for p in order.promotionRows} {#if p.code}{/if} {/for} {/if} {#if order.total} {/if} {#if order.roundOffText} {/if} {#if order.hasPromotions} {/if} {#if order.hasTicketDiscount} {/if} {#if order.hasPointsDiscount} {/if}
Subtotal {order.amount.symbolFormatted}
Shipping {order.shippingTotal.symbolFormatted}
Tax {order.taxTotal.symbolFormatted}
Discount − {order.couponTotalDiscount.symbolFormatted}
Promotions
{p.name}− {p.saving.symbolFormatted}
Code {p.code}
Total {order.total.symbolFormatted}
Round off {order.roundOffText}
Amount paid {order.amountPaid.symbolFormatted}
You saved {order.youSavedFormatted}
Includes ticket discount {order.ticketDiscountText}
Includes points discount {order.pointsDiscountFormatted} ({order.pointsRedeemed} points)
{#if order.gstDocument && !order.gstRows.isEmpty()} {#for row in order.gstRows} {/for}
GSTTaxableAmount
{row.label}{row.taxable.plainAmount}{row.amount.plainAmount}
{#else if !order.vatRows.isEmpty()} {#for row in order.vatRows} {/for}
VAT rateNetVAT
{row.rate}{row.net.plainAmount}{row.vat.plainAmount}
{/if} {#if order.shippingAddress}
Ship to
{#if order.shippingAddress.recipientName}
{order.shippingAddress.recipientName}
{/if} {#if order.shippingAddress.line1}
{order.shippingAddress.line1}
{/if} {#if order.shippingAddress.line2}
{order.shippingAddress.line2}
{/if}
{#if order.shippingAddress.city}{order.shippingAddress.city}{/if}{#if order.shippingAddress.stateName}, {order.shippingAddress.stateName}{/if}{#if order.shippingAddress.postalCode} {order.shippingAddress.postalCode}{/if}
{#if order.shippingAddress.countryName}
{order.shippingAddress.countryName}
{/if} {#if order.shippingAddress.phone}
{order.shippingAddress.phone}
{/if}
{/if}