SugarCRM - adding a total for the opportunity amount

It's long frustrated me that SugarCRM's opportunity list view doesn't show a total for the opportunity amount. So, I finally decided to fix this. A few notes to start:
  1. I am using SugarCRM CE 6.5.5.
  2. I used this post heavily http://forums.sugarcrm.com/f6/how-show-total-result-58485/
  3. I also referred to this post http://developers.sugarcrm.com/wordpress/2009/03/23/quick-listview-customization/
Ok, let's dive in.

1. Setup a new view processor

We are going to override some of the main SugarCRM functions. Find or create custom/modules/Opportunities/views/view.list.php. Setup the inheritance, so start with this... [php] <?php require_once('include/MVC/View/views/view.list.php'); class OpportunitiesViewList extends ViewList { } [/php] That gets Sugar to pay attention to our custom code. We really want to override the ListViewProcess function. But to do that, we also need to override the display function. So, first, we copy the display function from the default view.list.php (in include/MVC/View/views/view.list.php). And we make sure that we change the code so that it will refer to our own ListViewProcess  function. So, add the display override... [php] <?php require_once('include/MVC/View/views/view.list.php'); class OpportunitiesViewList extends ViewList { public function display(){ if(!$this->bean || !$this->bean->ACLAccess('list')){ ACLController::displayNoAccess(); } else { parent::listViewPrepare(); $this->listViewProcess(); } } } [/php] So that gets Sugar to use our new display function, which gets Sugar to use our new ListViewProcess function. So, let's again copy the base and then we will modify it. Add this to your custom view.list.php class. [php] function listViewProcess(){ $this->processSearchForm(); $this->lv->searchColumns = $this->searchForm->searchColumns; if(!$this->headers) return; if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){ $this->lv->ss->assign("SEARCH",true); $this->lv->setup($this->seed, 'include/ListView/ListViewGeneric.tpl', $this->where, $this->params); $savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']); echo $this->lv->display(); } } [/php]

2. Modify the ListViewProcess function

In order to get what we want, we need to 1) calculate the total, and then 2) direct Sugar to use a different view template. So, edit the ListViewProcess function like this. [php] function listViewProcess(){ $this->processSearchForm(); $this->lv->searchColumns = $this->searchForm->searchColumns; if(!$this->headers) return; if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){ $this->lv->ss->assign("SEARCH",true); $this->lv->setup($this->seed, 'custom/modules/Opportunities/tpls/ListView.tpl', $this->where, $this->params); $savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']); $total = 0; foreach($this->lv->data['data'] as $entry) { $total += unformat_number($entry['AMOUNT_USDOLLAR']); } $this->lv->ss->assign('TOTAL_AMOUNT',format_number($total)); echo $this->lv->display(); } } [/php] This modification does 2 things. It runs through the list data and calculates the total amount of what's being shown. It also defines a different template for the view to be shown in (/custom/modules/Opportunities/tpls/ListView.tpl). So, now we need to create that template.

3. Create the custom template

As usual, we will start from the stock template, found at /include/ListView/ListViewGeneric.tpl. Copy that into /custom/modules/Opportunities/tpls/ListView.tpl The thing we want to do is display that total amount as a new row in the display. We need to add that row after the loop that displays all the data rows. In the current ListViewGeneric.tpl, we want to add our row after line 239, viz. right after that "{/foreach}", which ends the data display loop. Since we want to keep the same column structure, we can use parts of the data display, just stripped down. There is a bunch of Smarty stuff in here that I don't quite understand, so this might not be all that could be removed. Anyway, here's what to add. [php] <tr height='20' class='totals'> {if !empty($quickViewLinks)} <td width='2%' nowrap colspan='2'></td> {/if} {counter start=0 name="colCounter" print=false assign="colCounter"} {foreach from=$displayColumns key=col item=params} {strip} <td {if $scope_row} scope='row' {/if} align='{$params.align|default:'left'}' valign="top" class="{if ($params.type == 'teamset')}nowrap{/if}{if preg_match('/PHONE/', $col)} phone{/if}"> {if $col == 'AMOUNT_USDOLLAR'}<b>${$TOTAL_AMOUNT}</b>{/if} </td> {/strip} {assign var='scope_row' value=false} {counter name="colCounter"} {/foreach} <td align='right'>{$pageData.additionalDetails.$id}</td> </tr> [/php] Notice the use of the "TOTAL_AMOUNT" variable we defined in the view processor.

Conclusion

  1. You can see that this opens up a whole world of possibilities. My next step is to create a more generic setup that will automatically create totals on all
  2. I am not sure how upgrade safe this is. Since I had to copy parts of the stock functions, it seems like my version might break when I upgrade, if the underlying functions change.
  3. I hope there aren't any errors. I tried to take all the info from working files. But, if something is wrong, please let me know, and I will correct this post.