I love Salesforce, but I fail to understand why the basic functionality like generating a presentable quotes PDF is not part of the standard out of the box functionality. Many of you may disagree because, salesforce.com does provide templates to modify the quotes.
But if you look at it closely, the page breaks are not consistent, if my product description is a little too long, the quote extends to multiple pages, without proper page breaks. So, I searched the internet for few solutions and found 1 good solution on the developer force, to dynamically (almost ;-) ) populate pages with the number of quotes. However, again the drawback is that if the description is too long, the page breaks will not be consistent and the quote will look ugly.
The final solution I came up with is an extension to an already existing solution on developer force. Though this is not a neat solution, but I guess we have to live with these kind of solutions until Salesforce comes up with a better out of the box quote generation functionality.
As you would expect, there are 2 components -
1. Visual Force Page to generate the pdf.
2. An extension to return the quotes.
Visual Force Page
Extension
public with sharing SalesQuoteExample{
public List<QuoteLineItem[]> pageBrokenQuoteLines {get; private set; }
// end new code
public Quote quote { get; private set;}
public QuoteLineItem[] quoteLineItems { get; private set; }
public Opportunity opp { get; private set; }
public Boolean hasContact { get { return (opp.opportunityContactRoles.size() == 1);} }
public Contact contact { get; private set; }
private ApexPages.StandardController controller;
// constructor, loads the quote and any opportunity lines
void queryQuoteLines(id id) {
quote = [ Select s.Contact.Name, Contact.Account.Name, s.Contact.MailingStreet, s.Contact.MailingState,
s.Contact.MailingPostalCode, s.Contact.MailingCountry,
s.Contact.MailingCity , s.Contact.Phone, S.Email,
(Select Quantity, PricebookEntry.Product2.Name, ListPrice, Adjusted_Price__c,
Product_Description__c, TotalPrice, LineNumber From QuoteLineItems
order by PricebookEntry.Product2.Name ),
s.Opportunity.HasOpportunityLineItem, s.Opportunity.Name, s.Name, s.QuoteNumber,
s.Opportunity.Id, s.OpportunityId
From Quote s
where s.id = :quoteid limit 1];
quoteLineItems = quote.QuoteLineItems;
prepareQuoteLinesForPrinting();
}
id quoteid;
/*public SalesQuotes() {
quoteid = ApexPages.CurrentPage().getParameters().get('id');
init();
}*/
public SalesQuotes(ApexPages.StandardController c) {
controller = c;
quoteid = c.getRecord().id;
init();
}
// load up quote lines, opportunity lines, opportunity details and contact info
void init() {
queryQuoteLines(quoteid);
}
/* The action method that will generate a PDF document from the QuotePDF page and attach it to
the quote provided by the standard controller. Called by the action binding for the attachQuote
page, this will do the work and take the user back to the quote detail page. */
public PageReference attachQuote() {
/* Get the page definition */
PageReference pdfPage = new PageReference( '/apex/quotePDFAdvanced' );
/* set the quote id on the page definition */
pdfPage.getParameters().put('id',quote.id);
/* generate the pdf blob */
Blob pdfBlob = pdfPage.getContent();
/* create the attachment against the quote */
Attachment a = new Attachment(parentId = quote.id, name=quote.name + '.pdf', body = pdfBlob);
/* insert the attachment */
insert a;
/* send the user back to the quote detail page */
return controller.view();
}
PageReference opportunityPR() { return new pagereference('/'+quote.OpportunityId); }
PageReference quotePR() { return new pagereference('/'+quote.id); }
public PageReference reset() {
queryQuoteLines(quote.id);
return null;
}
//splits the quote lines into an approximate number of rows that can be
//displayed per page
private void prepareQuoteLinesForPrinting()
{
pageBrokenQuoteLines = new List<QuoteLineItem[]>();
Integer linesAvailable = 60;
QuoteLineItem[] pageOfQuotes = new QuoteLineItem[]{};
Integer counter = 0;
boolean firstBreakFound = false;
//Additional variables
String description;
String productName;
Integer descLines=0;
Integer lines;
for(QuoteLineItem q : quoteLineItems)
{
System.debug('Quote Line Item is ****'+q.LineNumber);
description = q.Product_Description__c;
if(description!=null)
{
descLines = description.length()/40;
System.debug('Lines Available::::'+linesAvailable);
System.debug('Description Length==='+description.length());
System.debug('descLines+++'+descLines);
if(linesAvailable > descLines)
{
System.debug('Lines Available');
linesAvailable = linesAvailable - descLines;
pageOfQuotes.add(q);
descLines = 0;
}
else
{
System.debug('NO Lines Available::::'+linesAvailable);
pageBrokenQuoteLines.add(pageOfQuotes);
pageOfQuotes = new QuoteLineItem[]{};
descLines = 0;
}
}
}
//if we have finished looping and have some quotes left lets assign them
if(!pageOfQuotes.isEmpty())
{
pageBrokenQuoteLines.add(pageOfQuotes);
}
}
}
The method prepareQuoteLinesForPrinting is based on the following assumptions
Credits
But if you look at it closely, the page breaks are not consistent, if my product description is a little too long, the quote extends to multiple pages, without proper page breaks. So, I searched the internet for few solutions and found 1 good solution on the developer force, to dynamically (almost ;-) ) populate pages with the number of quotes. However, again the drawback is that if the description is too long, the page breaks will not be consistent and the quote will look ugly.
The final solution I came up with is an extension to an already existing solution on developer force. Though this is not a neat solution, but I guess we have to live with these kind of solutions until Salesforce comes up with a better out of the box quote generation functionality.
As you would expect, there are 2 components -
1. Visual Force Page to generate the pdf.
2. An extension to return the quotes.
Visual Force Page
<div style="page-break-after:always;"> </div> <apex:repeat value="{!pageBrokenQuoteLines}" var="aPageOfQuotes" id="theList"> <div style="page-break-after:always;">
<apex:dataTable value="{!aPageOfQuotes}" var="c" id="theTable">
<apex:column > <apex:facet name="header">Qty</apex:facet> <apex:outputText value="{!c.Quantity}"/> </apex:column> <apex:column > <apex:facet name="header" >Part Number</apex:facet> <apex:outputText value="{!c.PricebookEntry.Product2.Name}"/> </apex:column> <apex:column ></apex:dataTable>
Extension
public with sharing SalesQuoteExample{
public List<QuoteLineItem[]> pageBrokenQuoteLines {get; private set; }
// end new code
public Quote quote { get; private set;}
public QuoteLineItem[] quoteLineItems { get; private set; }
public Opportunity opp { get; private set; }
public Boolean hasContact { get { return (opp.opportunityContactRoles.size() == 1);} }
public Contact contact { get; private set; }
private ApexPages.StandardController controller;
// constructor, loads the quote and any opportunity lines
void queryQuoteLines(id id) {
quote = [ Select s.Contact.Name, Contact.Account.Name, s.Contact.MailingStreet, s.Contact.MailingState,
s.Contact.MailingPostalCode, s.Contact.MailingCountry,
s.Contact.MailingCity , s.Contact.Phone, S.Email,
(Select Quantity, PricebookEntry.Product2.Name, ListPrice, Adjusted_Price__c,
Product_Description__c, TotalPrice, LineNumber From QuoteLineItems
order by PricebookEntry.Product2.Name ),
s.Opportunity.HasOpportunityLineItem, s.Opportunity.Name, s.Name, s.QuoteNumber,
s.Opportunity.Id, s.OpportunityId
From Quote s
where s.id = :quoteid limit 1];
quoteLineItems = quote.QuoteLineItems;
prepareQuoteLinesForPrinting();
}
id quoteid;
/*public SalesQuotes() {
quoteid = ApexPages.CurrentPage().getParameters().get('id');
init();
}*/
public SalesQuotes(ApexPages.StandardController c) {
controller = c;
quoteid = c.getRecord().id;
init();
}
// load up quote lines, opportunity lines, opportunity details and contact info
void init() {
queryQuoteLines(quoteid);
}
/* The action method that will generate a PDF document from the QuotePDF page and attach it to
the quote provided by the standard controller. Called by the action binding for the attachQuote
page, this will do the work and take the user back to the quote detail page. */
public PageReference attachQuote() {
/* Get the page definition */
PageReference pdfPage = new PageReference( '/apex/quotePDFAdvanced' );
/* set the quote id on the page definition */
pdfPage.getParameters().put('id',quote.id);
/* generate the pdf blob */
Blob pdfBlob = pdfPage.getContent();
/* create the attachment against the quote */
Attachment a = new Attachment(parentId = quote.id, name=quote.name + '.pdf', body = pdfBlob);
/* insert the attachment */
insert a;
/* send the user back to the quote detail page */
return controller.view();
}
PageReference opportunityPR() { return new pagereference('/'+quote.OpportunityId); }
PageReference quotePR() { return new pagereference('/'+quote.id); }
public PageReference reset() {
queryQuoteLines(quote.id);
return null;
}
//splits the quote lines into an approximate number of rows that can be
//displayed per page
private void prepareQuoteLinesForPrinting()
{
pageBrokenQuoteLines = new List<QuoteLineItem[]>();
Integer linesAvailable = 60;
QuoteLineItem[] pageOfQuotes = new QuoteLineItem[]{};
Integer counter = 0;
boolean firstBreakFound = false;
//Additional variables
String description;
String productName;
Integer descLines=0;
Integer lines;
for(QuoteLineItem q : quoteLineItems)
{
System.debug('Quote Line Item is ****'+q.LineNumber);
description = q.Product_Description__c;
if(description!=null)
{
descLines = description.length()/40;
System.debug('Lines Available::::'+linesAvailable);
System.debug('Description Length==='+description.length());
System.debug('descLines+++'+descLines);
if(linesAvailable > descLines)
{
System.debug('Lines Available');
linesAvailable = linesAvailable - descLines;
pageOfQuotes.add(q);
descLines = 0;
}
else
{
System.debug('NO Lines Available::::'+linesAvailable);
pageBrokenQuoteLines.add(pageOfQuotes);
pageOfQuotes = new QuoteLineItem[]{};
descLines = 0;
}
}
}
//if we have finished looping and have some quotes left lets assign them
if(!pageOfQuotes.isEmpty())
{
pageBrokenQuoteLines.add(pageOfQuotes);
}
}
}
The method prepareQuoteLinesForPrinting is based on the following assumptions
- The description will have approximately 40 characters per line.
- A page can accommodate 50 lines of quotes. Can be changed by specifying a new value in the variable.
- For each quote line item, calculate the description length.
- Divide this length by 40, to get an approximate number of lines this quote line item will take.
- Subtract the value from above from the available lines. Available lines indicate the space left in the page to display quote line item.
- If the available lines is greater than the description lines(indicating space is available), add this quote on the current page.
- Else, add the quote to new page, reset the available lines to 50 (this is configurable).
Credits
Thanks for sharing fabulous information.It' s my pleasure to read it.I have also bookmarked you for checking out new posts.
ReplyDeleteDigital Marketing Training in Hyderabad
Muğla
ReplyDeleteBitlis
Karaman
JEL5
Denizli
ReplyDeleteAnkara
Antep
Bursa
Eskişehir
QR8K
sakarya
ReplyDeleteyalova
elazığ
van
kilis
EURR0
goruntulu show
ReplyDeleteücretli
5DXSU
Maraş Lojistik
ReplyDeleteHatay Lojistik
Tokat Lojistik
Elazığ Lojistik
Aksaray Lojistik
ZBSL
Maraş Lojistik
ReplyDeleteHatay Lojistik
Tokat Lojistik
Elazığ Lojistik
Aksaray Lojistik
RİİRDK
FD690
ReplyDeleteSiirt Lojistik
Kırşehir Evden Eve Nakliyat
Antep Parça Eşya Taşıma
Hatay Evden Eve Nakliyat
Gümüşhane Parça Eşya Taşıma
6136C
ReplyDeleteAdana Evden Eve Nakliyat
Çorum Evden Eve Nakliyat
Trabzon Evden Eve Nakliyat
Ardahan Evden Eve Nakliyat
Bayburt Evden Eve Nakliyat
856F2
ReplyDeleteBinance Güvenilir mi
Silivri Cam Balkon
Malatya Evden Eve Nakliyat
Nevşehir Evden Eve Nakliyat
Çerkezköy Fayans Ustası
158F1
ReplyDeleteMaraş Şehirler Arası Nakliyat
Adıyaman Şehirler Arası Nakliyat
Adana Şehir İçi Nakliyat
Gölbaşı Fayans Ustası
Düzce Parça Eşya Taşıma
Balıkesir Evden Eve Nakliyat
Hakkari Lojistik
Yobit Güvenilir mi
Ordu Şehir İçi Nakliyat
4D066
ReplyDeleteBitlis Parça Eşya Taşıma
Kars Evden Eve Nakliyat
Çanakkale Lojistik
Ankara Evden Eve Nakliyat
Burdur Evden Eve Nakliyat
Burdur Şehirler Arası Nakliyat
Sivas Parça Eşya Taşıma
Tekirdağ Cam Balkon
Trabzon Şehirler Arası Nakliyat
F0449
ReplyDeleteMuğla Lojistik
Sinop Şehirler Arası Nakliyat
Fuckelon Coin Hangi Borsada
Isparta Lojistik
Ünye Mutfak Dolabı
Antalya Rent A Car
Eskişehir Parça Eşya Taşıma
Düzce Lojistik
Aydın Şehir İçi Nakliyat
6E997
ReplyDeleteŞırnak Görüntülü Sohbet Siteleri Ücretsiz
bedava görüntülü sohbet
kütahya rastgele görüntülü sohbet ücretsiz
Çankırı Chat Sohbet
bayburt görüntülü sohbet
telefonda kızlarla sohbet
karaman yabancı görüntülü sohbet uygulamaları
mobil sohbet bedava
bedava sohbet uygulamaları
F6A6D
ReplyDeletemobil sohbet chat
Batman Canlı Sohbet Bedava
Urfa Yabancı Canlı Sohbet
ardahan görüntülü sohbet yabancı
bayburt görüntülü sohbet siteleri ücretsiz
batman mobil sohbet
Tokat Kadınlarla Rastgele Sohbet
seslı sohbet sıtelerı
bedava sohbet siteleri
118BD
ReplyDeleteen iyi ücretsiz sohbet siteleri
çanakkale en iyi ücretsiz görüntülü sohbet siteleri
artvin goruntulu sohbet
Elazığ Ücretsiz Görüntülü Sohbet Uygulamaları
hatay rastgele sohbet
çankırı yabancı canlı sohbet
kars canlı sohbet bedava
niğde random görüntülü sohbet
Elazığ Yabancı Sohbet
0F403
ReplyDeleteTumblr Beğeni Satın Al
Kripto Para Nasıl Oynanır
Periscope Beğeni Satın Al
Spotify Takipçi Hilesi
Kripto Para Nasıl Üretilir
Coin Madenciliği Nedir
Twitch Takipçi Satın Al
Coin Üretme
Bitcoin Üretme
75267
ReplyDeleteGörüntülü Sohbet
Coin Madenciliği Nasıl Yapılır
Hamster Coin Hangi Borsada
Bitcoin Kazanma
Yeni Çıkan Coin Nasıl Alınır
Nonolive Takipçi Hilesi
Area Coin Hangi Borsada
NWC Coin Hangi Borsada
Kaspa Coin Hangi Borsada
hbnfgjnhgjhkj
ReplyDeleteشركة تسليك مجاري بالاحساء
RFHTYJY
ReplyDeleteشركة مكافحة حشرات
1E2511CFF3
ReplyDeleteshow
شركة تنظيف سجاد بالجبيل 0GxN1ydgFj
ReplyDeleteشركة صيانة افران d78vHbgnOu
ReplyDeleteشركة تنظيف كنب بالاحساء kf80T30cFj
ReplyDeleteشركة تنظيف بالاحساء Rs6fQcpq5j
ReplyDeleteشركة عزل اسطح بالرياض qel7SgbOrw
ReplyDelete972165EFAD
ReplyDeletecialis
steroid satın al
skype show
steroid satın al
görüntülü show
www.ijuntaxmedikal.store