Use custom objects in HTML templates
You can use custom objects and fields in HTML templates to display more complex or advanced data in billing documents, including invoices, credit memos, and debit memos.
You must have the "View Custom Object" permission to generate PDFs from HTML templates that use custom objects.
This tutorial takes invoices as an example; the configuration procedure is similar for credit memos and debit memos.
When using custom objects and fields in HTML templates, keep the following key points in mind:
- Object names must be made plural when they are used in HTML templates.
If you define a custom object name asMessages
, you have to usedefault__messageses
to refer to the object list. The following table lists more examples.API names of custom objects Names to refer to object lists in HTML templates Messages default__messageses Entites default__entiteses Reefer default__reefers ExchangeRate default__exchangerates LegalEntity default__legalentities - The custom fields used in a filter must be filterable.
For example, if you want to retrieve a list of reefers that belong to a subscription, the custom fieldSubscriptionName__c
contained in{{#default__reefers|FilterByRef(SubscriptionName__c,EQ,SubscriptionNumber)}}
must be filterable.
Display messages based on locales
You can store translation messages in custom objects including locales and message keys as filterable fields. Later, you can query the translation messages based on message keys and locales, and use them as field labels, table header names, or texts in the template.
To display messages based on locales, perform the following steps:
-
Define a custom object named messages to store the messages.
The following table lists the structures of the custom object. For example, KEY is the field label, andkey__c
is its API name. The fieldskey__c
andlocale__c
are filterable.ID KEY(key__c) LOCALE(locale__c) VALUE(value__c) 0f9e8dc6-4256-4185-805a-efbb761245a4 invoice_date en_US Invoice Date 0f9e8dc6-4256-4185-805a-efbb761245a5 payment_terms en_US Payment Terms 0f9e8dc6-4256-4185-805a-efbb761245a9 invoice_date zh_CN 账单日 0f9e8dc6-4256-4185-805a-efbb76124510 payment_terms zh_CN 账期 - Use filter functions to query the message value based on keys.
{{#default__messageses|FilterByValue(locale__c,EQ,zh_CN)|FilterByValue(key__c,EQ,invoice_date)}}{{value__c}}:{{/default__messageses|FilterByValue(locale__c,EQ,zh_CN)|FilterByValue(key__c,EQ,invoice_date)}}
Display lists of custom object records
To display a list of custom object records in invoices, perform the following steps:
-
Define a custom object named reefer to store the reefers that each subscription has.
One subscription can have multiple reefers. The following table lists the structures of the custom object. The custom object uses Subscription Name as the key, and its API name isSubscriptionName__c
.ID Brand Number Volume StartDate Subscription Name 0f9e8dc6-4256-4185-805a-efbb761245a4 Brand1 10003 50m~3 2021-04-01 A-S00000056 0f9e8dc6-4256-4185-805a-efbb761245a5 Brand2 10002 100m~3 2021-01-01 A-S00000054 0f9e8dc6-4256-4185-805a-efbb761245a9 Brand3 10001 100m~3 2021-01-01 A-S00000056 -
Use the HTML component to configure how to display the reefers that an invoice contains. For more information about the configuration procedure, see Configure HTML codes in HTML templates.
- Use
{{#InvoiceItems|Map(Subscription)|Uniq}}
to construct the subscription list that the invoice contains. - For each subscription, filter reefers based on the subscription number:
{{#default__reefers|FilterByRef(SubscriptionName__c,EQ,SubscriptionNumber)}}
- For each reefer record, display its fields as a row in the table.
The following information is an example of HTML codes. The style part is ignored.
<style> ... </style> {{#Invoice}} <table class="table-grid u_content_custom_generic_table_2"> <thead><tr> <th style="width:auto; "> Subscription Name </th> <th style="width:auto; "> Brand </th> <th style="width:auto; "> Number </th> <th style="width:auto; text-align:right;"> Volume </th> <th style="width:auto; text-align:right;"> Start Date </th></tr></thead> <tbody> {{#InvoiceItems|Map(Subscription)|Uniq}} {{Cmd_Assign(SubscriptionNumber,Name)}} {{#default__reefers|FilterByRef(SubscriptionName__c,EQ,SubscriptionNumber)}} <tr> <td style="">{{SubscriptionName__c}}</td> <td style="">{{Brand__c}}</td> <td style="">{{Number__c}}</td> <td style="">{{Volume__c}}</td> <td style="">{{StartDate__c}}</td> </tr> {{/default__reefers|FilterByRef(SubscriptionName__c,EQ,SubscriptionNumber)}} {{/InvoiceItems|Map(Subscription)|Uniq}} </tbody> </table> {{/Invoice}}
- Use
The following image shows the preview result.
Display exchange rates on invoices
Assume that your customers have AED as the home currency, but are billed in USD. You want to present the charge amount and tax in AED on the invoice. The exchange rate that is used to convert from USD to AED is also displayed.
To display exchange rates on invoices, perform the following steps:
-
Define a custom object named ExchangeRate to store the exchange rate.
The following table lists the structures of the custom object. TheFrom__c
andTo__c
fields are filterable.
ID |
From (From__c) |
To (To__c) |
Rate(Rate__c) |
---|---|---|---|
0f9e8dc6-4256-4185-805a-efbb761245a4 |
USD |
AED |
8.00 |
0f9e8dc6-4256-4185-805a-efbb761245a5 |
USD |
GBP |
0.73 |
0f9e8dc6-4256-4185-805a-efbb761245a9 |
CAD |
GBP |
1.09 |
-
Use filter functions to query the exchange rate based on home currency (AED) and billed currency (USD).
You can use theCmd_Assign
command to define a global variable named TheRate, which can be used anywhere in the template.{{#default__exchangerates|FilterByRef(From__c,EQ,Invoice.Account.Currency)|FilterByValue(To__c,EQ,AED)|First(1)}}
{{Cmd_Assign(TheRate,Rate__c,True)}}
{{/default__exchangerates|FilterByRef(From__c,EQ,Invoice.Account.Currency)|FilterByValue(To__c,EQ,AED)|First(1)}}
-
Use the TheRate global variable to calculate all amount fields in home currency.
The following example is to calculate the total tax amount in home currency.
{{Account.Currency|Symbol}}{{TaxAmount|Round(2)|Localise}} ( {{#Wp_Eval}} {{TaxAmount}}*{{TheRate}}|Round(2)|Localise {{/Wp_Eval}} AED)
The output is displayed as $1.18 ( 9.44 AE).
The following example HTML codes are to show an invoice item as a row in a charge details table.{{#InvoiceItems}} <tr> <td style="">{{ChargeName}} </td> <td style="">{{ServiceStartDate|Localise}} - {{ServiceEndDate|Localise}} </td> <td style="text-align:right;">{{Account.Currency|Symbol}}{{ChargeAmount|Round(2)|Localise}} ({{#Wp_Eval}}{{ChargeAmount}}*{{TheRate}}|Round(2)|Localise{{/Wp_Eval}} AED) </td> <td style="text-align:right;">{{Account.Currency|Symbol}}{{TaxAmount|Round(2)|Localise}} ({{#Wp_Eval}}{{TaxAmount}}*{{TheRate}}|Round(2)|Localise{{/Wp_Eval}} AED) </td> <td style="text-align:right;">{{Account.Currency|Symbol}}{{#Wp_Eval}}{{ChargeAmount}}+{{TaxAmount}}|Round(2)|Localise{{/Wp_Eval}} ({{#Wp_Eval}}({{ChargeAmount}}+{{TaxAmount}})*{{TheRate}}|Round(2)|Localise{{/Wp_Eval}} AED) </td> </tr> {{/InvoiceItems}}
-
Preview the template after you add the merge fields.
The following image shows an example of the preview result.
Use custom objects with relationships with Zuora objects
Assume that your company has multiple legal entities globally, and you want to associate your customer accounts with appropriate legal entities. The legal entity information is used to display information conditionally on generated invoice PDF files.
To use custom objects with relationships with Zuora objects in your scenario, perform the following steps:
- Define a custom object named LegalEntity to store the legal entity information.
The custom object has a custom field calledAccount__c
withField Type
asRelationship
,Namespace
ascom_zuora
, andObject Name
asAccount
. The relationship between the custom object LegalEntity and its related object Account is many-to-one, although one Account object is related to only oneLegalEntity object.
The following table lists the structures of the custom object. TheEntityNumber__c
andAccount__c
fields are filterable.ID Entity Name (EntityName__c) Entity Number (EntityNumber__c) Account (Account__c) 0f9e8dc6-4256-4185-805a-efbb761245a4 Legal Entity USA 100001 2c92c8fe79652c000179683d2c1f122d 0f9e8dc6-4256-4185-805a-efbb761245a5 Legal Entity UK 100002 2c92c8fb783a5faa01783ae11bdc0731 0f9e8dc6-4256-4185-805a-efbb761245a9 Legal Entity APAC 100003 2c92c8fb7d2c85e1017d2d18bd9d0cda -
To display entity names on invoices, use the following example:
{{#Account.default__legalentities|First(1)}}
{{EntityName__c}}
{{/Account.default__legalentities|First(1)}}
In the preceding example,Account.default__legalentities
refers to the custom object list, and theFirst
function returns the first one record. -
To display tax information by entity number, use the following example:
{{#Invoice}}
{{#Account.default__legalentities|First(1)}}
{{Cmd_Assign(VarEntityNumber,EntityNumber__c,True)}}
{{/Account.default__legalentities|First(1)}}
{{#Wp_Eval}}"{{VarEntityNumber}}" == "100001" ? "show Legal Entity USA tax info" : ""{{/Wp_Eval}}
{{#Wp_Eval}}"{{VarEntityNumber}}" == "100002" ? "show Legal Entity UK tax info" : ""{{/Wp_Eval}}
{{/Invoice}}
The preceding example assignsEntityNumber__c
to a global variable, and uses the global variable in later expressions. The expressions evaluate entity numbers, and show tax information appropriately. For more information, see Variables and Expressions. -
To display the custom fields of a custom object in a table, use the following example:
{{#Invoice.Account.default__legalentities|First(1)}}
{{EntityName__c}}
{{/Invoice.Account.default__legalentities|First(1)}}
In a Data Table component, assume that you select InvoiceItems as Table Object. Then, you can add a new column with Advanced Options set to on, and use the preceding merge field example for the column. For more information, see Configuring data tables in HTML invoice templates.
Notes
If you use one custom object multiple times in a template or use multiple decorators like FilterByValue
and FilterByRef
on such objects, you cannot get the PDF generated as expected. For example, assume that you define a custom object named resources
, and the filter function examples are as follows:
{{#default__resources|FilterByValue(Key__c,EQ,SupplierVATId)|FilterByRef(Country__c,EQ,Invoice.Account.SoldTo.Country)}} {{Invoice.Account.SoldTo.Country}} {{Label__c}}: {{Value__c}} {{/default__resources|FilterByValue(Key__c,EQ,SupplierVATId)|FilterByRef(Country__c,EQ,Invoice.Account.SoldTo.Country)}}
{{#default__resources|FilterByValue(Key__c,EQ,SupplierPSTId)|FilterByRef(State__c,EQ,Invoice.Account.SoldTo.State)}} {{Label__c}}: {{Value__c}} {{/default__resources|FilterByValue(Key__c,EQ,SupplierPSTId)|FilterByRef(State__c,EQ,Invoice.Account.SoldTo.State)}}
You will receive an error, saying that "Could not generate PDF: Exception while fetching data (/default__resources) : com.zuora.owl.hawk.exception.HawkException: Bad argument: Your Filter is not supported for current object type [ErrorCode: 412 QueryFailed] [85B30716DE46310C]."
To generate the PDF files and avoid missing custom object data on the generated PDF files, you can use the Cmd_Assign
command to have the custom object get assigned to a variable. Note that you must have the required permissions to access the custom objects. For more information about the Cmd_Assign
command, see Merge field syntax for HTML templates.
Assume that you define a custom object named resources
, which has four custom fields called Entity
, Key
, Value
, Label
. You can assign the custom object to variable along with the available custom fields by using the Cmd_Assign
command:
{{Cmd_Assign(Resources1,default__resources|FilterByValue(Entity__c,NOT_NULL)|FilterByValue(Key__c,NOT_NULL)|FilterByValue(Value__c,NOT_NULL)|FilterByValue(Label__c,NOT_NULL),true)}}
The following example shows how you can apply the required decorators on the variable Resources1 in the template:
{{#Invoice}} {{Cmd_Assign(Resources1,default__resources|FilterByValue(Entity__c,NOT_NULL)|FilterByValue(Key__c,NOT_NULL)|FilterByValue(Value__c,NOT_NULL)|FilterByValue(Label__c,NOT_NULL),true)}} {{#Resources1|FilterByValue(Key__c,EQ,'Zuora')|FilterByValue(Entity__c,EQ,'Zuora Inc')}}
{{Label__c}}: {{Value__c}}
{{/Resources1|FilterByValue(Key__c,EQ,'OrgName')|FilterByValue(Entity__c,EQ,'Zuora Inc')}} {{Cmd_Assign(Resources1,default__resources,true)}} {{#Resources1|FilterByValue(Key__c,EQ,'Address1')|FilterByValue(Entity__c,EQ,'SomeValue')}}
{{Label__c}}: {{Value__c}}
{{/Resources1|FilterByValue(Key__c,EQ,'Address1')|FilterByValue(Entity__c,EQ,'SomeValue')}}
{{/Invoice}}
Through using the Cmd_Assign
command, you can avoid the PDF file generating issue when you use one custom object multiple times in a template or use multiple decorators like FilterByValue
and FilterByRef
on such objects. Also, with this Cmd_Assign
command workaround, you will not have custom object data missing on the PDF files.