Как вывести итоговую сумму в списке счетов Vtiger CRM 6.5?

Как вывести итоговую сумму в списке счетов Vtiger CRM 6.5?

Часто бывает необходимо посчитать итоговую сумму в каком-либо справочнике VtigerCRM или в ListView. С подобной задачей ко мне недавно обратился заказчик. Он попросил посчитать в списке счетов итог по балансам. Т.е. чтобы под списком выводилась итоговая сумма по всем счетам в списке. Пример реализации приведён на картинке.

Часто бывает необходимо посчитать итоговую сумму в каком-либо справочнике VtigerCRM или в ListView. С подобной задачей ко мне недавно обратился заказчик. Он попросил посчитать в списке счетов итог по балансам. Т.е. чтобы под списком выводилась итоговая сумма по всем счетам в списке. Пример реализации приведён на картинке.

Ниже я подробно опишу, как подобное решение было реализовано.

Итак, первое с чего мы начнём, это посчитаем общую сумму, которую мы получаем в списке. Самое простое решение - это обойти массив и просуммировать по массиву поле balance - именно так называется итоговое поле в счетах Vtiger CRM.

Для этого правим файл modules/Invoice/views/List.php, по-умолчанию там пустой класс, поэтому можно смело всё удалять и вставить вот этот код:

<?php

class Invoice_List_View extends Inventory_List_View {

    /*

 * Function to initialize the required data in smarty to display the List View Contents

 */

    public function initializeListViewContents(Vtiger_Request $request, Vtiger_Viewer $viewer) {

        $moduleName = $request->getModule();

        $cvId = $this->viewName;

        $pageNumber = $request->get('page');

        $orderBy = $request->get('orderby');

        $sortOrder = $request->get('sortorder');

        if($sortOrder == "ASC"){

            $nextSortOrder = "DESC";

            $sortImage = "icon-chevron-down";

        }else{

            $nextSortOrder = "ASC";

            $sortImage = "icon-chevron-up";

        }

 

        if(empty ($pageNumber)){

            $pageNumber = '1';

        }

 

        $listViewModel = Vtiger_ListView_Model::getInstance($moduleName, $cvId);

        $currentUser = Users_Record_Model::getCurrentUserModel();

 

        $linkParams = array('MODULE'=>$moduleName, 'ACTION'=>$request->get('view'), 'CVID'=>$cvId);

        $linkModels = $listViewModel->getListViewMassActions($linkParams);

 

        $pagingModel = new Vtiger_Paging_Model();

        $pagingModel->set('page', $pageNumber);

        $pagingModel->set('viewid', $request->get('viewname'));

 

        if(!empty($orderBy)) {

            $listViewModel->set('orderby', $orderBy);

            $listViewModel->set('sortorder',$sortOrder);

        }

 

        $searchKey = $request->get('search_key');

        $searchValue = $request->get('search_value');

        $operator = $request->get('operator');

        if(!empty($operator)) {

            $listViewModel->set('operator', $operator);

            $viewer->assign('OPERATOR',$operator);

            $viewer->assign('ALPHABET_VALUE',$searchValue);

        }

        if(!empty($searchKey) && !empty($searchValue)) {

            $listViewModel->set('search_key', $searchKey);

            $listViewModel->set('search_value', $searchValue);

        }

 

        $searchParmams = $request->get('search_params');

        if(empty($searchParmams)) {

            $searchParmams = array();

        }

        $transformedSearchParams = $this->transferListSearchParamsToFilterCondition($searchParmams, $listViewModel->getModule());

        $listViewModel->set('search_params',$transformedSearchParams);

 

 

        //To make smarty to get the details easily accesible

        foreach($searchParmams as $fieldListGroup){

            foreach($fieldListGroup as $fieldSearchInfo){

                $fieldSearchInfo['searchValue'] = $fieldSearchInfo[2];

                $fieldSearchInfo['fieldName'] = $fieldName = $fieldSearchInfo[0];

                $searchParmams[$fieldName] = $fieldSearchInfo;

            }

        }

 

 

        if(!$this->listViewHeaders){

            $this->listViewHeaders = $listViewModel->getListViewHeaders();

        }

        if(!$this->listViewEntries){

            $this->listViewEntries = $listViewModel->getListViewEntries($pagingModel);

        }

        $noOfEntries = count($this->listViewEntries);

 

        $viewer->assign('MODULE', $moduleName);

 

        if(!$this->listViewLinks){

            $this->listViewLinks = $listViewModel->getListViewLinks($linkParams);

        }

        $viewer->assign('LISTVIEW_LINKS', $this->listViewLinks);

 

        $viewer->assign('LISTVIEW_MASSACTIONS', $linkModels['LISTVIEWMASSACTION']);

 

        $viewer->assign('PAGING_MODEL', $pagingModel);

        $viewer->assign('PAGE_NUMBER',$pageNumber);

 

        $viewer->assign('ORDER_BY',$orderBy);

        $viewer->assign('SORT_ORDER',$sortOrder);

        $viewer->assign('NEXT_SORT_ORDER',$nextSortOrder);

        $viewer->assign('SORT_IMAGE',$sortImage);

        $viewer->assign('COLUMN_NAME',$orderBy);

 

        $viewer->assign('LISTVIEW_ENTRIES_COUNT',$noOfEntries);

        $viewer->assign('LISTVIEW_HEADERS', $this->listViewHeaders);

        $viewer->assign('LISTVIEW_ENTRIES', $this->listViewEntries);

 

        if (PerformancePrefs::getBoolean('LISTVIEW_COMPUTE_PAGE_COUNT', false)) {

            if(!$this->listViewCount){

                $this->listViewCount = $listViewModel->getListViewCount();

            }

            $totalCount = $this->listViewCount;

            $pageLimit = $pagingModel->getPageLimit();

            $pageCount = ceil((int) $totalCount / (int) $pageLimit);

 

            if($pageCount == 0){

                $pageCount = 1;

            }

            $viewer->assign('PAGE_COUNT', $pageCount);

            $viewer->assign('LISTVIEW_COUNT', $totalCount);

        }

        // Sergey Emelyanov add calculation of current balance on list view page

        $curbal = 0;

        if (!empty($this->listViewEntries)) {

            foreach ($this->listViewEntries as $entry) {

                $curbal += $entry->get('balance');

            }

        }

        $viewer->assign('CURBALANCE', $curbal);

        // Sergey Emelyanov end calculation

        $viewer->assign('LIST_VIEW_MODEL', $listViewModel);

        $viewer->assign('GROUPS_IDS', Vtiger_Util_Helper::getGroupsIdsForUsers($currentUser->getId()));

        $viewer->assign('IS_RECORD_CREATABLE', $listViewModel->getModule()->isPermitted('CreateView'));

        $viewer->assign('IS_MODULE_EDITABLE', $listViewModel->getModule()->isPermitted('EditView'));

        $viewer->assign('IS_MODULE_DELETABLE', $listViewModel->getModule()->isPermitted('Delete'));

        $viewer->assign('SEARCH_DETAILS', $searchParmams);

    }

}

?>

В этом коде мы дополняем наш класс, перезаписываем метода получения счетов и в нём передаём в шаблон итоговую сумму по балансам.

Итак, балансы мы в шаблон передали, теперь осталось дело за малым - вёрстка. Нужно это всё вывести на экран.

Для этого мы создаём файл layouts/vlayout/modules/Invoice/ListViewContents.tpl со следующим содержимым:

{strip}

<input type="hidden" id="view" value="{$VIEW}" />

<input type="hidden" id="pageStartRange" value="{$PAGING_MODEL->getRecordStartRange()}" />

<input type="hidden" id="pageEndRange" value="{$PAGING_MODEL->getRecordEndRange()}" />

<input type="hidden" id="previousPageExist" value="{$PAGING_MODEL->isPrevPageExists()}" />

<input type="hidden" id="nextPageExist" value="{$PAGING_MODEL->isNextPageExists()}" />

<input type="hidden" id="alphabetSearchKey" value= "{$MODULE_MODEL->getAlphabetSearchField()}" />

<input type="hidden" id="Operator" value="{$OPERATOR}" />

<input type="hidden" id="alphabetValue" value="{$ALPHABET_VALUE}" />

<input type="hidden" id="totalCount" value="{$LISTVIEW_COUNT}" />

<input type='hidden' value="{$PAGE_NUMBER}" id='pageNumber'>

<input type='hidden' value="{$PAGING_MODEL->getPageLimit()}" id='pageLimit'>

<input type="hidden" value="{$LISTVIEW_ENTRIES_COUNT}" id="noOfEntries">

 

{assign var = ALPHABETS_LABEL value = vtranslate('LBL_ALPHABETS', 'Vtiger')}

{assign var = ALPHABETS value = ','|explode:$ALPHABETS_LABEL}

 

<div class="alphabetSorting noprint">

<table width="100%" class="table-bordered" style="border: 1px solid #ddd;table-layout: fixed">

<tbody>

<tr>

{foreach item=ALPHABET from=$ALPHABETS}

<td class="alphabetSearch textAlignCenter cursorPointer {if $ALPHABET_VALUE eq $ALPHABET} highlightBackgroundColor {/if}" style="padding : 0px !important"><a id="{$ALPHABET}" href="#">{$ALPHABET}</a></td>

{/foreach}

</tr>

</tbody>

</table>

</div>

<div id="selectAllMsgDiv" class="alert-block msgDiv noprint">

<strong><a id="selectAllMsg">{vtranslate('LBL_SELECT_ALL',$MODULE)}&nbsp;{vtranslate($MODULE ,$MODULE)}&nbsp;(<span id="totalRecordsCount"></span>)</a></strong>

</div>

<div id="deSelectAllMsgDiv" class="alert-block msgDiv noprint">

<strong><a id="deSelectAllMsg">{vtranslate('LBL_DESELECT_ALL_RECORDS',$MODULE)}</a></strong>

</div>

<div class="contents-topscroll noprint">

<div class="topscroll-div">

&nbsp;

</div>

</div>

<div class="listViewEntriesDiv contents-bottomscroll">

<div class="bottomscroll-div">

<input type="hidden" value="{$ORDER_BY}" id="orderBy">

<input type="hidden" value="{$SORT_ORDER}" id="sortOrder">

<span class="listViewLoadingImageBlock hide modal noprint" id="loadingListViewModal">

<img class="listViewLoadingImage" src="{vimage_path('loading.gif')}" alt="no-image" title="{vtranslate('LBL_LOADING', $MODULE)}"/>

<p class="listViewLoadingMsg">{vtranslate('LBL_LOADING_LISTVIEW_CONTENTS', $MODULE)}........</p>

</span>

{assign var=WIDTHTYPE value=$CURRENT_USER_MODEL->get('rowheight')}

<table class="table table-bordered listViewEntriesTable">

<thead>

<tr class="listViewHeaders">

<th width="5%">

<input type="checkbox" id="listViewEntriesMainCheckBox" />

</th>

{foreach item=LISTVIEW_HEADER from=$LISTVIEW_HEADERS}

<th nowrap {if $LISTVIEW_HEADER@last} colspan="2" {/if}>

<a href="javascript:void(0);" class="listViewHeaderValues" data-nextsortorderval="{if $COLUMN_NAME eq $LISTVIEW_HEADER->get('column')}{$NEXT_SORT_ORDER}{else}ASC{/if}" data-columnname="{$LISTVIEW_HEADER->get('column')}">{vtranslate($LISTVIEW_HEADER->get('label'), $MODULE)}

&nbsp;&nbsp;{if $COLUMN_NAME eq $LISTVIEW_HEADER->get('column')}<img class="{$SORT_IMAGE} icon-white">{/if}</a>

</th>

{/foreach}

</tr>

</thead>

        {if $MODULE_MODEL->isQuickSearchEnabled()}

        <tr>

            <td></td>

{foreach item=LISTVIEW_HEADER from=$LISTVIEW_HEADERS}

             <td>

                 {assign var=FIELD_UI_TYPE_MODEL value=$LISTVIEW_HEADER->getUITypeModel()}

                {include file=vtemplate_path($FIELD_UI_TYPE_MODEL->getListSearchTemplateName(),$MODULE_NAME)

                    FIELD_MODEL= $LISTVIEW_HEADER SEARCH_INFO=$SEARCH_DETAILS[$LISTVIEW_HEADER->getName()] USER_MODEL=$CURRENT_USER_MODEL}

             </td>

{/foreach}

<td>

<button class="btn" data-trigger="listSearch">{vtranslate('LBL_SEARCH', $MODULE )}</button>

</td>

        </tr>

        {/if}

{foreach item=LISTVIEW_ENTRY from=$LISTVIEW_ENTRIES name=listview}

<tr class="listViewEntries" data-id='{$LISTVIEW_ENTRY->getId()}' data-recordUrl='{$LISTVIEW_ENTRY->getDetailViewUrl()}' id="{$MODULE}_listView_row_{$smarty.foreach.listview.index+1}">

            <td  width="5%" class="{$WIDTHTYPE}">

<input type="checkbox" value="{$LISTVIEW_ENTRY->getId()}" class="listViewEntriesCheckBox"/>

</td>

{foreach item=LISTVIEW_HEADER from=$LISTVIEW_HEADERS}

{assign var=LISTVIEW_HEADERNAME value=$LISTVIEW_HEADER->get('name')}

<td class="listViewEntryValue {$WIDTHTYPE}" data-field-type="{$LISTVIEW_HEADER->getFieldDataType()}" nowrap>

{if ($LISTVIEW_HEADER->isNameField() eq true or $LISTVIEW_HEADER->get('uitype') eq '4') and $MODULE_MODEL->isListViewNameFieldNavigationEnabled() eq true }

<a href="{$LISTVIEW_ENTRY->getDetailViewUrl()}">{$LISTVIEW_ENTRY->get($LISTVIEW_HEADERNAME)}</a>

{else if $LISTVIEW_HEADER->get('uitype') eq '72'}

{assign var=CURRENCY_SYMBOL_PLACEMENT value={$CURRENT_USER_MODEL->get('currency_symbol_placement')}}

{if $CURRENCY_SYMBOL_PLACEMENT eq '1.0$'}

{$LISTVIEW_ENTRY->get($LISTVIEW_HEADERNAME)}{$LISTVIEW_ENTRY->get('currencySymbol')}

{else}

{$LISTVIEW_ENTRY->get('currencySymbol')}{$LISTVIEW_ENTRY->get($LISTVIEW_HEADERNAME)}

{/if}

{else}

                    {if $LISTVIEW_HEADER->getFieldDataType() eq 'double'}

                        {decimalFormat($LISTVIEW_ENTRY->get($LISTVIEW_HEADERNAME))}

                    {else}

                        {$LISTVIEW_ENTRY->get($LISTVIEW_HEADERNAME)}

                    {/if}

{/if}

{if $LISTVIEW_HEADER@last}

</td><td nowrap class="{$WIDTHTYPE}">

<div class="actions pull-right">

<span class="actionImages">

<a href="{$LISTVIEW_ENTRY->getFullDetailViewUrl()}"><i title="{vtranslate('LBL_SHOW_COMPLETE_DETAILS', $MODULE)}" class="icon-th-list alignMiddle"></i></a>&nbsp;

{if $IS_MODULE_EDITABLE}

<a href='{$LISTVIEW_ENTRY->getEditViewUrl()}'><i title="{vtranslate('LBL_EDIT', $MODULE)}" class="icon-pencil alignMiddle"></i></a>&nbsp;

{/if}

{if $IS_MODULE_DELETABLE}

<a class="deleteRecordButton"><i title="{vtranslate('LBL_DELETE', $MODULE)}" class="icon-trash alignMiddle"></i></a>

{/if}

</span>

</div></td>

{/if}

</td>

{/foreach}

</tr>

{/foreach}

</table>

 

<!--added this div for Temporarily -->

{if $LISTVIEW_ENTRIES_COUNT eq '0'}

<table class="emptyRecordsDiv">

<tbody>

<tr>

<td>

{assign var=SINGLE_MODULE value="SINGLE_$MODULE"}

                    {* SalesPlatform.ru begin *}

                    {vtranslate('LBL_NOT_FOUND')} {vtranslate($MODULE, $MODULE)}.{if $IS_MODULE_EDITABLE} {vtranslate('LBL_CREATE')} <a href="{$MODULE_MODEL->getCreateRecordUrl()}">{vtranslate($SINGLE_MODULE, $MODULE)}</a>{/if}

{*{vtranslate('LBL_NO')} {vtranslate($MODULE, $MODULE)} {vtranslate('LBL_FOUND')}.{if $IS_MODULE_EDITABLE} {vtranslate('LBL_CREATE')} <a href="{$MODULE_MODEL->getCreateRecordUrl()}">{vtranslate($SINGLE_MODULE, $MODULE)}</a>{/if}*}

                    {* SalesPlatform.ru end *}

</td>

</tr>

</tbody>

</table>

{/if}

</div>

{* Sergey Emelyanov add balance total*}

<br>

<div><p>{vtranslate('LBL_BALANCE TOTAL',$MODULE)} &nbsp;&nbsp; {$CURBALANCE} {decimalFormat($LISTVIEW_ENTRY->get('currencySymbol'))}</p></div>

</div>

{/strip}

Здесь мы просто выводим в теге p нужную нам строчку. При желании к ней можно применить свои стили, поменяв в ней цвет.

Обратите внимание, текст выводится через языковую переменную LBL_BALANCE_TOTAL. Для её расшифровки нужно внести в файл languages/ru_ru/Invoice.php следующую строчку: 'LBL_BALANCE TOTAL'  => 'Итого по балансу:', или любой другой перевод, который вы пожелаете.

После этих манипуляций и после нескольких обновлений страницы у вас под таблицей должна появиться строчка, которая будет считать итог по всем счетам в выбранном вами фильтре.