Migrating Existing Projects to Salesforce DX
Identifying conflicts with package folders during a Salesforce DX migration.
In order to save a Quote as a PDF, provided you have the Quote ID, you simply have to leverage the following code (which in this case is wired up to the “Save to Quote” button.
// Assuming quote is a Quote variable set in the controller
public PageReference saveQuoteAsPDF()
{
PageReference pr = Page.VisualforceQuotePDF;
pr.getParameters().put('id', quote.id);
Blob content = pr.getContentAsPDF();
QuoteDocument doc = new QuoteDocument(Document = content, QuoteId = quote.id);
Database.SaveResult insertResult = Database.Insert(doc, false);
// check for errors here and act according!
System.debug('Result: ' + insertResult);
System.debug('Quote PDF created: ' + doc.Id);
//upon completion redirect to quote
PageReference quotePage = new PageReference('/' + quote.id);
quotePage.setRedirect(true);
return quotePage;
}
Pretty impressively, the above code will actually treat the Quote as a new version and name it accordingly.
There are some good posts around sending emails with APEX, as seen here and here. I had a slightly different need, as I was not automating an email, but instead wanted to save the Quote and then allow the user to leverage Salesforce’s email page to create a personalized message with the Quote PDF attached.
Completing this task is pretty simple as well, once you get used to interpreting Salesforce.com URLs. By essentially replicating this process via the UI (clicking the default Save & Email Quote button) you can see what the URL parameters look like. Then, in your APEX code, you can replicate the same URL pattern. While there is always the caveat of Salesforce changing their URL param structure in the future, I haven’t had any issues with it in the past, and there are plenty of other snippets of code out there that leverage URL parameter customization (particularly if you want to navigate to a Page Layout and populate some fields based on where you came from).
// Assuming quote is a Quote variable set in the controller
// Assuming quoteContact is the contact on the Quote object
public PageReference saveQuoteAsPDFandEmail()
{
PageReference pr = Page.VisualforceQuotePDF;
pr.getParameters().put('id', quote.id);
Blob content = pr.getContentAsPDF();
QuoteDocument doc = new QuoteDocument(Document = content, QuoteId = quote.id);
Database.SaveResult insertResult = Database.Insert(doc, false);
// check for errors here and act according!
System.debug('Result: ' + insertResult);
System.debug('Quote PDF created: ' + doc.Id);
//upon completion redirect to quote
String emailURL = '/_ui/core/email/author/EmailAuthor?p3_lkid=' + quote.Id + '&doc_id=' + doc.Id + '&retURL=%2F' + quote.Id;
if (quoteContact != null)
{
emailURL += '&p2_lkid=' + quoteContact.Id;
}
System.debug('Quote Email URL: ' + emailURL);
PageReference quotePage = new PageReference(emailURL);
quotePage.setRedirect(true);
return quotePage;
}
In this example, we also leverage the Contact on the Quote to set an initial “To” address. You can also see the quote ID and doc ID (the new Quote PDF we saved) in the URL params. You have the ability to add even more fields, such as the subject, if you want.
An added benefit of this logic is that it allows you to attach different business logic to your users’ ability to create Quote PDFs. For instance, if they are discounting products too heavily, you can simply not render the save buttons, or even the Quote PDF itself, and instead relay a message to the user that they need to submit the quote for approval first.