PDF Templates
The PDF Templates screen is the library of reusable PDF layouts that NomaUBL applies when rendering an invoice. Every layout is a pdf-template resource saved in config-pdf.json; document templates pick a layout by name via their pdfTemplate property — so a single layout can be shared across many documents.
The page covers four operations:
- manage the catalogue (Add / Import / Copy / Remove);
- edit a layout via the visual builder — a full-screen editor with the section catalogue on the left, a live preview in the centre and an inspector on the right;
- mark a default for documents that don't pick an explicit layout;
- load a real invoice XML into the builder so the preview and the XPath autocomplete switch to your data.
The page applies regardless of source system — JD Edwards, SAP, NetSuite or a custom ERP — since the input it consumes is the generated UBL 2.1, not the source XML.
PDF templates were previously edited inline on the Documents page (the PDF Template tab) and lived in the document template's properties. They are now first-class shareable resources with their own page. The Documents tab still exists, but it now picks a layout by name from this page's catalogue rather than holding the JSON inline.
Opening the page
- Sidebar → Management → PDF Templates.
- The page lists every layout in the catalogue. The sidebar entry
built-inis the bundled factory layout — read-only, always present as a safety fallback. - The current default layout — i.e. what a document with no explicit
pdfTemplateresolves to — is marked with a yellow ★ in the sidebar.
At a glance
The page splits into a left catalogue of saved layouts and a right summary panel for the selected layout. Editing a layout opens the visual builder — a full-screen, three-pane editor documented under Visual builder below — and the layout is saved to the catalogue under a name.
How a layout is resolved
When NomaUBL renders a PDF for an invoice, it walks a three-step chain to choose the layout:
- The document template of that invoice (read from
F564231.UHTMPL) carries apdfTemplateproperty — if set, that name is used. - Otherwise, the
defaultPdfTemplateproperty on theglobaltemplate is used — set from this page via the Set as default button. - Otherwise, the bundled
built-inlayout is used — always present, never deletable.
The third step is the safety net: a freshly installed environment renders sensible PDFs even before any layout is created.
Toolbar actions
The toolbar at the top of the page covers the catalogue lifecycle plus the default override.
| Action | Effect |
|---|---|
| Open visual builder | Opens the selected layout in the full-screen visual builder — palette on the left, live preview in the centre, inspector on the right. The primary editing surface. |
| Add | Opens a modal asking for a name and a description. Creates an empty pdf-template resource — start by adding sections in the builder. |
| Import | Loads a JSON file produced by another instance (or the Export action). Updates the matching template if the name already exists, otherwise creates it. The reserved name built-in is rejected. |
| Copy | Duplicates the selected layout under a new name. The fastest way to derive a variant from built-in or from an existing customer-specific template. |
| Remove | Deletes the selected layout after a confirmation. Disabled on built-in. |
| Set as default | Writes the selected layout's name into global.defaultPdfTemplate. Documents without an explicit pdfTemplate then resolve to this layout. |
| Reset to factory | Clears global.defaultPdfTemplate, restoring the chain to built-in. |
The catalogue
The sidebar list contains every saved layout plus the bundled built-in.
built-in— pinned to the top, read-only, marked with afactorybadge. Selecting it opens the editor in a banner-tagged read-only mode. Copy is the only way to derive an editable layout from it.- ★ marker — the layout currently used as the default for documents with no explicit
pdfTemplate. Exactly one layout carries the star at any time. - Description — free-text label persisted on the resource. Surfaced both in the sidebar and in the PDF Template selector on a document template.
Visual builder
The Open visual builder button opens the layout in a full-screen editor with three panes side-by-side — the canonical way to edit a pdf-template. The old single-page flow (section list + per-section drawers, click a Preview button to open a modal) is gone; the builder unifies everything in one screen with the preview always visible.
The three panes:
| Pane | What it carries |
|---|---|
| Left — palette + section list | Top half: the catalogue of available sections (Header, Parties, Line Table, Payment, Notes, Custom block, …). Click to add to the template. Bottom half: the ordered list of sections in this template. Click to select; drag the ⋮⋮ handle to reorder. |
| Centre — live preview | Renders the current template against a bundled sample invoice (or the operator's loaded XML) and re-renders on every change — toggling a checkbox, adding a section, editing a custom-block node all reflect in the preview in milliseconds. Clicking any block in the preview selects it; the inspector on the right jumps to the matching options. |
| Right — inspector | Shows the selected section's options grouped by category (Supplier, Invoice metadata, Columns, …). For a Custom block, the full block tree editor — text, field, row / column, repeat, conditional — opens directly in this pane with XPath autocomplete and per-node font / colour / alignment. |
Loading a real invoice
The ↑ Load XML sample button at the top of the builder accepts a real UBL invoice (drag-and-drop or file picker). Once loaded:
- The live preview switches to your data immediately.
- The XPath autocomplete inside the custom-block editor uses your XML — the dropdown suggestions match the elements your invoice actually carries.
The sample is per-session, not persisted with the template. Reopening the builder reverts to the bundled sample.
Save and discard
The top-right Save button persists the template directly from the builder. Close (the ✕ button) shows a Discard / Cancel confirmation when there are unsaved changes — closing without confirming is not possible. The Discard path drops every edit since the last save; Cancel keeps you in the builder.
Two kinds of sections
A layout is a list of sections. Two flavours can be mixed in the same template.
Preset sections — the curated layout building blocks
Nine reorderable preset sections cover the canonical shape of an invoice PDF: Header, Parties, Agent, Line Table, Document Allowances, VAT Breakdown, Totals, Payment, Notes. Each one is backed by a Java class that knows how to render the matching part of an EN 16931 invoice; the user controls visibility via per-section toggles in the inline drawer.
The drawer groups toggles by Category · Name prefix and arranges them in side-by-side columns that mirror the PDF layout itself — Header reads as METAS | SUPPLIERS, Line Table as Group headers | Columns | Sub-details — instead of one long flat list. Toggles use the rounded-blue Checkbox component for visual consistency in dark mode.
The full list of toggles per preset section:
- Header — eight
META · …toggles (invoice number, issue date, due date, contract / order / buyer references, invoice type, profile ID) plus sixSupplier · …toggles (address, SIREN, legal form, VAT, phone, email). - Parties — Customer and Delivery boxes, with separate toggles for SIREN, VAT, address, location ID and a Show Delivery box master switch (when off, the layout renders a single-column Customer block). The Delivery box shows the delivery party name (falling back to
ID: …when only the location ID is set), the full street, postal code + city and country code — matching the Customer box. - Line Table — group-header toggles (Delivery group, Page break per delivery, Document Reference group and, (2026.06.14), Group by customer order — a third band below the delivery and document-reference bands, showing the referenced customer-order ID, BT-132), seven column toggles (
Line #,Description,Quantity,Unit,Unit Price,Amount,Tax) and seven sub-detail toggles for line metadata (BT-127, BT-134/135, BT-156, BT-157, BT-158, allowances / charges, additional item properties). The customer-order band follows the same reset rules as the others: a new delivery re-prints both inner breadcrumbs, a new document reference re-prints the customer-order band. - Document Allowances — column toggles for type, reason, amount, tax.
- VAT Breakdown — column toggles for category, rate, taxable, tax amount (an exemption column auto-appears when present).
- Totals — seven row toggles covering the full totals stack (Total HT, Allowances, Charges, Tax Exclusive, Total Tax, Total TTC, Amount Payable).
- Payment — payment means / IBAN / BIC / payment-terms note toggles.
- Notes — single toggle to expand
[PMD]/[PMT]tag prefixes against the note-types catalogue.
Block sections — XPath-driven free-form composition
The new block section is an XPath-driven primitive that composes any layout the preset sections don't cover. A single block holds a tree of typed nodes:
| Kind | Use |
|---|---|
text | Literal string. |
field | Renders an XPath value, with an optional inline label and a format selector — date, currency, number, percent. |
image | Embed an image (logo, watermark, signature). |
spacer / hr | Vertical breathing room or a horizontal rule. |
row / column | Container with align (start / center / end) and gap controls. align: end and align: center shrink the row to ~50 % so a label + value pair stays grouped instead of stretching across the page. |
repeat | XPath returning a NodeList; the block's child is rendered once per match. |
if | XPath returning a boolean; the block's child is rendered when true, hidden otherwise. |
table | A rows × cols grid with optional cell borders and a styled header row. Setting xpath makes it iterate (one row per match), with the children acting as the per-row cell template. |
note | A Note (by code) block — pick a code from the note-types reference list; the renderer finds the cbc:Note carrying the matching #CODE# marker and prints its body in place. Lets you turn off the global Notes section and drop each note exactly where it belongs (header, between parties, near the totals, in a column). |
Several blocks can live in the same template — e.g. one for a French legal mention block, one for a structured payment-terms table, one for a watermark image. Each block carries a user-friendly name shown next to the section row in the editor, so a layout with three blocks reads as Block · payment-terms, Block · legal-mentions, Block · watermark.
XPath conventions inside a block
- The picker preserves the
cbc:/cac:namespace prefixes — required by the namespace-aware backend; a manually-typed XPath without a prefix simply will not match. - Picks are emitted as
/*/<full-path>so they're independent of the document root (the same path applies toInvoiceandCreditNote). - Inside an iterating ancestor (a
repeator atablewith anxpath), the picker further strips the iterator's path so child cells start with relative XPaths (cbc:TaxAmountinstead of/*/cac:TaxTotal/cac:TaxSubtotal/cbc:TaxAmount). This keeps row templates portable when the iterator changes.
Custom-block tree editor
When a Custom block section is selected inside the visual builder, the right pane switches from "checkbox toggles" to a full tree editor. It hosts everything the block needs in one place:
| Region of the inspector pane | Purpose |
|---|---|
| Tree | Indented view of every node in the block, with kind tags (text, field, repeat, table, …). Click a node to select it; the live preview in the centre highlights the matching region. |
| Node toolbar | Add child / wrap / unwrap / delete / move up / move down — operations applied to the currently selected node. The same operations are available via keyboard shortcuts. |
| Attributes form | Per-kind attribute form (XPath, label, format, alignment, gap, …) plus a Style sub-panel covering font, weight, size, colour, alignment and padding. |
| JSON escape hatch | A raw-JSON view of the current node — read-only by default, Edit JSON toggles in-place editing for advanced cases the form doesn't cover. |
A small but important detail at the top of the attributes form: a Kind select that morphs the selected node in place — turn a column into a repeat without deleting and re-adding it, the compatible attributes (children, style) are carried over by the transmuteKind helper. The same trick handles the common case of promoting a static layout block to an iterating one once the data shape is understood. The block-kind dropdown is sorted alphabetically.
The centre preview re-renders every keystroke — the iframe stays mounted and updates in place, so the operator sees the result without flicker as they edit XPaths or toggle styles. The ↑ Load XML sample button at the top of the builder feeds a single sample to the XPath autocomplete of every block in the template.
Template settings — builder toolbar
The builder toolbar carries a few settings applied to the whole layout:
| Setting | What it does |
|---|---|
| Accent | The accent colour for the section titles (CUSTOMER / DELIVERY), the highlighted total, the line-table header underline and the row-highlight background. Enter a 6-digit hex with or without #; the soft row-highlight tint is derived automatically. Empty keeps the default blue. |
| Date | The date pattern applied across the PDF — issue, due, period and per-line delivery dates. Choices: yyyy-MM-dd (default), dd/MM/yyyy, dd-MM-yyyy, MM/dd/yyyy, dd MMM yyyy, dd MMMM yyyy. |
| Show logo | Draws the company logo at the top of the supplier block on page 1. The file comes from Logo path in Settings → Global → Processing → PDF, where a Logo offset X (pt) also shifts it horizontally. PNG, JPG and GIF are supported. |
Section slots
Beyond the preset toggles, three preset sections expose named slots, each holding a full custom-block tree (text, field, row, column, table, repeat, if, note, …) edited in place with the same block builder. A slot drops a block exactly where you'd otherwise have no anchor, without inserting a standalone Block section between two built-ins:
| Section | Slots |
|---|---|
| Header | Left footer (under the supplier block) and Right footer (under Profile ID) — e.g. a TVA intra-UE line under the supplier address, or a payment-terms caption under Profile ID. |
| Parties | Customer footer and Delivery footer, embedded inside each party box (sharing its cell width and font). |
| Totals box | Before totals (above the totals table) and After totals (below). |
Slots, like the top-level block section, show in the inspector as a compact summary card with an Edit pill: clicking it hands the whole inspector pane to the block builder, with a ← Back · Section · Slot bar on top; selecting another section exits automatically.
REST API
The page reads and writes via the standard template endpoints — same routes used by every other resource type.
| Method + path | Purpose |
|---|---|
GET /api/templates | Lists all templates; the page filters by type = pdf-template. |
GET /api/templates/{name} | Loads one layout (the JSON sits in the template property). |
POST /api/templates | Creates a new layout (Add). |
POST /api/templates/{from}/copy/{to} | Duplicates (Copy). |
PUT /api/templates/{name} | Saves edits. |
DELETE /api/templates/{name} | Removes a layout. The reserved built-in is rejected. |
POST /api/pdf-templates/preview | Renders an arbitrary pdfTemplate JSON against a sample invoice — used by the live preview iframe. |
PUT /api/templates/global (with defaultPdfTemplate) | Behind Set as default / Reset to factory. |
Tips & best practices
- Start from
built-invia Copy. The factory layout is a solid baseline — derive variants by copying and tuning the toggles instead of starting from an empty template. - One layout, many documents. For each invoice variant (standard, credit note, recipient receipt …) prefer one shared layout over per-document inline JSON. The benefit is a single edit point when the legal mentions or the column set changes.
- Set a default early. Mark a layout as default before connecting customer-specific document templates — every new document then resolves to it implicitly, and the explicit
pdfTemplateproperty on a doc template stays reserved for genuine variants. - Use
blockfor what presets don't cover. Custom legal mentions, country-specific footers, structured signature blocks, watermarks — all best modelled as ablockrather than asked of an existing preset. - Iterate inside the visual builder. Toggling a section, then watching the centre preview re-render is the fastest way to converge on a layout — the live preview is always visible, no modal to open.
- Load a real XML once per session. The ↑ Load XML sample button at the top of the builder feeds the picker for every block — load it once and every XPath autocompletion uses your data.
- Don't delete
built-in. The button stays disabled on it for that reason — it is the safety fallback at the end of the resolution chain.