This article is relevant if you are considering using NetSuite’s Advanced PDF/HTML Template technology to produce great looking documents.
Addendum
We are committed to this space. Since we published this article in 2013, we have developed a number of other articles and tools that are most relevant for NetSuite users working to get more out of the Advanced PDF/HTML tools:
- Interrogating NetSuite’s Advanced PDF / HTML Templates
- Supercharge NetSuite Advanced PDF/HTML Templates
- Solved: Custom NetSuite Item Fulfillment Ship Notifications
- Framework for Generating Custom NetSuite PDF Files
Background
NetSuite’s standard document generator is basic. For the most part, the supplied documents, such as invoices or statements, gets the job done. However, if you wanted more complex output formatting, you previously had to move to SuiteScript.
NetSuite uses a technology called “Big Faceless Organization” or “BFO” to enable PDF file generation driven by FreeMarker template engine. A popular add-on in the Java community, these libraries are all built-in for us to use inside NetSuite behind the scenes. Elements have been available to SuiteScript developers for a number of years through the SuiteScript nlapiXMLToPDF function call.
This also means that it has been beyond the reach of many NetSuite users. However, more recently, the basic framework without the need for SuiteScript has been exposed via the “Advanced PDF/HTML Templates” feature. Once you enable this feature, you can user this tool to design your own PDF files without SuiteScript programming.
General Orientation
The template technology uses a framework that combines both XML, HTML, CSS, and BFO tags to drive the PDF generation. I have a sample invoice and the source code to help you make sense of what is happening. Anyone with a good understanding of HTML and Cascading StyleSheets (CSS) should be able to get comfortable with this tool relatively quickly.
Header, Footer and Body Concepts
The first thing to realize is that NetSuite supplies sample templates with HTML snippets called a header, a footer and the body. These concepts are easy to understand when we are in a document orientation. These elements, which could have been named anything, are defined through a macro definition supplied by the BFO framework. The header and the footer then produce a page concept that repeats as the body content changes. The Body is meant to be where the main elements of your document (or report) is generated.
NetSuite Data References
The NetSuite documentation is still being developed. But here are some important concepts to understand:
- record: this is the primary data set you are referencing. If you are working with an invoice, you are effectively working with the equivalent of a transaction search and the results set of one invoice record object. Use the NetSuite Record Browser document located in Help for your field references.
- record.item: the record object has an item sublist, as well as others. The BFO framework has a way to setup loop in the document and then output the result. This tag “< #list record.item as item>” is a directive to trigger the framework to create a loop with the content located between the closing tag. It then supplies the “item” element information so you can reference the record’s sublist contents.
- companyInformation: this elements allows you to access the Company Information located under Setup, Company Information. For example, companyInformation.addressText will supply you your address defined globally. To get the field names, click the field label after you have activated Show Field IDs.
Subsidiary Information and One World
Unfortunately, the Subsidiary information is not accessible in the framework. Essentially, the Company Information is the root subsidiary. Most of the time, your child subsidiaries are your operating entities. You will likely want to reference the Subsidary information as it contains key information about your subsidiary such as address, Tax ID, telephone and contact information. Since you can’t reference the subsidiary records in the PDF framework, here is what you need to do:
- For every subsidiary field you care about, create an equivalent custom transaction body field.
- Source the default values for the custom field from the Subsidiary record.
- When the transaction record is created, the information will be copied from the Subsidiary and stored with the transaction.
- Reference this custom information now on the “record” object.
Ideally, all of the NetSuite elements would be exposed to the framework. However, this technique to source information from another table to your target table is a common practice when trying to expand features in NetSuite.
Trial and Error Development
I copy and paste the source code information between my favorite editor. The process is iterative so be prepared to go back and forth many times to get the results you are looking for.
I also recommend you make local backups of your source document to disk. The document format is XML — as such, the tag layout must be perfect for the document to be valid. If you mess it up as you develop, a common occurrence, it is helpful to have a copy of an old version that worked.
Summary
Creating your own document formats can trigger your customers to know they are working with a high caliber professional organization. The new NetSuite PDF / HTML framework puts powerful document formatting within reach of most users comfortable with HTML.
If you would like help enhancing your NetSuite account, contact us.
See Related Articles
- Extend Data to Native NetSuite Advanced PDFs without Script
- Learn the Framework to Extend NetSuite Content Generation
- Video: How to Extend Advanced PDFs with Content Renderer Engine
- How To: Password Protect NetSuite Generated PDF Files
- Supercharge NetSuite Advanced PDF/HTML Templates
- Interrogating NetSuite’s Advanced PDF / HTML Templates
- Framework for Generating Custom NetSuite PDF Files
Hi Marty,
i’m trying to get items from work order sublist, using free-marker but i’m not able to get items, can you please help me i wrote code like given below.
${item.item}
but this code works for invoice and sales-order record.
Hi Marty,
New to Netsuite and suitescript after 25 years a developer, your columns have been a fantastic resource. Clear, concise, logical and a great help.
I am probably teaching my gramma to suck eggs but give Notepad++ a try. It will highlight XML errors as well as automatically save files locally.
Not a plug! One of my top dev. tools.
Now back to trying to find my templateId from name.
Thank you Paul,
We all need suggestions! I too have been using notepad ++ since, if I am not mistaken, since Windows 95.
Marty
Hi Marty,
Do you happen to know if when generating a PDF from transaction in Netsuite we can assign a specific file name sourced from the records fields? IE for invoices I would like to code the file name upon generation as something like: {customer_name}_{entity_name}_{documentnumber}. Is this possible with Netsuite advanced html templates?
Hello Lauren,
While what you are trying to do is a built-in part of the Content Renderer Engine (CRE) that we give to our clients free of charge, I don’t believe there is a native mechanism in NetSuite to name the files as you have requested.
Marty
Hi Marty I want the field withholding tax amount can be added in advance html/pdf but it never work the amount nevers show, the field of withholding tax never show in report.
If we can get to it via Saved Search or SQL, then this article is relevant:
https://blog.prolecto.com/2022/08/13/get-license-free-tools-to-link-netsuite-saved-search-sql-to-extend-data-reach/
Marty