SugarCRM’s Quote PDFs customizations always seem so complicated, but they’re one of the most common requests we get. Today I had to tackle an even more specific facet of the system: how the PDF Format select input is generated. Here’s a quick break-down of how it works in a default system:
- The Layout handler (modules/Quotes/Layouts.php) defines the stock $layouts array (Standard and Invoice) with a key to name the file and a path to the PDF layout. This path is never used; it doesn’t resolve and I think it’s probably just a fossil from older versions of the system.
- At the same time, the Application Language files (include/language/en_us.lang.php) hold an array called “layouts_dom” which holds the translated names of the PDF templates (this is where “Standard” becomes “Quote” and “Invoice” is just “Invoice”). Note that a comment in the original Layouts.php references that this language is defined within the Quotes module, but it’s not.
- Quote’s Detail View (modules/Quotes/views/view.detail.php) calls the function get_layouts() from Layouts.php, which mashes the $layouts array with the array in $app_list_strings[‘layouts_dom’]. This array is then converted to a set of HTML option elements and passed to Smarty as $LAYOUTS_OPTIONS.
- The next code block in the same file then re-defines the view metadata to include a “links” section (interestingly, I think that this is the only instance of the metadata “links” block in the system). Basically it formats it for the top-right of the form and maintains it’s association to the parent form, which was began by the rendering of the Email PDF and Print PDF buttons. In this block it puts the SELECT element with the $LAYOUT_OPTIONS options.
Now that we understand this, how would we go about changing the order of these options, or even add a new one? Fortunately Layouts.php has built-in checks for custom files at either custom/modules/Quotes/Layouts.php or custom/modules/Quote/Layouts.override.php. We’ll use these to add to or even redefine the $layouts array.
<?php $layouts = array( 'Invoice'=>'modules/Quotes/layouts/Invoice.php', 'Standard'=>'modules/Quotes/layouts/Standard.php', 'CreditCardInvoice' => '/this/path/is/garbage', );
We’ll then need to adjust the language to add any values into layouts_dom. I think the easier path in this is to create or modify custom/include/language/en_us.lang.php and redefine the array there.
$GLOBALS['app_list_strings']['layouts_dom'] = array( 'Standard' => 'Quote', 'Invoice' => 'Invoice', 'CreditCardInvoice' => 'Credit Card Invoice', );
Once you have these defined they’ll show up on the UI and be accessible to users. You still need to actually create the templates. A good starting point is usually to just copy the existing Standard template and modify it, or simply extend it and override the display method.
For the file itself: SugarCRM will use the array key from layouts_dom, run it through strtolower, and check /custom/modules/Quotes/sugarpdf/ and /modules/Quotes/sugarpdf/ with priority going toward the custom directory. The filename will be prefixed with ‘sugarpdf.’ so if you’re looking for Credit Card Invoice from the above example, it would be found as /custom/modules/Quotes/sugarpdf/sugarpdf.creditcardinvoice.php and the class to define it would be QuotesSugarpdfCreditCardInvoice.