SugarCRM PDF Manager for Quotes

by Daniel Ciobanu on May 20, 2013

Overview

SugarCRM allows us to define PDF templates to print/save specific module data as PDF.  This goal is achieved using a PDF library called TCPDF, some SugarCRM classes located in /include/Sugarpdf folder, and specific module customization.

Here, we’ll look at how the process of generating PDF is performed, and we’ll show some minor tricks & tips that will help you to quickly modify the PDF templates table layouts or add support for alternate line background colors.

PDF Generation Process

In Short, a PDF template is applied to a specific module record, and the PDF file is generated according to the following steps:

  1. The PDF template is read from database
  2. A temporary file  is written to the disk after some processing
  3. The temporary file is loaded into the Smarty template engine instance and processed
  4. The  HTML output from Smarty template is written as PDF using TCPDF library
  5. The PDF content is sent to the browser

Now, I’ll show in more detail how this works for Quote PDF generation request.  When you try to download a specific quote as PDF, a request like below will be issued:

index.php?module=Quotes&record=e0710171-84af-0338-4538-5126b5d2351d &action=sugarpdf&sugarpdf=pdfmanager&pdf_template_id=4710aba3-291f-2775-4ca8-5112e8a3e111

The record parameter represents the specific quote id from the database, and the pdf_template_id represents the id of the template used to render the quote.

The sugarpdf action is mapped to the sugarpdf view which is defined by the Quotes module in views/view.sugarpdf.php file using QuotesViewSugarpdf class. The view display method is responsible for calling the SugarpdfPdfManager->process method, which performs steps 1,2,3 and 4 as described above, and SugarpdfPdfManager->Output method which performs step 5. The following figure shows the sequence diagram for this flow:

Figure 1

The SugarpdfPdfmanager->preDisplay method performs steps 1 (PdfManager->retrieve)  and 2 (SugarpdfPdfmanager-> buildTemplateFile). Then, the display method inherited from SugarpdfSmarty is called to process the smarty template and creates the HTML output as in step 3. The HTML result is written as PDF using writeHTML method from TCPDF. At the end, the Output method will send the file to the browser(Step 5).

Here is the class hierarchy responsible for this process:

Figure 2

Note 1

According to the code from buildTemplateFile, it seems that there is a specific handling for Quotes module templates:

if ($pdfTemplate->base_module == 'Quotes') {

                $pdfTemplate->body_html = str_replace(
                    '$fields.product_bundles',
                    '$bundle',
                    $pdfTemplate->body_html
                );

                $pdfTemplate->body_html = str_replace(
                    '$fields.products',
                    '$product',
                    $pdfTemplate->body_html
                );
                
                $pdfTemplate->body_html = str_replace(
                    '<!--START_BUNDLE_LOOP-->',
                    '{foreach from=$product_bundles item="bundle"}',
                    $pdfTemplate->body_html
                );
                
                $pdfTemplate->body_html = str_replace(
                    '<!--START_PRODUCT_LOOP-->',
                    '{foreach from=$bundle.products item="product"}',
                    $pdfTemplate->body_html
                );
                
                $pdfTemplate->body_html = str_replace(
                    array("<!--END_PRODUCT_LOOP-->", "<!--END_BUNDLE_LOOP-->"),
                    '{/foreach}',
                    $pdfTemplate->body_html
                );
                
            }

So, START_PRODUCT_LOOKUP and   START_BUNDLE_LOOP are actually for statements. This note will help us later to implement alternate line colors.

Dealing with cell widths in PDF Templates

While working with PDF templates in Sugar, you’ll notice that a table like the one below:

<table width="100%">
<tr>
<td width="10%">Product No</td>
<td width="60%">Product Name</td>
<td width="30%">Price</td>
</tr>
</table>

will not look as expected in your generated PDF output. The explanation can be found in include/Sugarpdf/Sugarpdf.pdf  file,  looking at writeHTMLTable function comments :

//  TODO ISSUE - width in % for the td have to be multiply by the number of column.
 //  ex: for a width of 20% in a table of 6 columns the width will have to be 120% (20*6).

So, if you want your cells to have the expected width, you’ll need to multiply the actual column with by the number of columns, 3 in our case:

<table width="100%">
<tr>
<td width="30%">Product No</td>
<td width="180%">Product Name</td>
<td width="90%">Price</td>
</tr>
</table>

A simple method to display lines with alternate background colors

The default Quotes PDF template displays the bundle product list using a markup like below:

<!--START_PRODUCT_LOOP-->
<tr>
<td width="40%">{$product.quantity}</td>
<td width="280%">{$product.name}{if isset($product.list_price)}<br /> {$product.description}{/if}</td>
<td width="40%">{$product.discount_price}</td>
<td width="40%">{$product.ext_price}</td>
</tr>
<!--END_PRODUCT_LOOP-->

As we have seen in Note 1 above, the denotes actually a for statement. Also, we know that the template will be processed using Smarty engine. That means we can use Smarty functions and variables to accomplish any task we want.  In order to make the difference between the odd and even rows we can use a Smarty cycle statement as bellow:

<!--START_PRODUCT_LOOP-->
<!--{cycle values="color1, color2" assign="color"} -->
<!--{if $color == "color1" }-->
<tr bgcolor="white">
<td width="40%">{$product.quantity}</td>
<td width="280%">{$product.name}{if isset($product.list_price)}<br /> {$product.description}{/if}</td>
<td width="40%">{$product.discount_price}</td>
<td width="40%">{$product.ext_price}</td>
</tr>
<!-- {else} --> 
<tr bgcolor="grey">
<td width="40%">{$product.quantity}</td>
<td width="280%">{$product.name}{if isset($product.list_price)}<br /> {$product.description}{/if}</td>
<td width="40%">{$product.discount_price}</td>
<td width="40%">{$product.ext_price}</td>
</tr>
<!--{/if}-->
<!--END_PRODUCT_LOOP-->

We defined a variable called color using smarty assign and cycle function. This variable will cycle between two values color1 and color2. So, for odd iterations will use color1 as value and for even iterations will use color2.  Depending on that value we render the same product row using a different background color. In this case we used white and grey as background colors, but you can replace them with any valid html color code.

I’d like to emphasize that the added code is enclosed in HTML comments in order to avoid HTML parsing issues.  

 

Links

http://www.smarty.net

Find similar articles in these categories:

PRODUCT: SugarCRM

AUDIENCE: Developers

Daniel Ciobanu
Director of Development at UpCurve Cloud
More From This Author »