Example of Using Custom Data Sources for Advanced Printing
When setting up an advanced template, you can use multiple data sources. This example shows how to use a JSON object and an XML file together with NetSuite data from a saved search to create a packing slip for a customer.
The JSON object provides customer names and language preferences.
{"customers":[
{"firstName":"John", "lastName":"Doe", "language":"English"},
{"firstName":"Anna", "lastName":"Smith", "language":"Spanish"},
{"firstName":"Peter", "lastName":"Jones", "language": "English"}
]}
The XML file provides a holiday greeting in the customer’s preferred language.
<?xml version="1.0" encoding="UTF-8"?>
<message>
<engbody>Happy holidays! We are closed from Dec 22 - Jan 3. Take advantage of our great prices before Christmas!</engbody>
<spbody>¡Feliz Navidad! Estamos cerrados del 22 de diciembre al 3 de enero. Aproveche nuestros excelentes precios antes de Navidad!</spbody>
</message>
The advanced PDF/HTML template is edited in markup source view to incorporate the XML file and JSON object.
<?xml version="1.0"?>
<!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd">
<pdf>
<head>
<macrolist>
<macro id="nlheader">
<!-- XML Part -->
<#if XML?has_content>
<p style="color: blue">
<#if .locale?starts_with("es_")>
${XML.message.spbody}
<#else>
${XML.message.engbody}
</#if>
</p>
</#if>
<!-- End XML Part -->
<table class="header">
<tr>
<td rowspan="3">
<span class="addressheader">${companyInformation.companyName}</span><br />
<span class="addressheader">${companyInformation.addressText}</span></td>
<td align="right"><span class="title">${record@title}</span></td>
</tr>
<tr>
<td align="right"><span class="number">#${record.tranid}</span></td>
</tr>
<tr>
<td align="right">${record.trandate}</td>
</tr>
</table>
</macro>
</macrolist>
<style type="text/css">
table {
font-family: sans-serif;
font-size: 9pt;
table-layout: fixed;
}
th {
font-weight: bold;
font-size: 8pt;
vertical-align: middle;
padding: 5px 6px 3px;
background-color: #e3e3e3;
}
td {
padding: 4px 6px;
}
td.addressheader {
font-size: 8pt;
padding-top: 6px;
padding-bottom: 2px;
}
span.number {
font-size: 16pt;
}</style>
</head>
<body header="nlheader" header-height="20%" padding="0.5in 0.5in 0.5in 0.5in" size="Letter">
<table style="width: 100%; margin-top: 10px;">
<tr>
<td colspan="3" style="font-size: 8pt; font-weight: bold;">${record.billaddress@label}</td>
<td colspan="3" style="font-size: 8pt; font-weight: bold;">${record.shipaddress@label}</td>
<td colspan="5" style="font-size: 12pt; background-color: #e3e3e3; font-weight: bold;">${record.total@label?upper_case}</td>
</tr>
<tr>
<td colspan="3" style="padding: 0;">${record.billaddress}</td>
<td colspan="3" style="padding: 0;">${record.shipaddress}</td>
<td align="right" colspan="5">${record.total}</td>
</tr>
</table>
<table style="width: 100%; margin-top: 10px;">
<tr>
<th>${record.paymentmethod@label}</th>
<th>${record.otherrefnum@label}</th>
<th>${record.shipmethod@label}</th>
<th>${record.shipdate@label}</th>
</tr>
<tr>
<td style="padding-top: 2px;">${record.paymentmethod}</td>
<td style="padding-top: 2px;">${record.otherrefnum}</td>
<td style="padding-top: 2px;">${record.shipmethod}</td>
<td style="padding-top: 2px;">${record.shipdate}</td>
</tr>
</table>
<#if record.item?has_content>
<table style="width: 100%; margin-top: 10px;">
<!-- Start Items -->
<#list record.item as item>
<#if item_index==0>
<thead>
<tr>
<th align="center" colspan="3">${item.quantity@label}</th>
<th colspan="12">${item.item@label}</th>
<th align="right" colspan="4">${item.rate@label}</th>
<th align="right" colspan="4">${item.amount@label}</th>
</tr>
</thead>
</#if>
<tr>
<td align="center" colspan="3" line-height="150%">${item.quantity}</td>
<td colspan="12">
<span style="font-weight: bold; line-height: 150%;">${item.item}</span>
<br />
${item.description}
</td>
<td align="right" colspan="4">${item.rate}</td>
<td align="right" colspan="4">${item.amount}</td>
</tr>
</#list>
<!-- End Items -->
</table>
<hr style="width: 100%; color: #d3d3d3; background-color: #d3d3d3; height: 1px;" />
</#if>
<table style="page-break-inside: avoid; width: 100%; margin-top: 10px;">
<tr>
<td colspan="4"> </td>
<td align="right" style="font-weight: bold;">${record.subtotal@label}</td>
<td align="right">${record.subtotal}</td>
</tr>
<tr>
<td colspan="4"> </td>
<td align="right" style="font-weight: bold;">
${record.taxtotal@label}
${record.taxrate}%)
</td>
<td align="right">${record.taxtotal}</td>
</tr>
<tr style="background-color: #e3e3e3; line-height: 200%;">
<td background-color="#ffffff" colspan="4"> </td>
<td align="right" style="font-weight: bold;">${record.total@label}</td>
<td align="right">${record.total}</td>
</tr>
</table>
<!-- JSON Part -->
<#if JSON?has_content>
<p style="color: red">
JSON data:
</p>
<table style="width: 100%; margin-top: 10px;">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Language</th>
</tr>
</thead>
<#list JSON.customers as item>
<tr>
<td>${item.firstName}</td>
<td>${item.lastName}</td>
<td>${item.language}</td>
</tr>
</#list>
</table>
</#if>
<!-- End JSON Part -->
<!-- Saved Search Part -->
<#if SEARCH?has_content>
<p style="color: green">
Saved Search results:
</p>
<table style="width: 100%; margin-top: 10px;">
<thead>
<tr>
<th>trandate</th>
<th>amount</th>
<th>entity</th>
</tr>
</thead>
<#list SEARCH as item>
<tr>
<td>${item.trandate}</td>
<td>${item.amount}</td>
<td>${item.entity}</td>
</tr>
</#list>
</table>
</#if>
<!-- End Saved Search Part -->
</body>
</pdf>
The SuiteScript file incorporates the JSON object and XML file with NetSuite data and the advanced template.
/** *
@NApiVersion 2.x
*/
require(['N/render', 'N/file', 'N/record', 'N/search'],
function(render, file, record, search) {
// load JSON file from file cabinet
var jsonFile = file.load({
id: #json_content_file_cabinet_id#
});
// load XML file from file cabinet
var xmlFile = file.load({
id: #xml_content_file_cabinet_id#
});
// load printing template file from cabinet
var templateFile = file.load({
id: #template_content_file_cabinet_id#
});
var renderer = render.create();
renderer.templateContent = templateFile.getContents();
// add JSON custom data source
renderer.addCustomDataSource({
alias: "JSON",
format: render.DataSource.JSON,
data: jsonFile.getContents()
});
// add XML custom data source
renderer.addCustomDataSource({
alias: "XML",
format: render.DataSource.XML_STRING,
data: xmlFile.getContents()
});
// add search data source
var rs = search.create({
type: search.Type.TRANSACTION,
columns: ['trandate', 'amount', 'entity'],
filters: []
}).run();
var results = rs.getRange(0, 1000);
renderer.addSearchResults({
templateName: 'SEARCH',
searchResult: results
});
// add record data source
var objRecord = record.create({
type: record.Type.SALES_ORDER
});
renderer.addRecord({
templateName: 'record',
record: objRecord
});
// render PDF file and save
var invoicePdf = renderer.renderAsPdf();
invoicePdf.folder = #file_cabinet_folder_id#;
var id = invoicePdf.save();
});
The output of this example resembles the following.
