Skip to main content

Logic control and looping

Zuora

Logic control and looping

The HTML Templates feature is generally available for invoices as of Zuora Release 2022.02.R2, and for credit and debit memos as of Zuora Release 2022.05.R1.

Although Mustache is a logicless template engine, you can still use merge fields to conduct basic logic control and looping in HTML templates for billing documents, including invoices, credit memos, and debit memos.

Conditional control 

If the input data meets the condition specified by the merge fields, the content defined in the middle of merge fields is displayed in the rendered result.

The following table lists merge field examples with conditional control.

 

Pseudo-code

Merge Fields

Description

Boolean field

If Invoice.Account.AutoPay == True
  "Auto pay account"
Else
  "AutoPay is not enabled"

{{#Invoice.Account.AutoPay}}
  "Auto pay account"
{{/Invoice.Account.AutoPay}}

{{^Invoice.Account.AutoPay}}
  "AutoPay is not enabled."
{{/Invoice.Account.AutoPay}}

If an account has the AutoPay option enabled, the Auto pay account message is displayed in the rendered result. 

If an account has the AutoPay option disabled, the AutoPay is not enabled. message is displayed in the rendered result.

Field with Boolean functions

If InvoiceItems.IsEmpty
  "Empty Invoice"
Else
  "Non-Empty Invoice"

{{#InvoiceItems|IsEmpty}}
  "Empty invoice"
{{/InvoiceItems|IsEmpty}}


{{^InvoiceItems|IsEmpty}}
  "Non-Empty Invoice"
{{/InvoiceItems|IsEmpty}}

If the InvoiceItems list is empty, the Empty invoice message is displayed in the rendered result.

If the InvoiceItems list is non-empty, the Non-Empty Invoice message is displayed in the rendered result.

If Account.AccountNumber == null or Account.AccountNumber.isBlank

  "Show a blank string"

Else

{{Account.AccountNumber}}

{{#Account.AccountNumber|IsBlank}}
  ""
{{/Account.AccountNumber|IsBlank}}

 

{{^Account.AccountNumber|IsBlank}}
{{Account.AccountNumber}}
{{/Account.AccountNumber|IsBlank}}

If the AccountNumber value of an account is blank, a blank string is displayed.

If the AccountNumber value of an account is not blank, the actual account number is displayed in the rendered result.

And

If Account.AutoPay and Balance == 0
  "AutoPay account and zero balance"

{{#Account.AutoPay}}
{{#Balance|EqualToVal(0)}}
  "AutoPay account and zero balance"
{{/Balance|EqualToVal(0)}}
{{/Account.AutoPay}}

If an account has the AutoPay option enabled and the account’s balance is equal to zero, the automatically paid account with zero balance is displayed in the rendered result. 

Exists

If Account.Entity__c == French and Hardware Product exists
  "Display a message."

{{#Invoice}}

{{#Account.Entity__c|EqualToVal(French)}}

{{^InvoiceItems|Map(RatePlanCharge)|Map(ProductRatePlanCharge)|Map(ProductRatePlan)|Map(Product)|FilterByValue(ProductType__c,EQ,Hardware)|IsEmpty}}

“Display message 1”

{{/InvoiceItems|Map(RatePlanCharge)|Map(ProductRatePlanCharge)|Map(ProductRatePlan)|Map(Product)|FilterByValue(ProductType__c,EQ,Hardware)|IsEmpty}}

{{/Account.Entity__c|EqualToVal(French)}}

{{/Invoice}}

If an account has a custom field named Entity__c and a product has a custom field  named ProductType__c, the Map Map function returns a list of Product values.

Equals

If RatePlanCharge.ChargeModel == “Flat Fee Pricing”

"Is Flat Fee"

Else

 "Not Flat Fee"

{{#Wp_Eval}}

"{{RatePlanCharge.ChargeModel}}" == "Flat Fee Pricing" ? "Is Flat Fee" : "Not Flat Fee"

{{/Wp_Eval}

If the charge model of a rate plan charge is Flat Fee Pricing, the Is Flat Fee message is displayed in the rendered result. 

Otherwise,  the Not Flat Fee message is displayed in the rendered result. 

If RatePlanCharge.ChargeModel == “Per Unit Pricing”

Display like Per Unit: $ 70.00 Per License

Else Display like Flat Fee: $ 4.50

{{#Wp_Eval}}

"{{RatePlanCharge.ChargeModel}}" == "Per Unit Pricing" ? `

<b>Per Unit: {{Invoice.Account.Currency|Symbol}} {{UnitPrice|Round(2)|Localise}} Per {{UOM}}</b>

`: '

Flat Fee: {{Invoice.Account.Currency|Symbol}} {{UnitPrice|Round(2)|Localise}}

'

{{/Wp_Eval}}

If the charge model of a rate plan charge is Per Unit Pricing, the text in the format of Per Unit: {{Invoice.Account.Currency|Symbol}} {{UnitPrice|Round(2)|Localise}} Per {{UOM}} is displayed in the rendered result, for example, Per Unit: $ 70.00 Per License

Otherwise, the text in the format of Flat Fee: {{Invoice.Account.Currency|Symbol}} {{UnitPrice|Round(2)|Localise}} like is displayed in the rendered result, for example, Flat Fee: $ 4.50. 

(Other charge models (Tiered Pricing?) are also displayed as Flat Fee: $ number??)

Multiple conditions

If RatePlanCharge.ChargeModel == “Flat Fee Pricing”

"Flat Fee Pricing"

Else If RatePlanCharge.ChargeModel == “Per Unit Pricing”

"Per Unit Pricing"

Else If RatePlanCharge.ChargeModel == “Tiered Pricing”

"Tiered Pricing"

Else

 “Other Pricing”

{{#Wp_Eval}}

"{{RatePlanCharge.ChargeModel}}" == "Flat Fee Pricing" ? "Flat Fee Pricing" : "{{RatePlanCharge.ChargeModel}}" == "Per Unit Pricing" ? "Per Unit Pricing" : "{{RatePlanCharge.ChargeModel}}" == "Tiered Pricing" ? "Tiered Pricing" : "Other Pricing"

{{/Wp_Eval}}

If the charge model of a rate plan charge is Flat Fee Pricing, the Flat Fee Pricing message is displayed in the rendered result. 

If the charge model of a rate plan charge is not Flat Fee Pricing, the rendered result depends on conditions.

  • If the charge model of a rate plan charge is Per Unit Pricing,  the Per Unit Pricing message is displayed in the rendered result. 
  • If the charge model of a rate plan charge is Tiered Pricing,  the Tiered Pricing message is displayed in the rendered result. 
  • If the charge model of a rate plan charge is not any of the preceding charge models, the Other Pricing message is displayed in the rendered result. 

 

 

Loop control 

You can use list section merge fields to achieve looping. The following table lists merge field examples with loop control.

 

Pseudo-code

Merge fields

Description

Loop lists

for item in Invoice.InvoiceItems
  print item.ChargeName - item.ServiceStartDate -- item.ServiceEndDate

{{#Invoice.InvoiceItems}}
{{ChargeName}} - {{ServiceStartDate}} -- {{ServiceEndDate}}
{{/Invoice.InvoiceItems}}

You can use this example to show the charge name and service period of all invoice items in generated invoices.

Nested loops

for invoiceItem in Invoice.InvoiceItems
  print invoiceItem.ChargeName :
  for taxItem in invoiceItem.TaxationItems
    print taxItem.Name -- taxItem.TaxAmount

{{#Invoice.InvoiceItems}}
{{ChargeName}} :
{{#taxationItems}}
{{Name}} -- {{TaxAmount}}
{{/taxationItems}}
{{/Invoice.InvoiceItems}}

You can use this example to show all taxation items of every invoice item in generated invoices.

Nested loops 

A nested loop is a loop inside another loop. For example, you might want to show all taxation items for every invoice item.

The pseudocode is as follows:

for invoiceItem in Invoice.InvoiceItems
  print invoiceItem.ChargeName :
  for taxItem in invoiceItem.TaxationItems
    print taxItem.Name -- taxItem.TaxAmount

To do the same with merge fields in HTML invoice templates, you can use the following merge fields:

{{#Invoice.InvoiceItems}}
{{ChargeName}} :
{{#taxationItems}}
{{Name}} -- {{TaxAmount}}
{{/taxationItems}}
{{/Invoice.InvoiceItems}}

For example, if you want to show a charge details table for each subscription. One invoice contains multiple subscriptions.

The pseudocode is as follows:

for subscription in Invoice.InvoiceItems.Subscription
  print subscription.Name
  for invoiceItem in invoiceItems of Subscription
    print ChargeName -- ChargeAmount

To do the same with merge fields in HTML invoice templates, you can use the following example HTML code. The GroupBy function transforms an InvoiceItems list into a new list, which consists of two fields only:

  • Subscription.Name: It is the field name used for grouping.

  • _Group: It is a hard-coded key, which contains a list of InvoiceItems with the same subscription name.

See the GroupBy function in Functions used in merge fields for more information.

{{#InvoiceItems|SortBy(ServiceStartDate,ASC)|GroupBy(Subscription.Name)}}
<h4>Subscription: {{Subscription.Name}}</h4>
{{Cmd_Assign(BySubscriptionName,_Group)}}
  <table class="table-grid u_content_custom_generic_table_1">
  <thead><tr>
      <th style="width:auto; text-align:right;">
          Description
      </th>
      <th style="width:auto; text-align:right;">
          Charge Amount
      </th>
      <th style="width:auto;text-align:right; ">
          Tax
      </th>
      <th style="width:auto; text-align:right;">
          Total
      </th></tr></thead>
  <tbody>
  {{#BySubscriptionName}}
    <tr>
      <td style="">{{ChargeName}}</td>
      <td style="text-align:right;">{{ChargeAmount}}</td>
      <td style="text-align:right;">{{TaxAmount}}</td>
      <td style="text-align:right;">{{#Wp_Eval}}{{ChargeAmount}}+{{TaxAmount}}{{/Wp_Eval}}</td>
    </tr>
  {{/BySubscriptionName}}  
    <tr>
      <td style="text-align:right;">Subtotal</td>
      <td style="text-align:right;">{{BySubscriptionName|Sum(ChargeAmount)}}</td>
      <td style="text-align:right;">{{BySubscriptionName|Sum(TaxAmount)}}</td>
      <td style="text-align:right;">{{#Wp_Eval}}{{BySubscriptionName|Sum(ChargeAmount)}}+{{BySubscriptionName|Sum(TaxAmount)}}{{/Wp_Eval}}</td>
    </tr>
  </tbody>
  </table>
  {{/InvoiceItems|SortBy(ServiceStartDate,ASC)|GroupBy(Subscription.Name)}}
{{/Invoice}}