Templates are managed under Organization settings → Document templates.
Uploading a template
Drop an.html or .pdf file (at most 10 MB) on the upload area. The template is named after
the file, without its extension, and the flow action picks it by that name. Names are unique
within an organization: to replace a template, delete it and upload the new version.
Each template is checked when it is uploaded, so a broken one is refused there and then instead
of failing a flow run later:
- An HTML template must be valid Liquid. A syntax error is reported with its line number.
- An AcroForm must be a standard PDF form with at least one fillable field. XFA forms and PDFs without fields are refused.
What a template needs
Click a template in the list to see what a flow has to give it. For an AcroForm, that is the list of its form fields. The flow passes a map with one entry per field name. For an HTML template, the dialog has three parts:- Data to supply. The keys the map passed to the template must have, and what each holds: a single value, a map with certain fields, or a list of rows with certain fields.
- Placeholders. Every value the template reads, written as a path into that map.
[]marks a list:rows[].Amountis theAmountof each row. When the template reads a value under another name, that name is shown next to it. - Set by the template. Names the template creates itself with
{% assign %}or{% capture %}. The flow does not supply these.
rows[].Employee_Name (read as summary.Employee_Name),
rows[].Description and rows[].Amount (read as row.Description and row.Amount), and
employee.salary_currency (read as currency). summary and currency are set by the
template. The flow supplies two keys: employee and rows.
The placeholder list is read from the template’s text, so it is a strong hint rather than a
guarantee. A value read in an unusual way, for example through a name built at run time, may
not appear in it.
Rendering a template in a flow
Add a Flow Action and pick the Render HTML to PDF step:- Template: the HTML template to render.
- Data assign: the assign holding the map the template reads. Build it with Build Map, one row per key from Data to supply.
- File name, or File name assign to name each file from the data
(
payslip-1042.pdf). - Fail on missing values: stop when the template reads a value the data does not have, instead of printing it blank. The error names each missing value and its line in the template.
- Output assign: where the PDF is written, ready for an upload step.
employee, taken from the assign holding the
employee, and rows, taken from the assign holding the payslip lines (for example the rows read
from a CSV file).
Fill PDF form works the same way, with a Fields assign holding one entry per form field
instead of a data assign. Its Flatten option, on by default, bakes the values into the page so
the result can no longer be edited.
Employees and dated properties
An employee from Twine’s System Data can be passed to the template as it is. The template reads its properties by their Twine names, and each one prints the value valid today:@ in expressions:
A payslip printed after a change of bank account can show the account valid on the payment date
rather than today’s:
salary_currency. These are read
across all of the employee’s employments, so employee.salary_currency is the currency valid
today whichever employment it belongs to.
A property the employee has no value for prints blank, or stops the flow when Fail on missing
values is on. Use Twine’s property names (bank_iban), not the source system’s: the
employee data model lists them.
Writing HTML templates
Templates use Liquid:{{ ... }} prints a value and
{% ... %} holds logic such as if and for. Liquid’s standard filters are available, plus one
of Twine’s own:
moneyformats a number Swedish style:{{ row.Amount | money }}prints5838.42as5 838,42. Pass the number of decimals to change them:{{ row.Amount | money: 0 }}.
- Make the file self-contained. For security, rendering cannot fetch anything from the
internet. Put styles in a
<style>block and images in the file asdata:URIs. An external stylesheet, font or image is left out of the PDF, and the flow run log names each one. - Read the first row with
rows[0].rows.firstandrows.lastare not supported on lists. - An empty text value counts as true.
{% if row.Unit %}is true for an empty cell. Reading a CSV file turns blank cells into nothing by default, which counts as false. - Keep Liquid out of HTML comments. Liquid reads
{{and{%inside<!-- -->too, so a comment containing them is a syntax error. - Use print CSS for page layout.
@page { size: A4; margin: 20mm; }sets the paper size and margins, andpage-break-before: alwaysstarts a new page.