Pricefx Classic UI is no longer supported. It has been replaced by Pricefx Unity UI.

 

Message Templates

Template Types

There are different template types designated for different document lifecycle situations. In addition, there are also templates for general cases and for the messaging functionality in Unity UI.

Workflow

There are several workflow email templates which inform users (approvers, watchers, owners) about various workflow states. The templates are:

  • For email body: 
    • approvalRequired – Request for an approval to the approver.
    • approve_success – Confirmation to the approver.
    • deny_success – Confirmation to the approver.
    • stepApproved – Notification to others.
    • stepDenied – Notification to others.
    • watcherNotification – Triggered by having a watcher step in the workflow. 
    • workflowApproved – Triggered when the whole workflow is approved.
    • delegationFooter/Header – Delegation of approval authority to other user.
  • For email subject: 
    • workflowSubjectSuffix – Adds document's details to the email subject. (The subject is hardcoded and contains one of the following: Pricefx - Approval Required, Pricefx - Watcher notification, Pricefx - Approved, Pricefx - Workflow Approved, Pricefx - Denied.)
    • delegationSubjectSuffix – Adds source and target users' names to the subject.
      (warning) When editing these templates, you must put everything in one row (text line), even if you use a more complex template code. (If multiple rows were used, the subject suffix would be generated empty and the code you wrote would appear in the email body.)

Some of these notifications can be switched off. You can disable:

  • All notifications for specified events – for details see Workflows Configuration.
  • Individual message types. Use the 'Allow Sending' check-box to control which message types will be sent.
    Note: Some messages are split into several items (e.g., email subject and body) – in this case only the main part (e.g., the email body) has an active check-box. Disabling the main part disables the whole message. 

All of these templates are available for all the approvable documents: 

  • Data Change Request
  • Price Grid Item
  • Quote
  • Rebate Agreement
  • Agreement/Promotion
  • Price List
  • Rebate Record

Export and Send by Email

There are templates for emails which users can send manually from Quotes, Agreements/Promotions and Rebate Agreements with the related document as an attachment (available only in the Unity interface):

  • quote_externalEmailSubject
  • quote_externalEmailBody
  • contract_externalEmailSubject
  • contract_externalEmailBody
  • rebateagreement_externalEmailSubject
  • rebateagreement_externalEmailBody

Other

There are also message templates for:

  • general failure
  • workflow failure
  • e-signature system notifications
  • messaging in Unity UI (see 99587618)

Template Language

To support easier text customizations and localization of the templates, their content and formatting are separated (since Bijou 7.0).

  • All textual elements in the templates are represented by placeholders. These placeholders and their values (texts) are shipped and maintained as part of the product. In your custom templates you can use them or replace them with "real" text.
  • The default templates contain only HTML and styling information and text placeholders.

To ensure that the previous system (templates containing both formatting and content) keeps working, the following rules apply:

  • Template names stay as they are.
  • First the server loads customized language specific templates (e.g. quote_approvalRequired_fr). 
  • If no customized template is found, the server will load the default template in a 3-step hierarchy:
    1. Full template name as specified (e.g. quote_approvalRequired_fr)
    2. Full template name without locale (e.g. quote_approvalRequired)
    3. Template name without locale and without type prefix (e.g. approvalRequired)
  • It will then add the locale specific translations into the templating engine (plus the usual placeholders) and render it.

By default, the templates are available in the same languages as the application UI. You can also add other languages in the Edit dialog (if you have provided the Email.properties file for that language) and then simply switch between the template's language versions in the Locale drop-down list. To determine, which language version will be used for a particular user, go to the User Admin section and select the appropriate language in 'Email Locale'.

Customize Template

A default template is provided and can be changed by writing standard HTML code and using Pricefx fields. Make sure you keep the correct syntax. 

In the message you can access data from the object which triggered sending the email message. For example, the method withDataMap(Map dataMap) of the WorkflowDTO object allows you to access any workflow related data at the time of submitting. (If data from later phases of the workflow are needed, use Workflow Post Step Logic.) To access data stored with the method withDataMap(Map dataMap) in the message templates, you need to access the context variable workflowHistory.dataMap.

Example:

Workflow code
def map = [test: "This is test"]
workflow.withDataMap(map)
Message template code
$workflowHistory.dataMap.test$

Templates for Messaging in Unity

The following templates relate to the messaging functionality in Unity (available for Quotes, Agreements/Promotions or Rebate Agreements):

  • emailBody_requestInfo
  • emailSubject_requestInfo

In these templates you can work with the following variables:

  • $requester – Sender of the message. It is the user object for which which you can access fields such as firstname, lastname etc.
  • $recipient – Recipient of the message. It is the user object for which which you can access fields such as firstname, lastname etc.
  • $baseURL – URL of the Pricefx application. You can append to it a specific string pointing to e.g. Agreements/Promotions and create a link to this part of the application.
  • $type – Allows you to find out in which context you are: it is either quote, contract or rebateagreement
    Instead of this variable you can also use one of the following three variables (isQuote, etc.) – their usage is similar.
  • $isQuote – Allows you to customize the template for quotes only. It returns true if $entity is a quote.
  • $isContract – Allows you to customize the template for Agreements/Promotions only. It returns true if $entity is an Agreement/Promotion.
  • $isRebateAgreement – Allows you to customize the template for rebate agreements only. It returns true if $entity is a rebate agreement.
  • $entity – Contains the whole object of a Quote, Agreement/Promotion or Rebate Agreement (based on the context). See this Knowledge Base article to learn how to find out which fields are available for use for a specific object.
  • $message – Body of the message which you type in the Messages tab of e.g. a Quote.
  • $msgEntity – Object of the message. In a thread, there is msgEntity created for each message sent within the conversation. You can work with its fields such as sender, recipient, date of sending, message body etc.

Examples

This will be replaced by the label of the quote:

$quote.label$

This block will be rendered conditionally:

(It works only with true values; it is not possible to use if( a == 'a') . This true/null element has to be visible in the line item logic on the quotes.)

$if(quote.additionalInfo3)$
  <p>
    <b> Additional info about the Quote: </b>$quote.additionalInfo3$
  </p>
$endif$

Adding "&approve" or "&deny" to the document link approves/rejects the document immediately after clicking on the link, skipping the dialog where users can add a comment.

"$baseURL$/pricefx/$partition$/directaction/approve/$workflow.externalActionToken$?output=html&approve"
"$baseURL$/pricefx/$partition$/directaction/deny/$workflow.externalActionToken$?output=html&deny"

Replacing "approve" or "deny" in the document link with "form" displays a dialog with both Approve and Deny buttons.

"$baseURL$/pricefx/$partition$/directaction/form/$workflow.externalActionToken$?output=html"

(info) If the $partition$ variable is not present,  you can use $entity.partition$.

(tick) When you check the JSON structure of the underlying item (using Chrome Developer tools), all attributes should be accessible through the $entity reference. In addition, there are variables like $entity.partition which are not visible in this JSON representation, but they are part of the object in the backend.



More advanced example: it iterates through line items and conditionally shows the line items with workflow with colors. 

Enhanced email template
<body>
Quote $quote.uniqueName$ - $quote.label$ created by $quote.createdByName$ requires your approval.<br/><br/>
Quote details: 
<p>
  <b>Customer:</b> $quote.customerId$  $quote.CustomerName$<br/>
<br/>
<b>Target date:</b> $quote.targetDate; format = "MM/dd/yyyy"$ <br/> 
<b>Expiry date:</b> $quote.expiryDate; format = "MM/dd/yyyy"$<br/>
  <b>Margin:</b> $quote.outputsMap.Margin.result;format = "##.##%"$<br/>
  <b>Total Price:</b> $quote.outputsMap.TotalPrice.result;format = "#,###.####"$USD<br/>  

  </p>

<table style="border: 1px solid black;border-collapse: collapse;">
<tr>
  <th style="border: 1px solid black;" >Product</th>
  <th style="border: 1px solid black;" >Quantity</th>
  <th style="border: 1px solid black;" >Total Cost</th>
  <th style="border: 1px solid black;" >Total Price</th>
  <th style="border: 1px solid black;" >Margin</th>
  <th style="border: 1px solid black;" >Δ List</th>
  <th style="border: 1px solid black;" >Δ Target</th>
  <th style="border: 1px solid black;" >Δ Floor</th>
  <th style="border: 1px solid black;" >Is Index Product</th>

  </tr>
$quote.lineItems:{ item |
  $if(item.outputsMap.hasWorkflow.result )$
  <tr>
  	<td style="background-color: #FE6464;border: 1px solid black;" width = "400">$item.sku$ - $item.label$</td>
	<td style="background-color: #FE6464;border: 1px solid black;text-align:right">$item.outputsMap.Quantity.result;format = "#,###.####"$ $item.outputsMap.UoM.result$</td>
    <td style="background-color: #FE6464;border: 1px solid black;text-align:right">$item.outputsMap.TotalCost.result;format = "#,###.####"$ $item.outputsMap.CustomerCurrency.result$</td>
    <td style="background-color: #FE6464;border: 1px solid black;text-align:right">$item.outputsMap.TotalPrice.result;format = "#,###.####"$ $item.outputsMap.CustomerCurrency.result$</td>
    <td style="background-color: #FE6464;border: 1px solid black;text-align:right">$item.outputsMap.Margin.result;format = "#,###.####"$ $item.outputsMap.CustomerCurrency.result$</td>
    <td style="background-color: #FE6464;border: 1px solid black;">$item.outputsMap.DeltaList.result;format = "##.##%"$</td>
    <td style="background-color: #FE6464;border: 1px solid black;">$item.outputsMap.DeltaTarget.result;format = "##.##%"$</td>
    <td style="background-color: #FE6464;border: 1px solid black;">$item.outputsMap.DeltaFloor.result;format = "##.##%"$</td>
    <td style="background-color: #FE6464;border: 1px solid black;">$item.outputsMap.IsIndexProduct.result$</td>

 </tr>
  $else$
    <tr>
  	<td style="border: 1px solid black;" width = "400">$item.sku$ - $item.label$</td>
	<td style="border: 1px solid black;text-align:right">$item.outputsMap.Quantity.result;format = "#,###.####"$ $item.outputsMap.UoM.result$</td>
    <td style="border: 1px solid black;text-align:right">$item.outputsMap.TotalCost.result;format = "#,###.####"$ $item.outputsMap.CustomerCurrency.result$</td>
    <td style="border: 1px solid black;text-align:right">$item.outputsMap.TotalPrice.result;format = "#,###.####"$ $item.outputsMap.CustomerCurrency.result$</td>
    <td style="border: 1px solid black;text-align:right">$item.outputsMap.Margin.result;format = "#,###.####"$ $item.outputsMap.CustomerCurrency.result$</td>
    <td style="border: 1px solid black;">$item.outputsMap.DeltaList.result;format = "##.##%"$</td>
    <td style="border: 1px solid black;">$item.outputsMap.DeltaTarget.result;format = "##.##%"$</td>
    <td style="border: 1px solid black;">$item.outputsMap.DeltaFloor.result;format = "##.##%"$</td>
    <td style="border: 1px solid black;">$item.outputsMap.IsIndexProduct.result$</td>

 </tr>
  $endif$
}$
</table>
<br/>
Possible actions:<br/> 
<A HREF = "$baseURL$/priceFxWeb.html?targetPage=priceShopPage&targetPageState=$quote.typedId$">View the quote in a browser <A/><br/>
or <br/>
<A HREF = "https://pfx.cs60.visual.force.com/apex/Quote_Configurator?sfdc.tabName=01r3C000000Gu7L&typeId=$quote.typedId$">View the quote in SFDC <A/><br/>
  
or  
  <A HREF = "$baseURL$/pricefx/$partition$/directaction/approve/$workflow.externalActionToken$?output=html">Approve the quote now<A/><br/>
or<br/>
<A HREF = "$baseURL$/pricefx/$partition$/directaction/deny/$workflow.externalActionToken$?output=html">Deny the quote now<A/><br/>
</body>
</html>  

Note on Arrays

Sometimes you may have to do some work with arrays.

Typically, this type of work should not be done in the presentation layer, and so StringTemplate only has very limited support for this using the following functions: first(), last(), rest(), trunc(), strip() and  length(). These functions can be used in conjunction with each other for more specific needs.

An example showing how to obtain a property of a quotes first line item:

$first(quote.lineItems).outputsMap.SomePropertyWeNeed.result$

Accessing an array like array[index] as you would expect is not possible.

There are however some workarounds, such as first(rest(array)), which would return the second item in the array.

As you can see, this can quickly get messy, so the true solution would be to take such logic out of the presentation layer altogether if possible.


Found an issue in documentation? Write to us.