PDF Template Editor
The PDF Template Editor lets you design your own layouts for any document Fast2Task can print. You build a template from blocks, drop in placeholders that pull live data from the document, and watch a preview update as you type.
Find it under Settings → PDF Template.
Every document type ships with a built-in default layout, so you only need this editor when you want something of your own: your branding, a different column set, extra calculated figures, or a layout a particular customer insists on.
Managing templates
The dropdown at the top of the page is where every template starts:
- An existing template - loads it for editing.
-- New Template --- an empty A4 template, ready to build from scratch.-- Duplicate Default for <document type> --- starts from Fast2Task’s built-in layout for that document type. This is almost always the best starting point: you get a working, properly laid out document and can change just the parts you care about.
The ⋮ menu next to the dropdown offers:
- Import/Export - shows the template as JSON. Copy it out to keep a backup or move a template between accounts; paste one in and choose Import Template to load it.
- Duplicate Template - makes a copy under a new name, so you can experiment without touching the original.
- Delete Template.
Changes are only kept when you press Save Template. Navigating away with unsaved changes prompts you first.
Template settings
Above the editor:
| Setting | What it does |
|---|---|
| Template Name | How the template appears in dropdowns, including when choosing a template to email or print with. |
| Resource Type | The document type this template is for - invoices, sales_orders, work_orders and so on. This decides which fields are available to placeholders, so set it before you start building. |
| Resource | The actual document used to fill in the live preview. Pick a real, representative one - an order with several lines, some tax and a discount will show up layout problems that an empty document won’t. |
Under Options:
- Page Width / Page Height (mm), with one-click A4 and A5 presets in portrait and landscape. Any size works, which is what makes label templates possible.
- Page Margins (points, in top, right, bottom, left order) - the printable area of every page.
- Header height and Footer height (points) - how much room is reserved at the top and bottom of every page for the header and footer regions. If header content is being clipped, increase this.
The three regions
The editor shows three stacked regions, each outlined in its own colour and matched by a tint in the preview when you hover over it:
- Header (cyan) - repeats at the top of every page.
- Body (green) - the document content. This is the part that flows and paginates.
- Footer (magenta) - repeats at the bottom of every page.
Header and footer sit inside the space you reserved with Header height / Footer height, so content taller than that gets clipped.
Blocks
Everything in a template is a block. The dropdown on each block’s toolbar changes what kind of block it is:
| Block | What it’s for | |
|---|---|---|
| ¶ | Paragraph | Text - fixed wording, placeholders, or a mix. The workhorse block. |
| ☰ | Stack | A container that stacks its children vertically. Use it to group blocks that share a background, border or margin. |
| ↻ | Loop | Repeats its children once for every related record - one small block of content per line, per note, per step. |
| ‖ | Columns | Places blocks side by side. |
| ⌗ | Table | A real table with a header row and one body row per related record. This is how line-item tables are built. |
| 🖼️ | Image | Your logo or another stored image. |
| ▮ | Barcode | A 1D or 2D barcode generated from any text or placeholder. |
| ⤓ | Page break | Forces everything after it onto a new page. |
Block toolbar
Each block carries the same small toolbar:
- Type dropdown - as above.
- ⁝⁝ Drag handle - drag the block to reorder it within its list. Hold Ctrl as you drop to copy rather than move it, which is the quickest way to duplicate a table column or a styled paragraph. A block can only be dropped into the list it came from.
- ✎ Settings - opens the block’s settings dialog (only shown for blocks that have settings).
- ▲ / ▼ - move the block up or down one place.
- ✕ - delete the block.
Paragraph
The Content field holds text, placeholders, or both - Order {{sales_order_number}} for {{client_name}}. Multiple lines are kept as written.
+ Add styled run splits the paragraph into inline runs: separate segments that sit on the same line but each carry their own bold, colour and font size. That’s how you get SALES ORDER in grey next to the order number in bold black, on one line.
Settings: bold, colour, font size, alignment (left / center / right / justify), line height, and margin.
Stack
A stack groups blocks vertically and can carry a fill colour, a border on any combination of its four edges with a colour per edge, and a margin. Stacks are how you build tinted panels and boxed sections.
Loop
Set Repeat for each (relationship) to a relationship on the current document - lines, notes, steps - and everything inside the loop is rendered once per related record. Inside the loop, placeholders resolve against that record, so {{product_name}} means the current line’s product.
Use a loop when a table isn’t the right shape: a block of several lines of text per record, a barcode per package, a signature area per step.
Columns
Each column has a Column Width:
*- share the leftover space equally with other*columnsauto- only as wide as its content- a number - a fixed width in points
Column Gap controls the spacing between them.
Table
The key setting is Body row relationship - the relationship whose records become the table’s rows, usually lines. Rows are rendered in the records’ saved order.
Each column has:
- a Column Width (
*,auto, or a number of points), - a header area (a stack, so it can hold styled text), and
- a body block that renders once per row, with placeholders resolving against that row.
Table settings:
- Layout - Light Horizontal Lines, Header Line Only, or No Borders.
- Fill colour.
- Zebra striping - alternating row shading, which makes long line tables much easier to read.
- Margin.
Image
Source is either Company logo (from config) - which always uses the logo from your account settings, so it stays right if you rebrand - or Account image, where you pick a specific stored image.
Size it with Width and/or Height in points, or with Fit: give a width and height and the image is scaled to fit inside that box while keeping its proportions. Fit is usually what you want for a logo, because it can’t distort.
Barcode
Content is any text or placeholder - {{barcode}}, {{sales_order_number}}, or a combination. Supported symbologies:
Code 128, Code 39, EAN-13, EAN-8, UPC-A, UPC-E, ITF-14, QR Code, Data Matrix, PDF417.
Image Width and Image Height (points) control the rendered size. If the content is empty the barcode renders as nothing rather than as an error.
Page break
Starts a new page. Inside a loop it fires once per repetition, which - combined with Show if - is how you get one page per record, or a break only after every third one.
Placeholders
A placeholder is anything inside double braces. At its simplest it’s a field name:
{{invoice_number}}{{client_name}}Reaching other records
Follow a relationship with a dot:
{{client.email}}{{product.description}}For many-to-many relationships, _pivot reaches the fields stored on the link itself:
{{_pivot.quantity_required}}You can also index into a list:
{{notes.0.note}}Company details
config. reads your account settings rather than the document:
{{config.email}}{{config.phone_number}}{{config.bank_account_number}}Page numbers
{{page_number}} {{page_count}}Finding fields
You rarely need to remember field names:
- Start typing inside
{{and an autocomplete list appears. Relationships are highlighted - pick one and it stays open so you can drill into the related record’s fields. - The magnifier button on any placeholder field opens the field browser, a full tree of the document’s fields and relationships. Click a field to insert it at your cursor.
Inside a table or loop, both of these automatically show the fields of the related record, because that’s what placeholders resolve against there.
Formatting
Add a | and a format name to control how a value is presented:
| Pipe | Result |
|---|---|
{{invoice_date | date}} | Date in your locale’s format |
{{created_at | datetime}} | Date and time |
{{amount | currency}} | Currency, in the document’s currency |
{{quantity | number:2}} | Number with thousands separators and 2 decimal places |
{{quantity | round:2}} | Rounded to 2 decimal places, no separators |
{{status | upper}} | UPPERCASE |
{{code | lower}} | lowercase |
Fields that Fast2Task already knows to be money, dates or times are formatted for you, so you only need a pipe when you want something different - or when you’ve calculated the value yourself.
Calculations
Placeholders can do arithmetic, not just look values up. This is how you print figures that aren’t stored anywhere: a back-ordered quantity, a saving against list price, a tax-inclusive total.
{{quantity - sum(fulfillments, quantity)}}{{unit_price * quantity | currency}}The field browser has a Maths & expressions panel with the full reference and clickable examples, so you don’t need to keep this page open while you work.
Operators
| Arithmetic | + - * / % |
| Comparison | < <= > >= == != |
| Logic | && (and) || (or) ! (not) |
| Choice | condition ? value_if_true : value_if_false |
| Grouping | ( ) |
Text can be joined with +, and quoted with ' or ":
{{'Ref ' + reference}}{{quantity > 0 ? 'IN STOCK' : 'OUT OF STOCK'}}Functions
Numbers
round(value, decimals) · floor(value) · ceil(value) · abs(value) · int(value) · number(value) · pow(value, power) · sqrt(value) · min(a, b) · max(a, b) · clamp(value, low, high)
Totals across related records
sum(relationship, expression) · avg(relationship, expression) · count(relationship, condition) · min(relationship, expression) · max(relationship, expression)
Logic and text
if(condition, then, else) · coalesce(a, b, …) · not(value) · len(value) · concat(a, b, …) · upper(text) · lower(text) · trim(text) · substr(text, start, length) · replace(text, find, replace_with) · contains(text, search)
Totalling related records
The aggregate functions take a relationship first and an expression evaluated for each of its records second:
{{sum(lines, amount) | currency}}{{sum(lines, quantity - sum(fulfillments, quantity))}}{{count(lines, quantity > sum(fulfillments, quantity))}}{{avg(lines, unit_price) | currency}}count used on its own just counts records: {{count(lines)}}.
These nest, as the second example shows - the total still to ship across an order is the sum, over every line, of that line’s ordered quantity minus everything already fulfilled against it.
Worked examples
| Expression | Prints |
|---|---|
{{quantity - sum(fulfillments, quantity)}} | Back-ordered quantity on an order line |
{{unit_price * quantity | currency}} | Line value before discount |
{{unit_price * quantity - amount | currency}} | What the discount saved |
{{round(discount_percentage * 100, 1)}}% | The discount as a percentage |
{{amount * (1 + tax_rate) | currency}} | Tax-inclusive line amount |
{{amount / (1 + tax_rate) | currency}} | Tax stripped out of a gross amount |
{{quantity > sum(fulfillments, quantity) ? 'BACK ORDER' : ''}} | A flag only on short-shipped lines |
{{clamp(quantity - sum(fulfillments, quantity), 0, 999999)}} | Back order, never negative |
If an expression can’t be worked out - a misspelt field, a stray bracket, a division by zero - the placeholder prints as blank rather than breaking the document. If something’s unexpectedly empty, that’s the first thing to check.
Conditional content
Every block has Show if and Hide if in its settings. Each takes a placeholder or expression; the block is included only when Show if is true and Hide if is not.
Show if: {{is_paid}}Hide if: {{is_tax_exempt}}Show if: {{amount > 0}}Show if: {{quantity > sum(fulfillments, quantity)}}Empty values, zero, and false all count as false; anything else counts as true.
This is what lets one template serve several situations - a “PAID IN FULL” stamp that only appears when it should, a discount column that vanishes when nothing is discounted, a back-order notice only on orders that have one.
Previewing and printing
The right-hand panel renders the template against the document you chose as Resource, and refreshes as you edit. It’s an approximation - good for layout, spacing, colours and checking your placeholders resolve - but it doesn’t paginate, so page breaks show as a dashed line and page numbers aren’t filled in.
Print generates the real PDF from the same template and document. Check anything that depends on pagination there.
Using your template
Once saved, a template can be:
- Chosen when emailing a document - the template dropdown in the send dialog.
- Set as a client’s default for a document type, on the client record. Any document of that type generated for that client uses their template automatically - useful for customers who require their own paperwork layout.
See Printing and Sending Documents for the sending side.
Tips
- Start from a duplicated default. Getting spacing and column widths right from an empty page takes far longer than adjusting a layout that already works.
- Preview against an awkward document - many lines, a long product description, a discount, a partial shipment. Templates usually break on the messy cases, not the tidy ones.
- Ctrl-drag to duplicate a table column or a styled paragraph rather than rebuilding it.
- Export the JSON before a big change. It’s the quickest way back if an experiment goes wrong, and it’s how you copy a template to another account.
- Reserve enough header and footer height. Clipped content is nearly always this rather than a layout bug.