On this page
PalmOrder print forms use Chunk Templates to insert data, format values, apply conditions and repeat lines. Chunk works in both HTML templates for PDFs and .prn templates for printers. In a PDF form, HTML and CSS define the layout. Chunk determines which data appears.
Start with the PDF form example. See Printing setup to transfer your template to a device.
Basic syntax
| Syntax | Purpose |
|---|---|
{$doc.number} | Insert a field value. |
{$doc.customer_name|html} | Insert text with HTML special characters escaped. |
{$row.price|decimal} | Display a number with two decimal places. |
{% if (…) %}…{% endif %} | Display a section when a condition matches. |
{% loop in $table as $row %}…{% endloop %} | Repeat a section for each document line. |
{!-- Comment --} | Add a comment that is omitted from the output. |
Plain text and HTML outside tags are preserved. Field and command names are case-sensitive. For example, doc.number and doc.Number are different names.
Fields and data groups
Use a dot to separate a group from its field.
<h1>Order No. {$doc.number|html}</h1>
<p>Date: {$doc.date_localized|html}</p>
<p>Customer: {$doc.customer_name|html}</p>
| Order data group | Contents |
|---|---|
doc | Header fields such as number, customer_name, sum and discount. date_localized is the date formatted for the locale. |
doc.customer | Customer reference fields such as doc.customer.code. |
we | Business details: company, address, registration, billing and comment. |
table | Document lines, accessed in a loop. |
row | The current line in a loop that uses as $row. |
row.product | Product reference fields for the current line. |
Use field names from your data schemas. For example, {$doc.customer.address|html} requires an address field in the customer reference and a matching customer record. Fill in the we values under Settings → Print → Business details.
Missing and empty values
A missing field can leave a tag such as {$doc.some_field} in the output. Add a default after a colon for a missing value, or leave the default empty to suppress the tag.
<p>Note: {$doc.info|html:Not provided}</p>
<p>{$doc.info|html:}</p>
Use onempty to handle both a missing field and an empty string.
<p>Note: {$doc.info|onempty(Not provided)|html}</p>
Use a condition to hide the whole paragraph, including its label.
Filters and formatting
A vertical bar (|) introduces a filter. Filters run from left to right, so {$doc.info|onempty(No note)|html} inserts a default and then escapes it for HTML.
| Filter | Example | Result |
|---|---|---|
html | {$row.name|html} | Escapes characters such as &, <, > and quotes for HTML. |
decimal | {$row.price|decimal} | Two decimal places, such as 42.50. |
number | {$row.count|number} | Up to six decimal places without unnecessary trailing zeros, such as 2.5. |
onempty(text) | {$doc.info|onempty(Not provided)|html} | Supplies text for a missing or empty value. |
trim | {$doc.customer_name|trim|html} | Removes whitespace at the start and end of the text. |
uc | {$we.company|uc|html} | Converts text to uppercase. |
lc | {$doc.customer.code|lc|html} | Converts text to lowercase. |
PalmOrder supplies decimal and number. Number separators depend on the device locale. Use html for text fields in HTML forms. Text .prn templates do not need HTML escaping.
A numeric field may also have an _display tag, such as {$row.count_display}, with precision taken from the column settings on the device.
Aligning text and numbers
PDF forms with HTML and CSS
Set text-align to left, center or right. For example, center the heading, align names to the left and align quantities and amounts to the right.
<h1 style="text-align: center;">Order No. {$doc.number|html}</h1>
<table style="width: 100%;">
<tbody>
{% loop in $table as $row %}
<tr>
<td style="text-align: left;">{$row.name|html}</td>
<td style="text-align: right;">{$row.count|number}</td>
<td style="text-align: right;">{$row.sum|decimal}</td>
</tr>
{% onEmpty %}
<tr>
<td colspan="3">There are no products in this order</td>
</tr>
{% endloop %}
</tbody>
</table>
For repeated styles, define classes in <style> as shown in the example HTML template.
Text forms with sprintf
The Chunk sprintf filter adds spaces to align columns in .prn files.
| Format | Example | Result |
|---|---|---|
%20s | {$row.name|sprintf(%20s)} | Right-aligned text in a field at least 20 characters wide. |
%-20s | {$row.name|sprintf(%-20s)} | Left-aligned text in a field at least 20 characters wide. |
%-20.20s | {$row.name|sprintf(%-20.20s)} | Left-aligned text limited to 20 characters, with spaces to fill the field. |
%10s | {$row.sum|decimal|sprintf(%10s)} | An amount with two decimal places, right-aligned in a field at least 10 characters wide. |
In %20s, 20 is the minimum width and s indicates text. The minus sign changes alignment to the left. The .20 part limits the text length. Without that limit, long values can shift the following columns.
{% loop in $table as $row %}
{$row.name|sprintf(%-20.20s)} {$row.count|number|sprintf(%8s)} {$row.sum|decimal|sprintf(%10s)}
{% onEmpty %}
There are no products in this order
{% endloop %}
With an English locale, a quantity of 2.5 and an amount of 125.00 produce the following line for Water.
Water 2.5 125.00
Format numbers before aligning them so the width applies to the displayed value. Use a monospaced printer font and keep the line within the printer's character capacity in the selected mode.
Conditions
For orders, doc.has_discount is 1 when the order has a discount.
{% if ($doc.has_discount == 1) %}
<p>Discount: {$doc.discount|decimal} UAH</p>
{% else %}
<p>No discount</p>
{% endif %}
The else branch is optional. Some templates use {% /if %} as an alternative closing tag.
| Operator | Meaning |
|---|---|
== | Values are equal. |
!= | Values differ. |
&& | Both conditions match. |
|| | At least one condition matches. |
!$field | The value is absent. |
Put text in double quotes and use parentheses to group conditions. Equality compares the string representation, so 1 and 1.0 differ. Conditions do not support ordinary numeric operators such as >, <, >= and <=.
Multiple branches and nested conditions
Use elseIf to check several alternatives. The first matching branch runs.
{% if ($we.company && $we.company != "") %}
<p>Supplier: {$we.company|html}</p>
{% elseIf ($we.registration && $we.registration != "") %}
<p>Supplier registration or tax number: {$we.registration|html}</p>
{% else %}
<p>Supplier details unavailable</p>
{% endif %}
Give each nested condition its own closing tag.
{% if ($we.company && $we.company != "") %}
<p>{$we.company|html}</p>
{% if ($we.address && $we.address != "") %}
<p>{$we.address|html}</p>
{% endif %}
{% endif %}
Hiding empty fields
{% if ($we.billing && $we.billing != "") %}
<p>Bank details: {$we.billing|html}</p>
{% endif %}
$we.billing checks that the field has a value, and $we.billing != "" excludes an empty string. A plain if ($field) also matches an empty string or zero. For an order's discount flag, use == 1.
Loops and document lines
The loop repeats its body for each record in table. The name after as identifies the current record. counter=$num,1 numbers records starting at 1, and onEmpty displays a section when there are no records.
<table>
<thead>
<tr><th>No.</th><th>Product</th><th>Quantity</th><th>Amount</th></tr>
</thead>
<tbody>
{% loop in $table as $row counter=$num,1 %}
<tr>
<td>{$num}</td>
<td>{$row.name|html}</td>
<td>{$row.count|number}</td>
<td>{$row.sum|decimal}</td>
</tr>
{% onEmpty %}
<tr><td colspan="4">There are no products in this order</td></tr>
{% endloop %}
</tbody>
</table>
The counter is optional. Add an onEmpty section to control what appears when there are no records. Without it, Chunk outputs an empty table error. Document header fields and conditions are available inside a loop. To hide a discount column, wrap both its header and its line cell in the same condition.
First and last line
Set first_last=true to make $first and $last available on the first and last record respectively. A single record has both flags. They apply to the full list of products.
{% loop in $table as $row first_last=true %}
{% if ($first) %}
<p>Product list:</p>
{% endif %}
<p>{$row.name|html}</p>
{% if ($last) %}
<p>End of list</p>
{% endif %}
{% onEmpty %}
<p>There are no products in this order</p>
{% endloop %}
Separator between records
Use divider to put a separator between records. It is omitted after the last record.
<p>
{% loop in $table as $row %}
{$row.name|html}
{% divider %}, {% enddivider %}
{% onEmpty %}—
{% endloop %}
</p>
Reusing fragments
Define a fragment between {#name} and {#} and insert it with include. The definition itself is omitted from the output. The fragment can use fields available at the point of insertion.
{#company_details}
<p>{$we.company|html}</p>
{% if ($we.address && $we.address != "") %}
<p>{$we.address|html}</p>
{% endif %}
{#}
{% include #company_details %}
<h1>Order No. {$doc.number|html}</h1>
{% include #company_details %}
To reuse a fragment across several forms, save it in a separate file such as common.chtml.
{#signature}
<p>Dispatched by: ____________________</p>
<p>Received by: ____________________</p>
{#}
Insert it in the main template.
{% include common#signature %}
Transfer common.chtml through the same exchange as the main template and keep the default storage location on the device. Use the base name common in include. PalmOrder's template loader looks for the .chtml file. Keep the main HTML template name in <file> in pdf_forms.xml.
Calculations
Use the PalmOrder po_calc filter for simple calculations. Use field names without $ inside the expression. It supports +, -, *, / and parentheses. Apply decimal or number to format the result.
<p>Half the total: {$doc.sum|po_calc(doc.sum/2)|decimal} UAH</p>
Use doc.sum, doc.discount and the line amounts for document totals so they reflect the application's discounts and rounding.
Comments
A Chunk comment is removed along with any tags inside it.
{!-- Display business details here. --}
<p>{$we.company|html}</p>
Checking a template
After updating the template, download it to the device and generate the form again. Check orders with and without business details and discounts, and with one or several products.
| Symptom | What to check |
|---|---|
A {$…} tag remains | Check the name and availability of the field. Use a default or a condition for optional fields. |
| A label appears with no value | Wrap the whole paragraph, including the label, in the condition. |
| A zero discount is shown | Check that the condition compares doc.has_discount with 1. |
| Product lines do not repeat | Check that the cells are inside the loop and refer to the current row. |
Text with & or < displays incorrectly | Check the html filter in the HTML template. |
| Incorrect decimal precision | Check decimal, number or the appropriate _display tag. |
| A fragment is missing | Check the name in include, the {#…} definition and whether the .chtml file was downloaded. |
Temporarily insert {% tagStack(html) %} in an HTML template to see tag names in the current context. You can also place it inside a loop. Remove it after checking the template.
The Chunk Templates documentation covers more of the language. The filters decimal, number and po_calc are specific to PalmOrder.
