Interrogating NetSuite’s Advanced PDF / HTML Templates

This article is relevant if you are seeking to get a good handle on NetSuite’s Advanced PDF / HTML template technology

Background

I wrote about the general framework about a year ago in this article:¬†“How To: Leverage NetSuite‚Äôs Advanced PDF / HTML Generation Tools”¬†. ¬†That article offers a good over and references to documents to help you build new templates.

Since that time and as of this writing, NetSuite has announced a roadmap to push customers toward the Big Faceless Organization (BFO) Freemarker framework for generating HTML and PDF documents. ¬†The technology is still considered “Beta” but it is clear NetSuite is making a significant investment. ¬†In anticipation for a need to master this new technology, I wanted to produce a Freemarker template that can help all of us understand the underlying data that is being passed to us so we can better craft our specific templates used in the business. ¬†Meaning, I want to go much deeper into the possibility of using these tools to unlock the power.

Locked Up Data Model

I want to be wrong about this. ¬†But after spending about a half day trying everything I could, I have concluded that NetSuite is not supporting an important FreeMarker “Built In” called “keys”. ¬†Essentially, when NetSuite provides us with a reference to the template data model such as “record”, we are supposed to know in advance the field name. ¬†For example, if you want the date on the record, you would reference “${record.trandate}”.

That is fine and dandy, but it demands much hunt and pecking to get field names.  Sometimes, field names are not so obvious especially as you start to traverse NetSuite sublists.  I wanted to build a tree representation of all the data being passed to us so we can diagnose the data model and its contents to dramatically shorten the trial and error cycle required to build our templates.

Built in “Key” Lookup

NetSuite is not obligated to give us the Built-In “Key” lookup. ¬† When NetSuite provide us data elements to work with, they are provided as Hashes. ¬†The Hash is effectively a collection of name:value pairs commonly available in most object oriented development languages. ¬†Sometimes these are called dictionaires because with the name, you can get its value or meaning. ¬†In general, when you have a Hash, you can loop through all the elements if you have the “Keys”. ¬†The Keys are a list of all the names located within the Hash. ¬†This is perfect if we want to output every field name and its related value. ¬†Imagine the time saved if you could spit out all the data NetSuite passes to us so we can see it in one place and perform cut-and-paste field name operations during our template development?

The Keys are available to us at the very top of the tree called the “data_model”. ¬†I have produced a template that at least let’s us look at the names of all the hashes (record types) being passed to us. ¬†From this, we can tell that the hashes are not case sensitive. ¬†For example, NetSuite’s sample templates show us ${companyInformation}. ¬†From my discovery work, ${companyinformation} works just as fine as well.

I suspect NetSuite is not providing us the Keys because it may reveal more data than what they want us to see and possibly breach security.   But really, just because something is obscure does not mean it is secure.

NetSuite Advanced PDF Inspection Template

This template is quite basic primarily because Keys support is limited.  Use it to inspect what record types are being passed to you.

<?xml version="1.0"?>
<!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd">
<pdf>
<head></head>
<body>
<h2>Advanced PDF Template to Discover BFO Global Environment Information Passed from NetSuite</h2>
<h2>Crafted by Marty Zigman</h2>
<div><img src="http://www.prolecto.com/assets/footer/casual-cropped-marty-zigman-20121025-small.jpg"></img></div>
<div><img src="http://www.prolecto.com/assets/footer/prolecto_logo_360x41_2007.jpg"></img></div>
<p>Template Version: ${.version}</p>
<p>Template Name: ${.template_name}</p>
List (.data_model)
<table>
	<#assign keys = .data_model?keys>
	<#list keys as key>
		<tr>
			<td>Key: ${key}</td>
			<td>Value: ${.data_model[key]}</td>
		</tr>
	</#list>
</table>
List (.namespace)
<table>
	<#assign keys = .namespace?keys>
	<#list keys as key>
		<tr>
			<td>Key: ${key};</td>
		</tr>
	</#list>
</table>

List (.main)
<table>
	<#assign keys = .main?keys>
	<#list keys as key>
		<tr>
			<td>Key: ${key};</td>
		</tr>
	</#list>
</table>
</body>
</pdf>

NetSuite Enhancement Request

There is a NetSuite enhancement request for this capacity. Please vote for SuiteIdea: 296495 to help this enhancement get priority.  Once it is in place, I will develop a template that will enumerate all the field names and values so we all can enjoy.

Related Articles

We are committed to this space.  With some tools we built which are available to, all the data is now exposed.  See below articles most relevant for NetSuite users working to get more out of the Advanced PDF/HTML tools:

  1. How To: Leverage NetSuite’s Advanced PDF / HTML Generation Tools
  2. Supercharge NetSuite Advanced PDF/HTML Templates
  3. Solved: Custom NetSuite Item Fulfillment Ship Notifications
  4. Framework for Generating Custom NetSuite PDF Files
Be Sociable, Share!

Marty Zigman

Holding all three official certifications, Marty is Southern California's NetSuite expert and leads a team of senior professionals at Prolecto Resources, Inc. He is a former Deloitte & Touche CPA and has held CTO roles. For over 25 years, Marty has produced leadership in ERP, CRM and eCommerce business systems. Contact Marty to set up a conversation.

More Posts - Website - Twitter - Facebook - LinkedIn - Google Plus - YouTube

| Tags: , , , | Category: NetSuite, Technical | 29 Comments

24 Comments

  1. Corey Hunt
    Posted February 3, 2015 at 10:32 am | Permalink

    An easy hack to get fields that are present for Freemarker is to append &xml=t to the transaction you are viewing. This doesn’t give you what you have available from company but gives most of what you can get from record.

  2. Giriesh
    Posted February 9, 2015 at 11:57 am | Permalink

    Good article.

    @Corey Hunt – Thanks for that hack. Really helpful.

  3. Posted April 29, 2015 at 5:10 am | Permalink

    Hi Marty, i want to create sales order pdf using suitelet. I wrote the code to do that, but the XML Parser in not parsing the Logic directives how to write those in script. pls help me.

  4. Posted May 8, 2015 at 5:07 pm | Permalink

    Hi Vinod,

    I find that during development, it is pretty easy to “mess up” and the system won’t parse the data. A few thoughts:

    1. Use an XML validator tool to help you see what’s wrong with the XML. Here is one that should work well
    2. Work with the XML outside of the NetSuite tool in your favorite editor. This does require cut and paste. I like to frequently save my files with new names to help version in case I need to go back in time.

    Good luck! I plan on writing many more articles on this subject as we have done some new things to get more power of out this framework.

    Marty

  5. Sachin Khairnar
    Posted July 1, 2015 at 11:30 pm | Permalink

    Hi Marty
    I have clear the suite foundation exam and now preparing for Certified developer.
    Please let me which study material should I refer.
    Any specific Netsuite PDF, Video,Help topics.
    Thanks in advance.

  6. Posted July 6, 2015 at 7:23 am | Permalink

    Hello Sachin,

    I don’t have any specific recommendations. We all have different learning styles. The SDN program offers a number of resources for you to peruse. Good luck!

    Marty

  7. Bob Henry
    Posted July 14, 2015 at 3:24 pm | Permalink

    Hi Marty,

    You mentioned you edit the XML in another editor and copy and paste it into the NetSuite interface.

    Our team has streamlined this by uploading all the templates to the File Cabinet and using the SuiteScript plugin for eclipse to edit straight in eclipse. We use imports in the NetSuite interface to load the template from the File Cabinet.

    This gives you the a) advantage of an easy workflow (e.g. ctrl + u automatically uploads to NetSuite so it’s as simple as pressing ctrl + u and refreshing the template to try any new changes) and b) the ability to use version control (e.g. git) to collaborate efficiently.

  8. Posted July 24, 2015 at 6:48 pm | Permalink

    Hi Bob,

    That’s a great idea. Much faster to work in that context. Thank you. These days, we are pushing the Advanced PDF / HTML tools pretty hard. Our capacity now to execute multiple searches that we can join together and then present to the environment is solving many client problems. See article: Supercharge NetSuite Advanced PDF/HTML Templates

    Marty

  9. MG2016
    Posted January 27, 2016 at 12:54 pm | Permalink

    Hey Marty,

    Today I started to build my first Advanced PDF template for an invoice. All is fine except I need to show a line of text based on tax code. Now I can pull the tax code but when I do a compare it is never true:

    text to be shown here…

    If I do a != my text is shown. However, the value returned from taxcode on the line item shows VAT:Standard GB.

    Any thoughts or advice? And how can we reach the field ids from the line item on an invoice, is this possible?

    Many Thanks!

  10. Posted February 9, 2016 at 5:33 pm | Permalink

    Hi,

    These days, we are using the CRE Tool to get exactly what ever we need. No more copying fields and so forth just because NetSuite can’t reach the data. We feel so blind to the data set with NetSuite’s standard implementation. It’s trial and error which burns a lot of time. Let me know if you want the tool. It’s a short services engagement to make sure you are productive.

    Marty

  11. Dan S
    Posted February 12, 2016 at 2:17 pm | Permalink

    Marty,

    Great article. I was hoping there would be some way to pull out the various field IDs, but cannot get anywhere. I noticed on the advanced PDF pick tickets, there is no longer a column for the preferred bin of the item. I’ve tried numerous field names and cannot get anywhere. Do you have any ideas on how to go deeper into this? I know your article was published in 2014… I’ve tried record.item.binnumbers, nothing…I’ve even tried record.item.item.binnumbers which DOES get me to the bin sublist, but getting the preferred bin for the given location would be a mess of code!

  12. Posted February 13, 2016 at 6:03 am | Permalink

    Hello Dan,

    Yes, this is solved using our CRE Tool. We basically can define the saved search and target the preferred bin location. How are you printing these?

    Marty

  13. Dan S
    Posted February 13, 2016 at 6:09 am | Permalink

    Looks interesting. Right now we’re still using the non-Advanced PDF forms, which has a printable field for “Bin Numbers”. This is the only thing holding us back from using the new Advanced PDF pick tickets.

  14. Posted February 14, 2016 at 7:59 am | Permalink

    Dan,

    I setup a sample transaction in our system to confirm I could see the concern. Here is my assessment:

    1) We definitely can reproduce the Pick Ticket to include the Preferred Bin information. This includes logic to determine availability like you can see in the classic form.
    2) The challenge though becomes driving the enhanced CRE based PDF through NetSuite’s Bulk “Print Picking Tickets” function. We can’t get control over that element as it is wired to native templates.
    3) To solve that, we would need to create a SuiteLet that emulates that function so that we can create bulk or batch print mechanisms. We have done solutions like that before.

    However, I am not sure the effort is worth it. While the CRE tool can give you control, if you need a new batch mechanism to drive it, it diminishes the value because we need to build that. The “old school” approach to start writing custom fields also has weakness. Traditionally, you would create a custom transaction column on the Sales Order to drive this. However, the information about item availability is dynamic and thus, information in the custom field would be stale at the time to print the tickets. We may be able to create a custom formula field to get the information in play but there are times (or really, specific use contexts) the data won’t calculate.

    Marty

  15. Mark Zschiegner
    Posted February 15, 2016 at 6:46 am | Permalink

    Hey Dan,

    We ended up creating a Suitelet to do this. It wasn’t easy, but it works well as we needed a way to print pick-pack tickets customized for each of our customers.

    Cheers,

    Mark

  16. Posted February 15, 2016 at 6:57 am | Permalink

    Mark,

    Thanks for sharing. I suspect I could couple your SuiteLet to the Content Rendering Engine to get maximum control over the experience. Did you end up creating custom field(s) to hold the data so that the Advanced PDF template could read it?

    Marty

  17. Dan S
    Posted February 15, 2016 at 7:00 am | Permalink

    Thanks for the quick responses guys. I was hoping it was something obvious that I was missing, but unfortunately, that’s not the case. I’ll see if I can file something with NetSuite to get this back. For now, I think we’ll continue with the standard PDF templates.

    Thanks!

  18. Mark Zschiegner
    Posted February 15, 2016 at 7:24 am | Permalink

    Hey Marty,

    I just reviewed the code really quick, and it appears we ended up using the OzLink custom fields, but I don’t see any new ones created. I’ll email you a screenshot of how this looks form wise on our end now.

    It has actually worked pretty well since we had discussed initially with you our problem.

    Cheers,

    Mark

  19. Posted January 19, 2017 at 5:26 am | Permalink

    Hi, Marty.

    I found this post very useful to find out the real data structure being passed on to the template. What I’m really struggling is to find out the correct syntax to enumerate the fields (for the record data, for example).

    Is this only a matter of using the correct syntax to get the second-level fields keys or is there another level of complexity I’m not aware of?

  20. Posted January 19, 2017 at 5:34 am | Permalink

    Edson,

    I agree. It’s trial and error. Our Content Renderer Engine allows us to inspect all the variables and is useful in this context. See this image Content Renderer Engine Syntax. Here is a supporting article.

    If you are doing a lot of this work, we can give you the tool with a bit of coaching.

  21. Trav
    Posted April 3, 2017 at 10:51 pm | Permalink

    As always – awesome. Do you know how to change page size from LETTER to A4?

  22. Posted April 4, 2017 at 4:00 pm | Permalink

    Hello Trav,

    Did you see this reference? Give it a try. It may do the trick: http://bfo.com/products/report/docs/tags/atts/size.html

  23. brus
    Posted November 2, 2017 at 4:20 am | Permalink

    Hai sir i have one doubt i get the standard sublist from transaction record but i did’t get the custom sublist can you please help me using in freemarker advanced PDF

  24. Posted November 11, 2017 at 4:00 pm | Permalink

    Hello Brus,

    The trick with custom sublists is to determine if you can get to the ‘recordmachine’. In the browser, right click and inspect the tab to see if you can discover the name. Of course, we solve all of these ‘simple but hard matters’ with our Content Renderer Engine tool.

    Marty

5 Trackbacks

  1. […] have developed a NetSuite Advanced PDF Content Generator leveraging the FreeMarker template syntax. ¬†In this effort (subject to future article), we wanted […]

  2. […] have developed a NetSuite Advanced PDF Content Generator leveraging the FreeMarker template syntax. ¬†In this effort (subject to future article), we wanted […]

  3. […] Interrogating NetSuite‚Äôs Advanced PDF / HTML Templates […]

  4. […] Interrogating NetSuite‚Äôs Advanced PDF / HTML Templates […]

  5. […] Interrogating NetSuite‚Äôs Advanced PDF / HTML Templates […]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>