Now, Generating a Quote PDF is a breeze Using Salesforce Flow! Learn how!

Now, Generating a Quote PDF is a breeze Using Salesforce Flow! Learn how!

Last Updated on April 23, 2022 by Rakesh Gupta

The last thing you want your Sales teams to do is to get ensnared in manual – or procedural – activities; they are your horsepower, free them up to do what they do best – Sell! Does that mean activities – not directly related to selling – can be eschewed? Far from it! 

Let us have our cake and eat it too – think automation!!

Multiple research affirms the positive impact of automation on the bottom line! By leveraging automation, we can ensure that activities – not directly related to sales – get done without burdening your sales team. 

Let us take a simple use case – generating a quote PDF whenever a customer is ready to receive a formal proposal containing the most current pricing information and product quantities. To generate a quote pdf should not require salespeople to click a button! And, thanks to Salesforce Flow, we can make that a reality!

Objectives:

After reading this blog, you’ll be able to: 

  • Understand what a Quote is
  • Use filters and conditions to design a flow
  • Understand the Apex callout process in Salesforce Flow

Business Use case

Martin Jones is a System Administrator at Gurukul on Cloud (GoC). He received a requirement to auto-generate a quote pdf whenever a quote gets created (only if Opportunity amount is greater than 0) so that salespeople can spend less time in Salesforce and more time selling.  

What is a Quote?

A quote is a detailed list – of products or services with prices, shipping and billing addresses, payment terms and taxes, etc. – that is sent by a seller to a prospective buyer. Quotes usually have different statuses (Draft, In Review, Presented, Approved, Rejected, or Cancelled) depending on the stage of the sales process.

As of Winter’22 release, salespeople had to manually generate a quote pdf by clicking on the Generate PDF button. We can do better than that as automation champions – let us automate this process. 

Automation Champion Approach (I-do):

Usually, with Salesforce, multiple approaches are available to solve a business requirement. Choose the ones that are simple, straight forward, and consume fewer resources. 

Similarly in this scenario, either use Apex trigger or a combination of Flow and Process Builder.

Let us solve this scenario using After-save Record-Triggered Flow and Apex – as this business case involves generating PDF out of a quote record. Check out this article to understand why we are using after-save record-triggered flow for this scenario.

Before discussing the solution, let me show you a diagram of a Process Flow at a high level. Please spend a few minutes going through the following Flow diagram and understand it. Screen Shot 2020-06-17 at 1.01.02 AM Let’s begin building this automation process.

Guided Practice (We-do):

There are 3 steps to solve Martin’s business requirement using After-save Record-Triggered Flow. We must:

  1. creating a custom label to store Quote Template Id
  2. Create Apex class & Test class
  3. Salesforce flow
    1. Define flow properties for record-triggered flow
    2. Create a formula to determine whether the quote record is new or old
    3. Add a decision element to check if the opportunity amount is greater than $0
    4. Add action – call an Apex class to generate a quote pdf

Step 1: Creating a Custom Label 

  1. Click Setup.
  2. In the User Interface, type Custome Labels.
  3. Click on the New Custom Label button.
  4. Enter Short Description the Name will auto-populate. 
  5. Now enter the Quote Template Id in the Value.
  6. Click Save

PB 96.1

Step 2: Create an Apex class and Test class   

  1. Click Setup.
  2. In the Quick Find box, type Apex Classes.
  3. Clicks on the New button.
  4. Copy code from GitHub and paste it into your Apex Class. 
  5. Click Save.

PB - 97.3.45 Repeat the above steps and click the Test class. You can get the code from my GitHub repo. 

Step 3.1: Salesforce Flow – Define Flow Properties

  1. Click Setup.
  2. In the Quick Find box, type Flows.
  3. Select Flows then click on the New Flow.
  4. Select the Record-Triggered Flow option and click on Next and configure the flow as follows:
    1. How do you want to start building: Freeform
    2. Object: Quote
    3. Trigger the Flow When: A record is created or updated
    4. Set Entry Criteria
      1. Condition Requirements: None
    5. Optimize the Flow For: Action and Related Records
  5. Click Done.

Tips: Never try to write entry criteria in a Record-Triggered Flow. 

Step 3.2: Salesforce Flow – Formula to Determine Whether the Quote Record is New or Old

  1. Under Toolbox, select Manager, then click New Resource to determine whether the record is new or old
  2. Input the following information:
    1. Resource Type: Formula
    2. API Name: forBIsNew
    3. Data Type: Boolean
    4. Formula: IsNew()
  3. Click Done.

Step 3.3: Salesforce Flow – Using Decision Element to Check the Opportunity Amount

Now we will use the Decision element to check the opportunity amount to ensure that it is greater than $0.

  1. Under Toolbox, select Element.
  2. Drag-and-drop Decision element onto the Flow designer.
  3. Enter a name in the Label field; the API Name will auto-populate.
  4. Under Outcome Details, enter the Label the API Name will auto-populate.
  5. Condition Requirements to Execute Outcome: All Conditions Are Met (AND)
    1. Row 1:
      1. Resource: {!$Record.OpportunityId}
      2. Operator: Is Null
      3. Value: {!$GlobalConstant.False}
    2. Add Condition
    3. Row 2:
      1. Resource: {!$Record.Opportunity.Amount}
      2. Operator: Greater Than
      3. Value: 0
    4. Add Condition
    5. Row 2:
      1. Resource: {!forBIsNew}
      2. Operator: Equals
      3. Value: {!$GlobalConstant.True}
  6. Click Done.

Step 3.4: Salesforce Flow – Adding an Action to Call Apex class to Generate Quote PDF

  1. Under Toolbox, select Element.
  2. Drag-and-drop the Actions element onto the Flow designer.
  3. Select the GenerateQuotePdfDocument Apex class. 
  4. Enter a name in the Label field- the API Name will auto-populate.
  5. Set Input Values:
    1. Field: quoteIds
    2. Value: {!$Record.Id}
  6. Click Done.

In the end, Martin’s Flow will look like the following screenshot (I turned on Auto-Layout) for this flow:

Once everything looks good, perform the steps below:

  1. Click Save.
  2. Enter Flow Label the API Name will auto-populate.
  3. Click Show Advanced.
  4. API Version for Running the Flow: 53
  5. Interview Label: Record-Trigger: Quote After Save {!$Flow.CurrentDateTime}
  6. Click Save.

Almost there! Once everything looks good, click the Activate.

It’s time to test this feature!

Next time, when a Sales rep creates a quote and associates it with Opportunity (obviously Opportunity amount must be greater than 0) then, then Salesforce Flow will fire and auto-generate a quote pdf for it. 

Great! You are done! Feel free to modify it based on your business requirement. 

Formative Assessment:

I want to hear from you!

What did you learn from this post, is it relevant to you, and how will you modify the concepts taught in the post for your own business processes?

Make a post and tag me on Twitter @automationchamp using #AutomationChampionFlow.

Have feedback, suggestions for posts, or need more information about Salesforce online training offered by me? Say hello, and leave a message!
Preferred Timing(required)

51 thoughts on “Now, Generating a Quote PDF is a breeze Using Salesforce Flow! Learn how!

  1. Hi Rakesh,

    Could you please help me find the quoteTemplateId? I followed your previous comment but could not find it. I also tried querying an bunch of Quote and template objects to find it but couldn’t find any records. But, I have a standard quote template and a custom template for quote PDF in my org. Could you suggest in details where I can find it?

    Thank you

    1. In Step 1, I am storing the quote template ID in a custom label. Feel free to store it in a Custom Metadata Type instead.

      To find the Quote Template ID in Salesforce, you typically follow these steps:

      1. Log in to Salesforce
      2. Navigate to Setup | Feature Settings | Sales | Quotes | Quote Templates
      3. View Quote Template
      4. Grab the ID from the URL

  2. Hi Rakesh,
    I have implemented the Apex class the following requirement: I need to create a button on the Opportunity object. When this button is clicked, it should check if the Opportunity’s stage is ‘Paid’. If it is, the system should create a Quote and its associated Quote Line Items. Then, it should generate a PDF using a predefined Quote template. However, I’m encountering an issue where the Quote PDF does not include the Quote Line Items. Is there any way to check why the PDF is not including the line items?

  3. Hello,
    I solved the error of the missing footer by changing apex code from ” quoteUrl += ‘&headerHeight=197&footerHeight=10’;” to ” quoteUrl += ‘&headerHeight=197&footerHeight=80’;” enables to show the footer.
    Thank you for this shared Class
    Regards

  4. Hello Rakesh
    Thank you for this great flow.
    The PDF does not render the footer added in the Quote template. Any idea to improve this ?

  5. This is really great, but I am running into an issue where the Quote PDF does not include the Quote line items. I updated the Flow to run on a scheduled path delayed 0 minutes and it worked great. However, adding the scheduled path seems to cause 0% code coverage when I try to deploy it. Any ideas what I might be doing wrong?

  6. Hi Rakesh

    I followed the steps you provided, but I encountered an issue where the quote PDF is not being generated. Upon debugging the flow, I noticed that the output of the Apex action is returning null.”

  7. I’m having a problem with the header of the PDF, when i create an automated PDF, it has a blank space on header. When i preview it in Quote Templates it not appears. Any thoughts?

  8. Hello – I used you directions and 99% is working great. The only problem I have is that the footer does not show up on the automated quote PDF’s. If I manually click the button the footer shows up, but it is not there on the automatically generated quotes. Do you have a suggestion on what is causing this?

    Thanks!

  9. Hello
    I used your code in apex and i have no idea why created PDFs are blank.
    It look likes, there are products in PDF because i can see for example: Grand total fields, but when i open the page is blank.
    Any ideas?
    Thanks.

  10. Hi Rakesh,

    Thsnks so much for sharing the code!

    Well, I’m trying to assign a dynamic value to quoteTemplateId.

    In order to test that, I’ve created a new variable, called “labelName”, and set it the value of ‘QuoteTemplateDivMedica’.

    String labelName = ‘QuoteTemplateDivMedica’;

    After, I’ve set the quoteTemplateId value:

    //Get the Quote Template Id from Custom Settings
    String quoteTemplateId = ‘Label.’+ labelName;

    The final quoteUrl value seems to be as expected, since it results in the following string:

    /quote/quoteTemplateDataViewer.apexp?id=0Q0760000004rZCCAY&headerHeight=197&footerHeight=10&summlid=Label.QuoteTemplateDivMedica

    However, when I execute it within an anonymous apex code, I get an error with the message ‘Internal Salesforce.com Error’

    Any guess on how to solve this issue?

    Thanks,
    Gabriel

  11. I greatly appreciate this code. We’ve been looking at doing this for a while and now I’m starting to get in Apex so we can.

    Question for you, how do I add another input variable? I’m actually using this to call 2 different invoice templates and wish to base this on another value to pass from a Flow. I’ve added the if statement, I’m just not sure how to populate the variable.

  12. I used your code above to remove the references to recordtype in opportunities and when I run the test it passes but my code coverage is still 0% any suggestions on why that would be?

  13. This is working amazing in my sandbox but I can’t deploy to production due to code coverage. It says code coverage is 0% and I need at least 75%. I’m not a dev so I’m not really sure what to do here, any advice?

      1. It looks like my orgs overall code coverage is only 73% which some have said could be why it’s not deploying. Could that be true?

      2. Actually now as I’m looking at the coverage in my sandbox it’s saying 0/22 and 0%. It seems I’ve missed something somewhere. I ran the test and it passed but still says 0%

  14. Hi,

    This solution looks amazing, but I can not make it work because I’m using CPQ, and my knowledge related to APEX is not that complete,

    Is there anyway to see this same code but adapted to be able to work with SBQQ__Quote__c?

    Thanks so much in advance

    1. This is also something I am very interested in! I would love to be able to have an easy screen flow as well for our Sales Staff to product documents.

  15. HI , Team i need a solution for Custom Quote pdf generation.
    i am done the vf and apex class but button on PDF how to do, any idea.
    {save and email quote } && {save to quote} how to create these on PDF why because i an customizing total pdf.

  16. Hi there, I am using this and it has been working wonderfully, but I have had one issue when I updated the quote template to add some more details to the footer of the quote. For some reason when it is manually generated, the footer shows up blank. When I manually click to generate the PDF quote it shows up. Any thoughts on why this could be?

  17. I am calling this Apex from a screen flow that allows the user to input some relevant quote information before generating the quote and pdf. When I run the debug from the flow, it works wonderfully. When I run the flow from a lightning action, the pdf displays blank. I checked the debug logs for both instances and they’re practically identical so I can’t tell where it’s broken. Any thoughts?

  18. Hi Rakesh, I have an error on the test class. Error: Compile Error: Variable does not exist: RecordTypeId at line 25 column 12.
    I removed the “AND developerName = ‘Manufacturing'” as I don’t need it but still not working. Any idea why? I would also like to attach the PDF to a custom object instead of the opportunity. But let’s start to make it work 🙂

    1. If you are not using the RecordType in Opportunity, then remove all references. Like the following code:

      @istest
      private class generateQuotePdfDocumentTest {

      @testSetup
      static void setup() {

      Product2 product = new Product2();
      product.Name = 'Test Product ';
      product.ProductCode = '123';
      product.IsActive = true;
      insert product;

      PricebookEntry pbe = new PricebookEntry();
      pbe.Pricebook2Id = Test.getStandardPricebookId();
      pbe.Product2Id = product.Id;
      pbe.IsActive = true;
      pbe.UnitPrice = 10;
      insert pbe;

      Opportunity op = new Opportunity();
      op.Name = 'Test';
      op.Type = 'Value Proposition';
      op.Amount= 1200;
      op.CloseDate = Date.today().addDays(2);
      op.StageName = 'Created';

      insert op;

      Quote quote = new Quote();
      quote.OpportunityId = op.Id;
      quote.Name = 'TestQuote';
      quote.ExpirationDate = Date.today().addDays(5);
      quote.Status = 'Draft';
      quote.Pricebook2Id = Test.getStandardPricebookId();
      insert quote;

      QuoteLineItem qli = new QuoteLineItem();
      qli.QuoteId = quote.Id;
      qli.Quantity = 2;
      qli.PricebookEntryId = pbe.Id;
      qli.UnitPrice = 20;
      insert qli;
      }

      @isTest
      static void generateQuotePdfTest() {

      Quote quote = [SELECT Id, Status FROM Quote LIMIT 1];

      quote.Status = 'Draft';
      update quote;
      }

      }

  19. Awesome stuff Rakesh! I found this article yesterday and gave it a try with Flow. I was able to repurpose it for our Quote Process and have the PDF generated automatically at the end of a guided screen flow.
    Just working on attaching the PDF and emailing it to the related contact now (also in Flow).
    One other thing, i’ve never written an APEX class and test class before, so quite happy that I was able to take yours and adjust it to my requirements.
    Thanks for the great content!
    Paul

  20. I love that you have Conga and Docmotion as sponsors and yet chose to publish this kind of article, kuddos to you Sir !

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Automation Champion

Subscribe now to keep reading and get access to the full archive.

Continue reading