Skip to main content

Advanced PDF Templates

Create professional, branded PDF documents for invoices, purchase orders, and other transactions.


Overview

ADVANCED PDF TEMPLATE SYSTEM
-------------------------------------------------------------------------------

What It Is:
- Built-in PDF template engine using BFO (Big Faceless Organization)
- XML/FreeMarker-based templates
- Access to record data via template variables
- CSS-like styling support

Best For:
- Custom invoice layouts
- Branded purchase orders
- Professional packing slips
- Customer statements
- Any standard transaction document

Navigation: Customization > Forms > Advanced PDF/HTML Templates

Step-by-Step Tutorials

Tutorial 1: Creating Your First Advanced PDF Template

Goal: Create a custom invoice template from scratch.

Step 1: Navigate to Advanced PDF Templates

NAVIGATION PATH
-------------------------------------------------------------------------------

Home > Customization > Forms > Advanced PDF/HTML Templates

+-----------------------------------------------------------------------------+
| ADVANCED PDF/HTML TEMPLATES [New] [Import] |
+-----------------------------------------------------------------------------+
| Name | Type | Transaction | Preferred |
+-------------------------+----------------+-----------------+---------------+
| Standard Invoice | Transaction | Invoice | Yes |
| Standard Sales Order | Transaction | Sales Order | Yes |
| Custom Invoice - A | Transaction | Invoice | No |
+-----------------------------------------------------------------------------+

Click [New] to create a new template

Step 2: Configure Template Settings

NEW ADVANCED PDF/HTML TEMPLATE
-------------------------------------------------------------------------------

+-----------------------------------------------------------------------------+
| PRIMARY INFORMATION |
+-----------------------------------------------------------------------------+
| |
| Name*: [My Custom Invoice ] |
| |
| Type*: [Transaction v] |
| Options: Transaction, Statement, Custom |
| |
| Transaction*: [Invoice v] |
| (Only shows when Type = Transaction) |
| |
+-----------------------------------------------------------------------------+
| PREFERENCES |
+-----------------------------------------------------------------------------+
| |
| [ ] Preferred |
| Check to make this the DEFAULT template for this transaction type |
| |
| [x] Available Without Login |
| Allow access via public links (customer portal) |
| |
+-----------------------------------------------------------------------------+

[!IMPORTANT] Only ONE template can be marked "Preferred" per transaction type. The preferred template is used when no specific template is assigned to a form.

Step 3: Enter Template Content

TEMPLATE EDITOR TAB
-------------------------------------------------------------------------------

The editor provides a text area for XML/FreeMarker code:

+-----------------------------------------------------------------------------+
| SOURCE CODE EDITOR |
+-----------------------------------------------------------------------------+
| |
| <?xml version="1.0"?> |
| <!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd"> |
| <pdf> |
| <head> |
| <link name="NotoSans" type="font" subtype="truetype" |
| src="${nsfont.NotoSans_Regular}" /> |
| <style type="text/css"> |
| body { font-family: NotoSans, sans-serif; font-size: 10pt; } |
| .header { font-size: 18pt; font-weight: bold; } |
| .right { text-align: right; } |
| </style> |
| </head> |
| <body size="Letter" padding="0.5in"> |
| <h1 class="header">INVOICE</h1> |
| <p>Invoice #: ${record.tranid}</p> |
| <p>Date: ${record.trandate}</p> |
| <p>Customer: ${record.entity}</p> |
| </body> |
| </pdf> |
| |
+-----------------------------------------------------------------------------+
| [Save] [Preview] [Cancel] |
+-----------------------------------------------------------------------------+

Step 4: Preview Your Template

PREVIEW WORKFLOW
-------------------------------------------------------------------------------

1. Click [Preview] button
2. Select a real transaction to use as sample data:

+-----------------------------------------------------------------------+
| SELECT PREVIEW TRANSACTION |
+-----------------------------------------------------------------------+
| |
| Transaction Type: Invoice |
| |
| Select Transaction: [INV-00123 - ABC Corp v] |
| |
| [Preview] [Cancel] |
+-----------------------------------------------------------------------+

3. PDF opens in new browser tab/window
4. Review and iterate until satisfied

Step 5: Save the Template

After previewing:

1. Click [Save] to save the template
2. Template now appears in the list
3. Status: Not yet linked to any form (we'll do that next)

Tutorial 2: Linking Template to a Custom Form

Goal: Make your custom template appear when printing from a specific transaction form.

Step 1: Navigate to Transaction Forms

NAVIGATION PATH
-------------------------------------------------------------------------------

For Invoice forms:
Customization > Forms > Transaction Forms

Filter by: [Invoice v]

+-----------------------------------------------------------------------------+
| TRANSACTION FORMS [New] [Customize] |
+-----------------------------------------------------------------------------+
| Name | Type | Preferred | Standard | |
+---------------------------+-----------+-----------+----------+-------------+
| Standard Invoice Form | Invoice | Yes | Yes | [Customize] |
| Custom Invoice - Retail | Invoice | No | No | [Edit] |
| Custom Invoice - Wholesale| Invoice | No | No | [Edit] |
+-----------------------------------------------------------------------------+

Step 2: Edit/Customize the Form

EDITING A TRANSACTION FORM
-------------------------------------------------------------------------------

Click [Edit] on your custom form (or [Customize] on a standard form)

+-----------------------------------------------------------------------------+
| TRANSACTION FORM: Custom Invoice - Retail |
+-----------------------------------------------------------------------------+
| [MAIN] [SCREEN FIELDS] [ACTIONS] [PRINTING] [ROLES] |
+-----------------------------------------------------------------------------+

Click the [PRINTING] tab

Step 3: Assign PDF Template (THE KEY STEP)

PRINTING TAB
-------------------------------------------------------------------------------

+-----------------------------------------------------------------------------+
| PRINTING OPTIONS |
+-----------------------------------------------------------------------------+
| |
| Print Template: |
| +-------------------------------------------------------------------------+ |
| | ADVANCED TEMPLATE*: [My Custom Invoice v] <-- SELECT HERE | |
| | | |
| | Options: | |
| | - Standard Invoice (default) | |
| | - My Custom Invoice <-- Your new template | |
| | - Custom Invoice - Premium | |
| +-------------------------------------------------------------------------+ |
| |
| HTML Template: [Standard Invoice HTML v] |
| (For email body, screen display) |
| |
| [ ] Enable Transaction Printing |
| Allows printing directly from transaction |
| |
| [x] Show Print Button |
| |
+-----------------------------------------------------------------------------+
| [Save] [Cancel] |
+-----------------------------------------------------------------------------+

[!TIP] The Advanced Template field determines which PDF template is used when:

  • User clicks "Print" on the transaction
  • User selects "PDF" output
  • System generates documents for email

Step 4: Save and Test

TESTING THE LINK
-------------------------------------------------------------------------------

1. Save the form
2. Open an Invoice that uses this form
3. Click Actions > Print (or the Print button)

+-----------------------------------------------------------------------+
| PRINT OPTIONS |
+-----------------------------------------------------------------------+
| |
| Output Format: |
| (o) PDF |
| ( ) HTML |
| |
| Template: My Custom Invoice (auto-selected from form) |
| |
| [Print] [Cancel] |
+-----------------------------------------------------------------------+

4. Your custom template should render!

Tutorial 3: Creating Form-Specific Templates

Scenario: Different customer types need different invoice layouts.

MULTIPLE FORMS, MULTIPLE TEMPLATES
-------------------------------------------------------------------------------

RETAIL CUSTOMERS WHOLESALE CUSTOMERS
------------------- --------------------

Form: Invoice - Retail Form: Invoice - Wholesale
| |
+--> Template: Invoice-Retail-PDF +--> Template: Invoice-Wholesale-PDF
- Simple layout - Detailed pricing
- Consumer-friendly - Volume discounts shown
- Payment QR code - Terms & conditions

When user selects form, When user selects form,
matching template auto-applies matching template auto-applies

Implementation Steps

STEP 1: Create Both Templates
-------------------------------------------------------------------------------

Template 1: Invoice-Retail-PDF
- Type: Transaction
- Transaction: Invoice
- Preferred: No

Template 2: Invoice-Wholesale-PDF
- Type: Transaction
- Transaction: Invoice
- Preferred: No


STEP 2: Create Both Forms
-------------------------------------------------------------------------------

Form 1: Invoice - Retail
- Customize Standard Invoice Form
- Printing Tab > Advanced Template: Invoice-Retail-PDF
- Roles Tab: Assign to Sales - Retail role

Form 2: Invoice - Wholesale
- Customize Standard Invoice Form
- Printing Tab > Advanced Template: Invoice-Wholesale-PDF
- Roles Tab: Assign to Sales - Wholesale role


RESULT:
-------------------------------------------------------------------------------

+-- User with "Sales - Retail" role
| +-- Creates Invoice
| +-- Form auto-selected: Invoice - Retail
| +-- Print uses: Invoice-Retail-PDF
|
+-- User with "Sales - Wholesale" role
+-- Creates Invoice
+-- Form auto-selected: Invoice - Wholesale
+-- Print uses: Invoice-Wholesale-PDF

Linked Form Templates - Special Cases

Case 1: Subsidiary-Specific Templates

Scenario: Each subsidiary has different branding/logos.

SUBSIDIARY-BASED TEMPLATES
-------------------------------------------------------------------------------

Parent Company (Subsidiary ID: 1)
+-- Form: Invoice - Parent
| +-- Template: Invoice-Parent-PDF (Parent logo, US address)
|
+-- Subsidiary A (ID: 2)
| +-- Form: Invoice - Sub A
| +-- Template: Invoice-SubA-PDF (Sub A logo, UK address)
|
+-- Subsidiary B (ID: 3)
+-- Form: Invoice - Sub B
+-- Template: Invoice-SubB-PDF (Sub B logo, EU address)

Configuration Steps

1. Create template for each subsidiary:
- Invoice-Parent-PDF
- Invoice-SubA-PDF
- Invoice-SubB-PDF

2. Create form for each subsidiary:
Customization > Forms > Transaction Forms > Customize Standard Invoice

Form: Invoice - Parent
Main Tab:
Subsidiary: [Parent Company]
Printing Tab:
Advanced Template: [Invoice-Parent-PDF]

Form: Invoice - Sub A
Main Tab:
Subsidiary: [Subsidiary A]
Printing Tab:
Advanced Template: [Invoice-SubA-PDF]

3. Result:
Transactions for each subsidiary automatically use the correct form/template

Case 2: Customer-Specific Templates via Script

Scenario: VIP customers get a premium invoice layout.

/**
* User Event Script - Dynamic Template Selection
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/record', 'N/render'], function(record, render) {

function beforeLoad(context) {
if (context.type !== context.UserEventType.PRINT) return;

var invoice = context.newRecord;
var customerId = invoice.getValue('entity');

// Load customer to check VIP status
var customer = record.load({
type: record.Type.CUSTOMER,
id: customerId
});

var isVIP = customer.getValue('custentity_vip_customer');

if (isVIP) {
// Override the template for VIP customers
var vipTemplate = render.mergeEmail({
templateId: 'custpdf_vip_invoice' // Custom template internal ID
});
// Apply custom rendering logic
}
}

return {
beforeLoad: beforeLoad
};
});

Case 3: Conditional Template Based on Transaction Data

Scenario: Orders over $10,000 need additional terms and signature block.

/**
* Template with FreeMarker Conditional Logic
* This is handled WITHIN the template itself
*/
<?xml version="1.0"?>
<!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd">
<pdf>
<head>
<style type="text/css">
.terms { font-size: 8pt; border: 1px solid #ccc; padding: 10px; }
.signature { border-top: 1px solid black; width: 200px; margin-top: 50px; }
</style>
</head>
<body size="Letter">

<!-- Standard invoice content -->
<h1>INVOICE</h1>
<p>Invoice #: ${record.tranid}</p>
<p>Total: ${record.total}</p>

<!-- CONDITIONAL: Show extended terms for orders over $10,000 -->
<#if record.total?number gt 10000>
<div class="terms">
<h3>Extended Payment Terms</h3>
<p>For orders exceeding $10,000, the following terms apply:</p>
<ul>
<li>50% due upon signing</li>
<li>50% due upon delivery</li>
<li>Net 30 applies to remaining balance</li>
</ul>
</div>

<div class="signature">
<p>Customer Signature: ___________________</p>
<p>Date: ___________________</p>
</div>
</#if>

</body>
</pdf>

Case 4: Default Template vs Form Template Priority

TEMPLATE PRIORITY ORDER
-------------------------------------------------------------------------------

When printing, NetSuite selects templates in this order:

1. FORM-ASSIGNED TEMPLATE (highest priority)
| If form has "Advanced Template" set in Printing tab,
| that template is used.
|
+-- If no form template...
|
2. PREFERRED TEMPLATE
| Template marked as "Preferred" for that transaction type
| (only one per type)
|
+-- If no preferred template...
|
3. STANDARD TEMPLATE (lowest priority)
NetSuite's built-in default template

Case 5: Multiple Transaction Types in One Template

Scenario: Unified template for all sales documents.

<?xml version="1.0"?>
<!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd">
<pdf>
<body>
<!-- Dynamic title based on transaction type -->
<#if record.type == "invoice">
<h1>INVOICE</h1>
<#elseif record.type == "salesorder">
<h1>SALES ORDER</h1>
<#elseif record.type == "estimate">
<h1>QUOTE</h1>
<#else>
<h1>DOCUMENT</h1>
</#if>

<!-- Common content for all types -->
<p>Document #: ${record.tranid}</p>
<p>Date: ${record.trandate}</p>
<p>Customer: ${record.entity}</p>

<!-- Items table (common structure) -->
<table>
<#list record.item as item>
<tr>
<td>${item.item}</td>
<td>${item.quantity}</td>
<td>${item.rate}</td>
<td>${item.amount}</td>
</tr>
</#list>
</table>

<!-- Transaction-specific footer -->
<#if record.type == "invoice">
<p>Payment Due: ${record.duedate}</p>
<#elseif record.type == "salesorder">
<p>Expected Ship Date: ${record.shipdate!""}</p>
</#if>
</body>
</pdf>

Template Structure Reference

Basic XML Structure

<?xml version="1.0"?>
<!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd">
<pdf>
<head>
<!-- Font definitions -->
<link name="NotoSans" type="font" subtype="truetype"
src="${nsfont.NotoSans_Regular}" />
<link name="NotoSansBold" type="font" subtype="truetype"
src="${nsfont.NotoSans_Bold}" />

<!-- CSS styling -->
<style type="text/css">
body {
font-family: NotoSans, sans-serif;
font-size: 10pt;
}
/* More styles... */
</style>
</head>

<body size="Letter" padding="0.5in 0.5in 0.5in 0.5in">
<!-- Template content here -->
</body>
</pdf>

Available Fonts

Font NameVariable
NotoSans Regular${nsfont.NotoSans_Regular}
NotoSans Bold${nsfont.NotoSans_Bold}
NotoSans Italic${nsfont.NotoSans_Italic}
NotoSans CJK (Chinese/Japanese/Korean)${nsfont.NotoSansCJK_Regular}

Page Sizes

SizeDimensions
Letter8.5" x 11"
A4210mm x 297mm
Legal8.5" x 14"
Tabloid11" x 17"

Common Template Variables

Transaction Header Fields

HEADER FIELDS
-------------------------------------------------------------------------------

| Variable | Description |
|-----------------------------|-----------------------------------------------|
| ${record.tranid} | Transaction number (INV-00001) |
| ${record.trandate} | Transaction date |
| ${record.entity} | Customer/Vendor name |
| ${record.status} | Transaction status |
| ${record.memo} | Memo field |
| ${record.subsidiary} | Subsidiary name |
| ${record@type} | Record type (invoice, salesorder, etc.) |

Address Fields

ADDRESS FIELDS
-------------------------------------------------------------------------------

Billing Address:
| ${record.billaddress} | Full formatted address |
| ${record.billaddressee} | Addressee name |
| ${record.billaddr1} | Address line 1 |
| ${record.billaddr2} | Address line 2 |
| ${record.billcity} | City |
| ${record.billstate} | State/Province |
| ${record.billzip} | Postal code |
| ${record.billcountry} | Country |

Shipping Address:
| ${record.shipaddress} | Full formatted address |
| ${record.shipaddressee} | Addressee name |
| ${record.shipaddr1} | Address line 1 |
| ... (same pattern as billing) |

Line Items

<!-- Loop through item lines -->
<#list record.item as item>
<tr>
<td>${item.item}</td> <!-- Item name -->
<td>${item.description}</td> <!-- Description -->
<td>${item.quantity}</td> <!-- Quantity -->
<td>${item.units}</td> <!-- UoM -->
<td>${item.rate}</td> <!-- Unit price -->
<td>${item.amount}</td> <!-- Line total -->
<td>${item.taxcode}</td> <!-- Tax code -->
<td>${item.custcol_field}</td> <!-- Custom column field -->
</tr>
</#list>

Custom Fields

CUSTOM FIELD ACCESS
-------------------------------------------------------------------------------

Body Fields (custbody_xxx):
${record.custbody_po_number}
${record.custbody_project_name}
${record.custbody_shipping_method}

Column Fields (custcol_xxx) - inside item loop:
${item.custcol_serial_number}
${item.custcol_lot_number}
${item.custcol_warranty_date}

Custom Record Fields:
${record.custrecord_xxx}

Including Custom Record Data in PDFs

Accessing Custom Records

When a transaction has a field linked to a custom record, access it using the @ syntax:

<!-- If custbody_project links to a custom record -->
<p>Project Name: ${record.custbody_project}</p>
<p>Project Manager: ${record.custbody_project@custrecord_proj_manager}</p>
<p>Project Code: ${record.custbody_project@custrecord_proj_code}</p>

Use recmach prefix to access child records where "Record is Parent" is checked:

<!-- List shipping instructions attached to this transaction -->
<#if record.recmachcustrecord_si_transaction?has_content>
<h3>Shipping Instructions</h3>
<table>
<tr>
<th>Type</th>
<th>Description</th>
<th>Priority</th>
</tr>
<#list record.recmachcustrecord_si_transaction as instruction>
<tr>
<td>${instruction.custrecord_si_type}</td>
<td>${instruction.custrecord_si_desc}</td>
<td>${instruction.custrecord_si_priority}</td>
</tr>
</#list>
</table>
</#if>

[!NOTE] The recmach prefix is followed by the field ID on the child record that links to the parent (the "Record is Parent" field).

Complete Example: Invoice with Custom Gift Items

<?xml version="1.0"?>
<!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd">
<pdf>
<head>
<link name="NotoSans" type="font" subtype="truetype"
src="${nsfont.NotoSans_Regular}" />
<style type="text/css">
body { font-family: NotoSans; font-size: 10pt; }
.gift-table { background: #fffbe6; border: 1px solid #ffc107; }
.gift-table th { background: #ffc107; }
</style>
</head>
<body size="Letter" padding="0.5in">

<h1>INVOICE ${record.tranid}</h1>

<!-- Standard Items -->
<h3>Items Ordered</h3>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th><th>Total</th></tr>
<#list record.item as item>
<tr>
<td>${item.item}</td>
<td>${item.quantity}</td>
<td>${item.rate}</td>
<td>${item.amount}</td>
</tr>
</#list>
</table>

<!-- Custom Record: Gift Items (linked via recmach) -->
<#if record.recmachcustrecord_gift_transaction?has_content>
<h3>Complimentary Gift Items</h3>
<table class="gift-table">
<tr><th>Gift</th><th>Message</th></tr>
<#list record.recmachcustrecord_gift_transaction as gift>
<tr>
<td>${gift.name}</td>
<td>${gift.custrecord_gift_message!""}</td>
</tr>
</#list>
</table>
</#if>

</body>
</pdf>

Troubleshooting

Common Issues

IssueCauseSolution
Template not showing in formTemplate not saved or wrong typeVerify template Type matches form's transaction
Variables show as ${...}Typo in variable nameCheck exact field ID in Records Catalog
Page breaks unexpectedlyContent overflowsAdd page-break-inside: avoid CSS
Images not loadingWrong path or permissionsUse /images/ File Cabinet path
Fonts not renderingFont not linkedAdd <link> in <head> section

Debug Tips

<!-- Debug: Show all available fields -->
<#list record?keys as key>
<p>${key}: ${record[key]!""}</p>
</#list>

<!-- Debug: Check if field exists -->
<#if record.custbody_myfield??>
<p>Field exists: ${record.custbody_myfield}</p>
<#else>
<p>Field does not exist or is null</p>
</#if>

Best Practices

  1. Always test with real data - Use Preview with actual transactions
  2. Use null-safe access - ${field!""} or ${field!"Default"}
  3. Organize CSS in <head> - Keep styling separate from content
  4. Use classes not inline styles - Easier maintenance
  5. Consider page breaks - Plan for multi-page documents
  6. Test all subsidiaries - Verify currency, addresses, logos
  7. Version your templates - Use naming like Invoice-v2, Invoice-v3

References