It's Easy to Play with Sugar: Building Vertical Customizations | SugarCon 2011


Published on

We all need, as programmers, to customize SugarCRM in different ways and at different levels, so why don't we share our knowledge?

In our session, based on a couple of Business Cases, we'll show you what we did and, most important, how we did it, showing you the potential of SugarCRM from a programmer's perspective.

Presented by Fabio Grande, Senior Developer/Analyst/System Engineer, Poker SpA, at SugarCon 2011

Published in: Business
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide
  • Poker SpA is an Italian softwarehouse founded in 1980 based near Turin (North-West of Italy). After many years spent developing our ERP solution, we decided to extend our knowledge to cover Web development area, especially CRM. We evaluated many softwares, finally choosing SugarCRM as the only product to bet on. A new division, named Next Generation, was built to follow web and SugarCRM's development. We are SugarCRM's (Bronze) Partners since 2009.
  • From a Developer's perspective, we choose SugarCRM especially (but not only) for the following (good) reasons: Is OPEN, so we (as developers) can check the source code, discovering the way SugarCRM do things, implementing our procedures accordingly. Is FLEXIBLE, so we can extend it, building our procedures over a stable framework in an Upgrade-Safe way. Is CUSTOMIZABLE, so we don't have to modify the core to implement new functionalities or change the standard behaviour.
  • We think that SugarCRM's Customization can be done, as with any other software, in two ways: “Vertical” and “Horizontal”. While “Vertical” Customization is what we need to build Client's projects, with “Horizontal” Customization we build standard modules to satisfy common requirements. No matter what we do. What really matter is the way we do what we do: ALWAYS following the UPGRADE-SAFE development rules.
  • Our first Business Case is about a Car Repairer's Holding, with (currently) 10 active shops in North Italy. Working with insurance companies, private customers and fleets, they needed to load jobs in two ways: manually and automatically (from zipped files), directly from a shop or, most commonly, through the dedicated Call Center. A job is actually just an estimate, but users must calculate exactly the amount of time and spare parts they need to repair the car: if accepted the estimate become the task-list used by workers. Finally SugarCRM produce an invoice (PDF format) sent to our ERP for administration purposes. SugarCRM can also produce statistics in Excel format (PHPExcel library).
  • This is the list of the main POIs related to this Business Case, from a Developer perspective. We built up others interesting features, such as a custom agenda for managing appointments, but we choose just a bunch of them (consider that the project is a big one, and it took quite a year to be completed – and they're still continuosly asking us new implementations). Let's start discovering them.
  • SugarCRM is deeply customizable. But we all must understand that there are at least two levels of customizations : let's call them “light” and “heavy”. With “light” customization you can add fields, play with relationships and build “standard” new modules (Studio/Module Builder). I prefer the “heavy” customization, where the dev needs to really understand what happens in the background of Sugar before he starts coding (without changing the core – that's challenging). One of the requirements was to check the validity of VAT Code and CODICE FISCALE inserted in our custom modules. For those codes, the first check to do is the length check: 11 or 16 characters. A second check is done by a particular algorithm that calculate the last character (check digit). For VAT Codes there's a third possibile check: the actual existence based on a (free) European WebService; this is only valid for EU countries, and we're still testing it (it wasn't a requirement, so we're doing it just for fun... - don't tell it to my boss !). Anyway, we built a couple of custom fields dedicated to those kind of data, perfectly integrated with the standard validation of SugarCRM. Actually we built other kinds of Custom Fields, such as a ReadOnly field, with facilities for defining “class” tag and more. The target of those fields was to have something simple to customize.
  • In new releases of Sugar fields became more powerful, thanks to SugarLogic. But, sometimes, it's not enough... When You need to use deeply customized fields, then You need to build them by Yourself. A SugarField is made of : 1) Code for field definition (for use in Studio/Module Builder). 2) Code for Rendering (Edit/Detail/Search/List).
  • Google Maps helped a lot Call Center's girls, giving them an idea of places and distances, without knowing the territory. As a customer I would contact the Call Center, reporting the problem (usually a car accident) and my address (or the accident address). With the help of Google Maps the operator can see where I am (the standard pointer) and where the shops are located (the red flags). He also knows which is the nearest shop, the actual distance and the medium time to reach it. Data that the Operator knows for every shop (in order of distance, from the nearest to the farest).
  • SMS sending quickly become one of the most important activity: SugarCRM teach us that keepin in touch with customers is crucial in every business, and our Client knew it ! We can manually send SMS messages starting from the Job's detail view, getting the mobile number from the current record. We've implemented a templating system, so the User can choose a message model to send, automatically filled-in with values taken from current record (eg : plate number and Customer's name are the same You can see beneath the YUI panel). There's more : with the same engine, the application send automated messages to remind next day's appointment.
  • This is our first release for an SMS sending engine. We'll use the same logic (separated threads) also in the ngSms module we'll discuss later. Sending directly a message through WebServices is not a good idea: communication could fail, and devs are in trouble when they needs to recover the error. So we changed thread: SugarCRM write its own table, that's all. Then, every minute, a scheduled Job send new messages and check status of pending messages. SMS Gateways don't send messages immediately. The can be more or less fast, but not immediate.With a WS call, You can only add Your SMS to the Gateway's internal queue.
  • Insurance Companies use to send jobs via zipped files containing both images and documents (usually in JPG/PDF format); the job itself is described by an XML/INI file (the actual format is company-dependant) contained in the same zip file. Sugar's side, the automatic procedure load the zip file, unzip it and then create the job accordingly to the XML/INI file contained, attaching (and categorizing) all the images and documents just extracted.
  • We were very lucky ! When we started coding the Import Procedures, FireFow went out with a new feature: native multiple files upload ! Here, we can upload multiple files at once, automatically archiving them under a specific category. Then we AJAXized the Document management.
  • Even it's part of HTML5 specifications, at the moment multiple keyword is implemented only in Chrome and FireFox!!!!! With onchange event You can check files Users are trying to upload BEFORE they start the action. To upload files, You need to implement POST calls via XMLHttpRequest. Pay attention to PHP.INI pitfalls !
  • When users starts evaluating damages, they need to get spare parts, with related prices and standard working times. This is exactly what LRW ( by Quattroruote Professional) is made for: a database of (almost) all the spare parts of (almost) all the cars produced since 1980 (?). For every (visually) selected part, SugarCRM gets back (via SOAP Web Services) a list of prices and standard times (detailed for mounting/dismounting, total painting, partial painting, substitution). That done, SugarCRM can accurately recalculate the job,
  • New SugarCRM's Web Services structure, greatly help developers, because they find an easy way to implement new remote procedures. With just 4 files one can implement its own custom operations, in addition to the standard ones, working both with REST a SOAP technologies. Refer to Sugar WebServices Documentation, to understand changes between releases. Consider that signatures never change, this is a basic rule of Web Services (not only in Sugar World).
  • The actual (production) release of this project runs under SugarCRM 5.2, when the included YUI was rel. 0.26. Having not standard panels, we built them by ourselves... Well they aren't beautiful (we not designers !), but they are functional (that's guaranteed !). Next update will benefit of YUI 2.6, especially of its new panels, with a little development effort.
  • YUI Panels are a great improvement for User Experience. They are part of Web 2.0 philosophy, making users feel like they are working with Client/Server procedures. YUI Panels and AJAX are tightly correlated. This sample shows You how to implement a static panel: in fact You build the contained DIV in the HTML. At the same time, panel's rendering is done during page intialization. Static panels, or partially static panels, have good performances, because they are embedded in Smarty templates, meaning they come from a cache, where they lives partially rendered. What if You add 30 new buttons launching 30 different panels in the same page ?
  • This is the solution: dynamic panels. Throught Javascript, Menu calls the server to get the panel template. The the Client builds and render the panel adding, for instance, “ok” and “Cancel” Buttons. While “Cancel” button simply hide the panel, the “Ok” button launch (via Ajax) a server action, and get the answer asynchronously. This is just an example... We build a standard “wait panel” ajax-style.
  • Another Business Case, this time for a small (but well known) pharmaceutical company. The problem : automate salesforce. The challenge: be fast, easy and portable. The solution: SugarCRM (and some customization). As usual, for Customers coming from our ERP, the connection with Quasar-X is included. Also reports (statistics and order forms) are produced in PDF format via Jasper Reports Library.
  • Here the solution has been stacked on heavy AJAX customization, simplified by the small (and static) number of selled items. Salesman have just to fill-in quantities and (optionally) discounts (the standard ones came automatically from the ERP), and the order is done ! The sales flow end with the sending of the order to ERP system (Quasar-X): once verified by a supervisor, it's ready for delivery (and invoicement).
  • More Tips and Samples.
  • Every module have its own menu, partially controlled by ACL (Access Control List) and partially by contexts (e.g. the current view). Every self-developed module has its own Menu.php in modules/<modulename> directory. The standard Menu.php it's joined with the one contained in custom/modules/<modulename> directory, if exists. Finally, it's joined with custom/application/...., if present. Devs can add menus manually (copying files directly) or (better way) throught manifest, via the “menu” tag.
  • Menus are always (on every page refresh) evaluated, so people can do a lot of checks while they're created. Never change core Menus for standard modules, it's a bad habit. Whatever You need with menus can be done, with little effort, in the same old “Upgrade-Safe” way : using custom menus.... Don't You believe it ? Let's check next slide...
  • This is the Menu Item we added on our Jobs module to recalculate them. First we get current record id, throught $_REQUEST, and retrieve it. Then, if we are in DetailView, we check if the Job can actually be recalculated (maybe it's an incomplete job, with missing data – we have very few mandatory fields at GUI level, because users may need to jump between jobs at any time). If this is the case, we build a link to recall the action named “MyAction” that we will find in our controller.php as “function action_MyAction”. Otherwise we will open a popup telling that “Action is not Enabled”. Of course we could hide the button, it's a matter of design (and of Customer's willings).
  • The function loadBean is a big facility that let developers to instantiate Sugar's modules (the ones that inherith from SugarBean). This function do all for us: check if module exists, require (once) files needed and return a new instance of it. SugarBean offers us a lot of options. Here what we used a lot: disable_row_level_security (very dangerous), let us to retrieve records even if team security wouldn't let us see them. relDepth , when > 1, avoid loading names for relate objects.
  • We can do a lot of stuff hacking view.detail.php file, both in modules/<moduleName>/views directory (if we are developing our own module) and in custom/modules/<moduleName>/views directory (if we are hacking a core module that supports MVC) . Pay attention to the name of the class. Camel Case is very important. The order is : 1) preDisplay 2) displayErrors ($this->errors) 3) display 4) HOOK after_ui_frame 5) _displaySubPanels (now is protected and has an “_”) 6) displayFooter 7) HOOK after_ui_footer
  • This is how we hacked standard rendering. Note the highlighted reference to the standard Smarty Template. All the surrounding code is rendered before and after standard visualization of fields. You can also decide to change the way Your module shows up. It's not a good practice (standard templates translate viewdefs), but it's not forbidden !
  • Even ListView is customizable. Of course You can do customizations throught viewdefs, but this gives You better control on visualization. For instance, overriding listViewPrepare , You can define default sort order. Redefining display You can inject html code (with tags like script, etc...). CHECK RENDERING OF SINGLE RECORD
  • Some quick tip to help You save time. These are common errors we did (and we spent debugging time to get rid of them). Lowercase in field names and indexes names i snecessary, otherwise installer (and repair database) don't understand that we are dealing with the same field.... Field names must have a maximum length of 30 chars, because of Oracle's limit. This is necessary if You want to build standard modules cross database (like SugarCRM). When creating custom fields from manifest, don't forget the “_c” suffix in the field name, otherwise reinstalling the module will fail with a duplicate key error on fields_meta_data. Don't forget to mentione the error in the slide : not “vname” but “label”, since this is not a vardefs, but a custom_field tag in manifest.
  • This is the way we work on SugarCRM. Wiki – To keep hints and instructions, non only Sugar-related, but web development wide. SVN – For Sugar's packages, but also for sql scripts, system, scripts and whatever is customer-related. Test on Linux – To avoid naming cases issues. Virtual Machines – To easily build sandboxes.
  • Part of our work involve R&D. Apart the constant alignement with SugarCRM's new implemenbtation, that we keep on discovering everyday, we build standard modules for our “horizontal” market. We build our modules thinking like End Users, trying to keep things simple and friendly. At the moment we are working on those modules.
  • Heavily based on AJAX technology and on SugarCRM customization, you can find our ngReports module. This is a bridge between SugarCRM and JasperServer Reporting engine. We all know Zucker Reports. We're trying to build something better and simpler (in terms of configuration): all You need is to put reports (built with iRepports) on a Jasper Server. Then, throught a simple config page, the administrator can decide where to put links to launch them; a launch panel (self built) then appear, and the user can get its report with a single mouse click. The module is currently on test, but we are already thinking about new features, such as displaying its flash output on dashlets, archiving produced documents and sending them by eMail.
  • Even if SugarForge is plenty of modules for sending SMS, we decided to build one from scratch. The reason for that ? Because no one fully satisfied our requirements ! The experience we made wirth previous projects leads us to this decision: unfortunately when we built our first SMS Messaging system we weren't skilled enough to think about a standard module. But now, with rel 6.1, we are ready to do it ! The most important feature of our module will be the sending through different providers, to always get the best rates (important for international customers, less for domestic ones).
  • The biggest problem reported by our (old) Customers running both SugarCRM and Quasar-X, is the sync between databases. We solved the first part of the problem (send changed data from Qx to SugarCRM) with a small module that, catching changed data from a programmable and JDBC-compliant database, can feed a SugarCRM Web Service, populating underlying modules. What about getting back data ? Well, since the ERP's database is not linear (like the SugarCRM's one), getting back data is an activity that MUST be heavily customized (and cannot be standardized). Anyway we're working on an XML+XSLT standard module to send data back to our Quasar-X, trying to keep it open enough to make it works with other ERP systems.
  • It's Easy to Play with Sugar: Building Vertical Customizations | SugarCon 2011

    1. 1. It's easy to play with Sugar Building Vertical Customizations
    2. 2. Who we are
    3. 3. Why SugarCRM ? From a Developer's perspective SugarCRM is OPEN FLEXIBLE CUSTOMIZABLE
    4. 4. How we see Customizations always UPGRADE-SAFE V E R T I C A L HORIZONTAL
    5. 5. Car Repairer's – A Business Case Invoices
    6. 6. P.O.I. <ul><li>Custom Fields
    7. 7. Maps
    8. 8. SMS
    9. 9. Data Acquisition
    10. 10. Import Images
    11. 11. Connection With LRW (Spare Parts) </li></ul>
    12. 12. Custom Fields VAT & Tax Codes integrated with standard validation ReadOnly field with customizing facilities
    13. 13. Digging into Code - Fields For Field Definition (for use with Studio and ModuleBuilder) To build a Custom Field, just add a leading “custom” to above paths modules/DynamicFields/templates/Fields/Template<fieldname>.php get_field_def get_db_type modules/DynamicFields/templates/Fields/Forms/<fieldname>.php modules/DynamicFields/templates/Fields/Forms/<fieldname>.tpl For Field rendering (for use in Sugar's Forms) include/SugarFields/Fields/<fieldname> SugarField<fieldname>.php getDetailViewSmarty getEditViewSmarty EditView.tpl DetailView.tpl Javascript file (included in view)
    14. 14. Maps Google Maps/YUI technologies to locate and select shops
    15. 15. SMS Manual and Automatic SMS sending through Internet Gateways, with contextual template-based message construction
    16. 16. Digging into Code - SMS 1 n 1 n NEVER IN THE SAME THREAD ! Sugar's SMS db Table HTTP SMS Gateway Jobs Cases
    17. 17. Data Acquisition Insurance Companies send zipped files containing a self-describing XML/INI file and documents/images job-related. Then, Jobs are created/updated automatically. 100% Error Free !
    18. 18. Importing Documents Importing Documents/Images made simple... … and we made simple also Docs Management !
    19. 19. Digging into Code <input type=&quot;file&quot; id=&quot;txtFile&quot; name=&quot;txtFile&quot; multiple=&quot;true&quot; onchange=&quot;handleFiles(this);&quot;/> PHP.ini pitfall: post_max_size = total amount (files + post data) upload_max_filesize = max size of single file function handleFiles(pThis) { for (var i=0; i < pThis.files.length; i++) { alert(“File : “ + pThis.files[i].name); alert(“Size : “ + pThis.files[i].size); } } Action executed when user choose file(s)
    20. 20. Connection with LRW SugarCRM – LRW Integration for getting Spare Parts with related Times and Prices.
    21. 21. Digging into Code – Web Services We use to put our stuffs here: custom/services/ngV0/ ...and You can access You custom SugarCRM's service at http://yourwebsite/custom/services/ngv0/rest.php both via SOAP and REST !!!!! Operations Declarations Operations Implementations Entry Point definition rest.php soap.php registry.php implementation.php
    22. 22. When YUI was (too) young... The current production release (Sugar 5.2) offer an old YUI... we built panels by ourselves !!!!! (not particularly nice, but functional....)
    23. 23. Digging into Code – YUI Panels/1 YAHOO.namespace(&quot;myNS&quot;); YAHOO.myNS.EditPanel = null; YAHOO.myNS.initPage = function() { var args = { modal: true, visible: false, fixedcenter: true, constraintoviewport: false, underlay: &quot;shadow&quot;, close: true, draggable: true, } ; YAHOO.myNS.EditPanel = new YAHOO.widget.Panel('divEdit', args); YAHOO.myNS.EditPanel.render(document.body); } <div style=&quot;display: none;&quot;> <div id=&quot;divEdit&quot;> <div class=&quot;hd&quot;>Title</div> <div class=&quot;bd&quot;>Body</div> <div class=&quot;ft&quot;>Footer</div> </div> </div> <script type='text/javascript'> YAHOO.util.Event.onDOMReady(YAHOO.myNS.initPage); </script> JavaScript + HTML This Panel is rendered (not showed) during Page Init. They can be created on the fly...
    24. 24. Digging into Code – YUI Panels/2 Client Side Server Side User press Menu Button Javascript Show Panel Response to User (redirect? error? alert?) Build Template Do Server Action
    25. 25. Pharma – Another Business Case
    26. 26. P.O.I. Simplified Orders Loading. Put screenshot here Fast & Easy
    27. 27. More digging into Code
    28. 28. Digging into Code – Menus / 1 modules/<module>/Menu.php custom/modules/<module>/Menu.php custom/application/Ext/Menus/menu.ext.php Module Menu Manifest: $installdefs = array( ... 'menu' => array (0 => array ('from' => '<basepath>/common/Menu.php', 'to_module' => 'application', ), ), ... )
    29. 29. Digging into Code – Menus / 2 if(ACLController::checkAccess('cc_AssList', 'edit', true)) $module_menu[]=Array(&quot;index.php?module=cc_AssList&action=EditView&...&quot;, $mod_strings['LNK_NEW_RECORD'], &quot;Createcc_AssList&quot;, 'cc_AssList'); Menu.php contains the (re)definition of $module_menu array unset($module_menu[0]); // Remove the first link $module_menu = array(); // Remove all the menu, crazy but possible Standard Menu Item for record editing You can do many things in your (custom) Menu.php.....
    30. 30. Digging into Code – Menus / 3 $tHeaderId = $_REQUEST['record']; // Get current record $tHeader = loadBean(&quot;cc_Jobtestata&quot;); $tHeader->retrieve($tHeaderId); if ($_REQUEST['action'] == &quot;DetailView&quot;) { $_address = “index.php?module=cc_Jobtestata&action=MyAction&...”; $_label = $mod_strings['LBL_CALCULATE']; $_image = “Calculate”; $_module = “cc_Jobtestata”; $_error = “javascript:alert('Action Not Enabled');”; if ($tHeader->canBeCalculated()) { $module_menu[]=Array($_address, $_label, $_image, $_module); else $module_menu[]=Array($_error, $_label, $_image, $_module); } ...actually You can do almost everything !
    31. 31. Digging into Code – loadBeans $tFiliale = loadBean(&quot;cc_Filiali&quot;); $tFiliale-> disable_row_level_security = true; // option $tFiliale-> relDepth = 99; // option $tFiliale->retrieve($myId); require_once 'modules/cc_Filiali/cc_Filiali.php'; $tFiliale = new cc_Filiali(); $tFiliale->retrieve($myId); BAD HABIT
    32. 32. Digging into Code – Views/1 class <moduleName>ViewDetail extends ViewDetail { function displaySubPanels () { echo &quot;Whatever just before subpanels&quot;; parent::displaySubPanels(); echo &quot;Whatever after subpanels&quot;; } function display () { echo &quot;Whatever at beginning of page (but after menu)&quot;; echo '<script type=&quot;text/javascript&quot; src=&quot;custom/include/javascript/myJS.js&quot;></script>'; parent::display(); } function preDisplay () { $this->ss->assign(&quot;myBeanName&quot;, $this->bean->name); $this->dv = new DetailView2(); $this->dv->ss =& $this->ss; $this->dv->setup($this->module, $this->bean, 'modules/<modulename>/metadata/detailviewdefs.php', 'modules/<moduleName>/templates/DetailView.tpl'); } } Hacking (custom/)modules/<moduleName>/views/view.detail.php
    33. 33. Diggin into Code - Views/2 What about the Smarty template we included in previous preDisplay method ? {{include file=&quot;custom/include/BaseTemplates/ModuleShortcut.tpl&quot;}} <input type=&quot;hidden&quot; id=&quot;hidRowCount&quot; value=&quot;{$rowCount}&quot;></input> <input type=&quot;hidden&quot; id=&quot;hidIsInvalid&quot; value=&quot;0&quot;></input> {{include file=&quot;include/DetailView/DetailView.tpl&quot;}} <div id=&quot;invoiceWarningsDiv&quot;> Div containing something interesting.... </div> Now You can hack Your DetailView even from Smarty Templates !!!!!
    34. 34. Digging into Code – Views/3 class <moduleName>ViewList extends ViewList { function preDisplay() { parent::preDisplay(); $this->lv->delete = false; $this->lv->quickViewLinks = false; $this->lv->showMassupdateFields = false; } } Hacking (custom/)modules/<moduleName>/views/view.list.php Throught $this->lv object You can: <ul><li>Hide delete button (the one based on selected records)
    35. 35. Hide QuickView links (edit and detail buttons on the row)
    36. 36. Disable Mass Updating
    37. 37. And more.... </li></ul>
    38. 38. Quick Dev Tips - Timesavers 'indices' => array( 0 => array('name' => ' myindexname ', 'type' => 'index', 'fields' => array(' field1 ', ' field2 ', ... ' fieldn ', ), ), ), Remember LOWERCASE when adding custom indexes to vardefs Fields/Indexes name must be max 30 chars for compatibility cross-database Remember _c suffix when defining custom fields in manifest 'custom_fields' => array(0 => array('name' => 'erpcode _c ', 'vname' => 'LBL_ERPCODE', ... Don't forget to add (possibly clever) table indexes in vardefs.php
    39. 39. Some Advice <ul><li>Implement Your internal Wiki.
    40. 40. Use a Source Control (SVN, GIT...) even if You are a “one man team”.
    41. 41. Test on Linux.
    42. 42. Use Virtual Machines. </li></ul>
    43. 43. Work in Progress <ul><li>Module ngReports
    44. 44. Module ngSMS
    45. 45. Composite Module ngInterface
    46. 46. ...many others... </li></ul>Work as a Developer Think as a User
    47. 47. ngReports Reporting Module linked to Jasper Server Jasper Server iReports
    48. 48. ngSMS A SugarCRM's Module to send SMS messages from Modules, Menus, ShortCut Bar and Workflow throught different providers and protocols. SMS Gateway # 2 SMS Gateway # 1 SMS Gateway # 3 SMS Gateway # n
    49. 49. ngInterface Module for sending changed data from a programmable RDBMS (JDBC-compliant) to SugarCRM via a single REST Web Service
    50. 50. Here We Are
    51. 51. Thank You ! Fabio GRANDE [email_address]