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; documents 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.
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 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.
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 builder unifies everything in one screen with the preview always visible.
Coded fields render only their human label — invoice type, profile, payment method, note categories, document references and item identifiers no longer carry the raw code (Payment: Bank transfer, not Payment: 30 — Bank transfer; a note reads Payment information —, not [PMD] Payment information —). The codes stay in the UBL for machine processing.
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 — nine
META · …toggles (invoice number, issue date, due date, contract / despatch advice (BT-16) / 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 Group by order (EXT-FR-FE-135, EXT-FR-FE-144) — a third band below the delivery and document-reference bands, carrying the buyer's and the seller's order numbers on one line: Customer Order Reference: … Order number: …), an Order line reference (BT-132) toggle that prints the customer line number under each line — and, when order grouping is off, the two order numbers as detail rows too, column toggles (
Line #,Description,Quantity,Unit,Unit Price,Net unit price,Amount,Tax) — the Unit price column (BT-146) shows the price base quantity when it differs from 1 (40,49 / 100); the Net unit price column (line amount ÷ quantity, i.e. the price once line allowances and charges are folded in) is off by default, so the item price alone stays the standard layout. Sub-rows span the real column count, so hiding or adding columns never misaligns them. The line table also carries ten sub-detail toggles for line metadata (BT-127, BT-134/135, line despatch advice (EXT-FR-FE-BG-07), BT-155 — Seller's item code, BT-156, BT-157, BT-158, BT-159 — Country of origin (prints the country's full name resolved from the shared countries list — not the ISO code), allowances / charges, additional item properties). The 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 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 and Logo width / height (pt) set the box it is scaled to (ratio kept; blank = 200 × 80 points at most). The builder preview uses the same size as the produced PDF. PNG, JPG and GIF are supported. |
| Trim zeros | Drops trailing zero decimals from amounts, unit prices and quantities — a whole amount prints as 23 instead of 23.00, and a 23.0000 unit price prints as 23. Off by default, which keeps the fixed two-decimal amount and four-decimal price display. The setting is per template and applies to the line table, the totals box, and both the readable and on-screen PDFs. |
| Decimals — amount / price / qty | Decimals printed per kind of number, each auto or 0–6. Amount covers line amounts, allowances, VAT rows and totals; price covers the item price, the net unit price and the price discount; qty covers invoiced quantities. auto keeps the standard display (amounts 2 decimals, prices and quantities as in the UBL), so existing templates render unchanged. A fixed count is rounded half away from zero, as AFNOR requires; Trim zeros still applies on top. |
Labels
Every text the PDF generator prints — 46 labels across the document header, parties, lines table, line details, VAT summary, totals and payment — can be overridden per PDF template and per language. Open Labels in the Template group of the builder:
- each row shows the label key with an FR and an EN field; the default wording shows as placeholder, and a blank field keeps it;
- a Search… box and an Overridden only (N) filter help find a label; overridden keys are highlighted;
- × resets a row to the default, and Copy labels from… loads the overrides of another PDF template;
- the live preview reflects the overrides as you type.
A customer asking for N° de facture instead of N° facture UBL gets it on their template only; other templates keep the default wording. The full catalogue, with each key's default EN / FR text, is available from GET /api/pdf-templates/labels.
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 documents — 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.