Table of Contents
Create Quote Document
- App Launcher
- Salesforce CPQ
- Quotes
- All – List View
- Select appropriate quote
- Generate Document
- Preview
- X – close
- Save & Email
- Send
- Reopen Quote
- Related
- Quote Documents – Related List – the document exists here
Create your own template
- Without changes you get a simple template
- Quote Template
- New
- Specify name
- Default – set it as default
- Top Margin
- Specify Company Name
- Specify Company Slogan
- Specify Company Phone
- Specify Shading Color – e.g.:
CCEEFF
- Save
The new template will now be used and tested in a corresponding quota.
Add watermark
Find document ID of the watermark
Switch to Salesforce Classic
- Switch to Salesforce Classic
- + – Icon – Tabs
- Documents
- Go!
- Select document
- Select and copy the ID in the URL
- Switch to Lightning Experience
Specify watermark in Quote Template
- Quote Templates
- select appropriate template
- Edit
- Specify Watermark ID – Insert ID
- Save
Show watermark
- is not displayed by default
- Enable Watermark Shown – at the Quote

Use your own watermark
- Upload PNG file under Documents
- Activate Externally Available Image
Template building blocks
- Template contents are the building blocks/puzzle pieces
- so many template contents are created
- Templates are created from this library
Content via HTML editor
- Template Content
- News
- Select Content Type – e.g.: HTML
- Continue
- Specify name
- insert HTML accordingly
- Fields can be inserted as follows
{!template.SBQQ__CompanyName__c} {!salesRep.Name} {!salesRep.Email} {!template.SBQQ__CompanyPhone__c}
Possible data sources
- !quote = Quotes
- !primaryContact = Contact, which is referenced with Quote
- !salesRep = User, which is referenced with Quote
- !template = Quote template
- !document = Quote document
- Data from other sources can only be transferred to these objects via formula fields and thus integrated into the template (only !quote, !template and !document)
Add style – HTML inline CSS
Example:
<table border="1" cellpadding="1" cellspacing="1" style="width:500px;">
<tbody>
<tr>
<td style="width: 35%; padding: 3px; background-color: #{!template.SBQQ__ShadingColor__c};">Prepared For</td>
<td style="width: 35%; padding: 3px; background-color: #{!template.SBQQ__ShadingColor__c};">Prepared By</td>
</tr>
<tr>
<td style="padding: 3px; border: solid black;">
{!quote.SBQQ__BillingName__c}<br />
{!primaryContact.Name}<br />
{!primaryContact.Email}<br />
{!primaryContact.Phone}
</td>
<td style="padding: 3px; border: solid black;">
{!template.SBQQ__CompanyName__c}<br />
{!salesRep.Name}<br />
{!salesRep.Email}<br />
{!template.SBQQ__CompanyPhone__c}
</td>
</tr>
</tbody>
</table>
Add template content to the template
- Quote Templates
- Select appropriate template
- Related
- Section – Related List – New
- Specify section name
- Select Content
- Specify Display Order – Defines the order of all contents in the template – e.g.
10
- Save
Configuration can now be tested on corresponding quota.
Multiple templates in one
- when a section appears is controlled by Conditional Print Field

- Setup
- Object Manager
- Quote
- Fields & Relationships
- New
- Select Checkbox
- Next
- Select Label
- Next
- Next
- Save
Expand Picklist with the new field created at the quote:
- Object Manager
- Template Section
- Fields & Relationships
- Select Conditional Print Field
- New – Add value
- Specify API name of the new field created above
- Save
Now just create the template content. Add this to the Quote Template in the Section area and select the appropriate field in the „Conditional Print Field“ field.
Simple header
- Template Content
- New
- Select HTML
- Continue
- Specify Content Name
- Source
<table border="1" cellpadding="1" cellspacing="1">
<tbody>
<tr>
<td>
<p style="font-size: 16px">Quote {!quote.Name} v{!document.SBQQ__Version__c}</p>
<p style="font-size: 12px; color:#D3D3D3;">Expires {!quote.SBQQ__ExpirationDate__c}</p>
</td>
<td>
<p style="text-align: right;"><img height="40" src="https://developer.salesforce.com/files/awcomputinglogo.png" /></p>
</td>
</tr>
</tbody>
</table>
- Save
- Quote Templates
- select appropriate template
- Edit
- Header Content – select corresponding template content
- Exclude Header & Footer – select e.g.:
First Page
- Header Height – e.g.:
60
– so that it does not overlap with other content - Save
Reverse condition
- currently header is skipped on the first page – cover page
- some quotes have no cover page
- therefore they would start directly with contact details – does not look good
- therefore header should be displayed on the first page
- Solution:
- Create template content for the header
- make it dependent on a formula field (checkbox)
- Returns the opposite of „Include cover page
Create formula field:
- Setup
- Object Manager
- Quote
- Fields & Relationships
- New
- Formula
- Next
- Label angeben
- Checkbox
- Next
- Specify corresponding formula – e.g.:
IF(Include_Cover_Page__c, false, true)
- Next
- Next
- Save
Add this field again per API name of the Picklist Conditional Print Field at the Template Section object! Then only adjust the template.
- Quote Template
- select appropriate template
- Related
- Sections – Related List – New
- Specify section name
- Cortent – specify corresponding template content
- Display Order – e.g.:
1
- Bottom Margin – e.g.:
0.25
- Conditional Print Field – select the appropriate field
- Save
Show offer items
- Template Content
- New
- Line Items
- Continue
- Specify Content Name
- Save
Show offer items
- Template Content
- New
- Line Items
- Continue
- Specify Content Name
- Save
- Quote Template
- select appropriate template
- Sections – Related List – New
- Select content – specify corresponding template content
- Specify Display Order – e.g.:
30
- Save
The column representations can be customized in the Quote template in the Related List Line Columns.
- Column header
- Display order – left to right
- Width (%) – all columns together i.e. max. 100
- Field name
Show columns conditionally
- Show columns only when applied
- Controlled with Conditional Print Field

- Quote Template
- select appropriate template
- Related
- Line Columns – Related List – New
- Display Order – e.g.:
70
- Field Name – e.g.:
SBQQ__PartnerDiscount__c
- Width – e.g.:
10
- Select Alignment – e.g.:
Right
- Specify Conditional Print Field – e.g.:
SBQQ__AveragePartnerDiscount__c
- Save
Repeat procedure with corresponding fields!
If columns are hidden, missing width is added to the widest column. This can be prevented with „Discard Width When Hidden„.

Influence appearance
- Separate Line – Checkbox
- Hide On Product Options – checkbox
- Table Style – Table style (selection list)
- Hide Column Header – checkbox
- Show Discount Schedule – checkbox
- Line Sort Field – line orientation field (selection list)
Multiple line item tables
- More than just a table
- one reduced table
- another one with more details
- columns can be assigned with Section
- If Section is left empty, column appears in each section
Quote Line Items Group
Text formula field for separation
- Setup
- Object Manager
- Quote Line
- Fields & Relationships
- New
- Formula
- Next
- Specify name – e.g.:
Purchase Type
- Text
- Next
- specify corresponding formula – e.g.:
IF(ISPICKVAL(SBQQ__SubscriptionPricing__c, ""), "One-time Purchases", "Subscriptions")
- Next
- Next
- Save
Picklist Field – Quote Template
- Object Manager
- Quote Template
- Fields & Realtionships
- Select Group Fields
- Value Range – New
- Specify name – API name of the newly created grouping field – e.g.:
Purchase_Type__c
- Save
Customize template for grouping
- Quote Templates
- select appropriate template
- Edit
- Specify Group Shading Color – e.g.:
F3F3F3
- Specify Group Font Size – e.g.
14
- Select Group Field – API name of the field to be grouped – e.g.:
Purchase_Type__c
- Save
Groups within groups – subgroups
- Subgroup with additional field – e.g.:
Product Family
- Quote Templates
- select appropriate template
- Edit
- Select Sub Group Field – e.g.:
Product Family
- Save
CPQ should still sum up at least one row column.
- Related – Tab
- Line Columns – Related List –
View All
- Related Column –
Edit
- Select Summary Level –
Sub Group
- Select Summary Function –
SUM
- Save
Repeat this with further columns accordingly:
- corresponding column – Edit
- Select Summary Level –
Sub Group
- Specify Sub Group Summary Label – e.g.:
{0} Subtotal
- Save
Adjust sums
- Fields that can affect totals
Field name (object) | Effects with sums |
Print Quote Totals (Template Section) | Checkbox - in case of grouping - total sum displayed according to group tables |
Subtotal Fields (Quote Templates) |
Adds selection between the following:
|
Show Customer Discount & Customer Discount Field (Quote Templates) |
Picklist & checkbox selected:
|
Show Partner Discount (Quote Templates) | If enabled - amount partner discount added. |
Total Field (Quote Templates) |
Displays choices between the following:
Shows list price if empty. |
Hide Group Subtotals (Quote Templates) |
If activated and no grouping = subtotal hidden. If enabled and grouping = subtotal and total hidden. |
Hide Totals (Quote Templates) | If activated and no grouping = total hidden |
Summary Display (Template Section) |
Always shows independently of "Hide group subtotal" or "Hide sum":
|
Hide Quote Lines
Field name (object) | Effects on visibility |
Hide Component Products (Quote Template) | Removes all products that are option for package. |
Show Bundled Products (Quote Template) | Options marked as "Bundled" are displayed. |
Show all Package Products (Quote Template) | Parent "virtual bundle" with zero values are displayed. |
Quote Line Visibillity (Product Option) | line of the option are removed with "Never" or "Only Editor". |
Show Renewed Products (Quote Template) | Parent and sibling products without subscription to a renewed subscription are displayed in a renewal offer. Result affected by "Show Bundled Products" and "Show All Package Products". |
Hide Quote Lines with Filters
- Example – Hide rows marked as optional
- Quote Template
- select appropriate template
- Related – Tab
- Sections – Related List – Edit at corresponding section
- Select Filter Field – e.g:
Optional
- Select Filter Operator – e.g.:
equals
- Specify Filter Value – e.g.:
false
- Save
Custom Code
- very flexible solution with Apex and Visualforce
1. create apex class
- Setup
- Apex Classes
- New
Example:
public class CustomTemplateController{
public string quoteId {get; set;}
public string templateId {get; set;}
public List<SBQQ__QuoteLine__c> lines {get; set;}
public List<SBQQ__QuoteLineConsumptionSchedule__c> linesWithConsumptionSchedules {get; set;}
public List<SBQQ__QuoteLineConsumptionRate__c> consumptionRates {get; set;}
public List<Id> lineIDsWithCS {get; set;}
public SBQQ__QuoteTemplate__c template {get;set;}
public boolean showConsumptionSchedule {get;set;}
public CustomTemplateController(){
quoteId = ApexPages.currentPage().getParameters().get('qid');
templateId = ApexPages.currentPage().getParameters().get('tid');
lineIDsWithCS = new List<Id>{};
consumptionRates = new List<SBQQ__QuoteLineConsumptionRate__c>{};
showConsumptionSchedule = false;
this.populateTemplate();
this.populateLineData();
this.populateCSData();
}
public void populateTemplate(){
template = [SELECT Id, SBQQ__FontFamily__c, SBQQ__FontSize__c, SBQQ__ShadingColor__c FROM SBQQ__QuoteTemplate__c WHERE Id = :templateId];
}
public void populateLineData(){
lines = [SELECT Id, SBQQ__HasConsumptionSchedule__c FROM SBQQ__QuoteLine__c WHERE SBQQ__Quote__c = :quoteId ORDER BY SBQQ__Number__c ASC];
for(SBQQ__QuoteLine__c line : lines){
if(line.SBQQ__HasConsumptionSchedule__c){
lineIDsWithCS.add(line.Id);
showConsumptionSchedule = TRUE;
}
}
}
public void populateCSData(){
linesWithConsumptionSchedules = [SELECT Id, SBQQ__QuoteLine__r.SBQQ__ProductName__c, Name, SBQQ__UnitOfMeasure__c, (SELECT Id, SBQQ__LowerBound__c, SBQQ__UpperBound__c, SBQQ__Price__c, SBQQ__QuoteLineConsumptionSchedule__r.SBQQ__QuoteLine__c FROM SBQQ__QuoteLineConsumptionRates__r ORDER BY SBQQ__ProcessingOrder__c) FROM SBQQ__QuoteLineConsumptionSchedule__c WHERE SBQQ__QuoteLine__r.Id IN :lineIDsWithCS];
for(SBQQ__QuoteLineConsumptionSchedule__c schedule : linesWithConsumptionSchedules){
for(SBQQ__QuoteLineConsumptionRate__c rate : schedule.SBQQ__QuoteLineConsumptionRates__r){
consumptionRates.add(rate);
}
}
}
}
- Save
2. create visualorce page
- Setup
- Visualforce Page
- New
- Specify Label
Example:
<apex:page contentType="text/xml" showHeader="false" sidebar="false" controller="CustomTemplateController" rendered="{!showConsumptionSchedule}">
<block font-size="{!template.SBQQ__FontSize__c}" font-family="{!template.SBQQ__FontFamily__c}" >
<table width="75%">
<table-column column-width="60%"/>
<table-column column-width="40%"/>
<table-header>
<table-row font-weight="bold" background-color="#{!template.SBQQ__ShadingColor__c}">
<table-cell padding="3px" border-style="solid" border-width="1px" text-align="left">
<block>
Consumption Schedules
</block>
</table-cell>
<table-cell padding="3px" border-style="solid" border-width="1px" text-align="center">
<block>
Rates
</block>
</table-cell>
</table-row>
</table-header>
<table-body>
<apex:repeat id="schedulerepeat" value="{!linesWithConsumptionSchedules}" var="schedule">
<table-row keep-together.within-page="always">
<table-cell padding="3px" border-style="solid" border-width="1px" text-align="left">
<block>
{!schedule.SBQQ__QuoteLine__r.SBQQ__ProductName__c} - {!schedule.Name} ({!schedule.SBQQ__UnitOfMeasure__c})
</block>
</table-cell>
<table-cell border-style="solid" border-width="0px" text-align="left">
<table border-collapse="collapse" >
<table-column column-width="50%"/>
<table-column column-width="50%"/>
<table-body>
<apex:repeat id="raterepeat" value="{!consumptionRates}" var="rate">
<apex:outputText rendered="{!rate.SBQQ__QuoteLineConsumptionSchedule__r.Id = schedule.Id}">
<table-row keep-together.within-page="always">
<table-cell padding="3px" border-style="solid" border-width="1px" text-align="center">
<apex:outputText rendered="{!NOT(ISNULL(rate.SBQQ__UpperBound__c))}">
<block>
{!rate.SBQQ__LowerBound__c} - {!rate.SBQQ__UpperBound__c - 1}
</block>
</apex:outputText>
<apex:outputText rendered="{!ISNULL(rate.SBQQ__UpperBound__c)}">
<block>
{!rate.SBQQ__LowerBound__c}+
</block>
</apex:outputText>
</table-cell>
<table-cell padding="3px" border-style="solid" border-width="1px" text-align="right">
<apex:outputText >
<block>
<apex:outputText value="{0,number,currency}">
<apex:param value="{!rate.SBQQ__Price__c}"/>
</apex:outputText>
</block>
</apex:outputText>
</table-cell>
</table-row>
</apex:outputText>
</apex:repeat>
</table-body>
</table>
</table-cell>
</table-row>
</apex:repeat>
</table-body>
</table>
<block> </block>
</block>
</apex:page>
- Save
3. Reference Visualforce page with custom content
- Salesforce CPQ
- via Navigation – Template Content
- New
- Custom
- Continue
- Specify Content Name – e.g.: A
W Consumption Schedules
- Custom Source – e.g.:
/apex/c__ConsumptionSchedulesVFP
- Save
- via Navigation – Quote Templates
- Select template
- Related – Tab
- Sections – Related List – New
- Specify section name
- Content – select appropriate template content
- Specify Top Margin – e.g.:
0.25
- Specify Display Order – e.g.:
40
- Save
Use prefabricated content
- for basic information in Quote Templates
- per Navigation – Template Content
- New
- Select Template Bottom
- Continue
- Enter content name – e.g.
AW Signatures
- Save
- per Navigation – Quote Templates
- Select Template
- Related – Tab
- Sections – Related List – New
- Specify section name
- Content – select appropriate template content
- Specify Top Margin – e.g.:
0.5
- Specify Display Order – e.g.:
50
- Save
Template conditions
- Offers also contain important conditions of the negotiated deal
- e.g. return policies – are defined as quotation policies
- Quote Term Record represents a part of the general terms and conditions of business
- should be included in the offer
- CPQ compiles quote terms into one block
- can be inserted into the template in any way
- for each term there is a field for printing order
- each Quote Term can be displayed under certain conditions
- per Navigation – Quote Templates
- New
- Quote Terms
- Continue
- Specify Content Name
- Specify Font Size
- Save
Quote Term Template is only a placeholder. Still needs to be inserted into a template section.
- per Navigation – Quote Templates
- Select Quote Template
- Related – Tab
- Sections – Related List – New
- Enter section name
- Content – select above created or corresponding Quote Template
- Specify Top Margin – e.g.:
0.25
- Specify Display Order – e.g.:
45
- Save
Create corresponding Quote Term.
- per Navigation – Quote Terms
- New
- Print Order – e.g.:
20
- Activate Active
- Body – specify the text to be displayed
- Save
For dynamic information, appropriate field placeholders (e.g.: {!quote.SBQQ__ExpirationDate__c}
) can be embedded to the quote data.
Organize terms
- with large collections of quote terms, text block can become unwieldy
- Solution: Parent-child relations between quote terms
- per Navigation – Quote Terms
- All – List View
- select corresponding Child-QT
- Parent Term – select corresponding parent QT
- Save
- repeat for further QTs
For a better clarification of the should additionally use the numbering.
- per Navigation – Quote Templates
- select appropriate template
- Edit
- Activate Number Terms
- Save
Split quota terms
- show at different places in the template
- create 2 template content records
- place them in 2 different Quote Template Sections
- Restrictions
- Parent and Childs can be separated
- numbering as if they were not childs
- if a quote term is not assigned to a template content, it will always be displayed
Quote term conditions
- Show Quote Terms only for specific sales
- Create a condition under which certain quote terms are hidden
- per Navigation – Quote Terms
- select corresponding QT
- Related – Tab
- Term Conditions – Related List – New
- Select Tested Field – Specify API name of the field to be tested – e.g.:
AccountSLA__c
- Select Operator – e.g.:
equals
- Specify Value – e.g.:
bronze, silver, gold
- Save
A parent element is hidden, then the corresponding child elements are also hidden.
- Alternatively, a summary variable can also be tested
- multiple conditions also possible
- each condition must be true by default – field Conditions Met by default
All
- Conditions Met =
Any
, then only one condition must be true - complex conditional logic also possible – Condition1=true OR Condition2 and Condition3 = true
- give index field unique value – e.g.:
100
,200
and300
- use these values in Advanced Condition accordingly – e.g.:
100 OR (200 AND 300)
- Conditions Met =
Custom
- give index field unique value – e.g.:
- each condition must be true by default – field Conditions Met by default
Users can customize conditions
- not necessary if the rules are formulated carefully
- at the Quote Record there is a button Modify Quote Terms
- list of assigned quote terms appears
- with click a simple editor appears
- saving does not change the original – CPQ creates a clone for this and assigns it to the current quote