Skip to content

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:

SettingWhat it does
Template NameHow the template appears in dropdowns, including when choosing a template to email or print with.
Resource TypeThe 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.
ResourceThe 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:

BlockWhat it’s for
ParagraphText - fixed wording, placeholders, or a mix. The workhorse block.
StackA container that stacks its children vertically. Use it to group blocks that share a background, border or margin.
LoopRepeats its children once for every related record - one small block of content per line, per note, per step.
ColumnsPlaces blocks side by side.
TableA real table with a header row and one body row per related record. This is how line-item tables are built.
🖼️ImageYour logo or another stored image.
BarcodeA 1D or 2D barcode generated from any text or placeholder.
Page breakForces 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 * columns
  • auto - 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:

PipeResult
{{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)
Choicecondition ? 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)

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

ExpressionPrints
{{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.