In continuation with our love with Issabele customization,
today we will discuss and guide step by step on how to implement the
billing report customization, as we discussed in our last issabele post
that issabele is an asterisk based IP-PBX solution (open source) which
manage enterprise Voip network. So the custom requirements were -
1.
On the GUI of billing report page, need to add "Cost Center" parameter
on the Search tab menu.So in total will be Eight search parameters now
as shown below:
- Rate Applied
- Duration
- Rate Value
- Source
- Destination
- Dst. Channel
- Account Code
- Cost Center
2. On the GUI page of billing report need to add Cost Center in the Billing Report table
3. Add Custom dynamic Column on the report table
4. Add custom button on GUI , if user click on that button it should add the custom column on the report table
5. Map the Cost Center code with mysql CDR table.
In
order to achieve the desired outputs, you need to make change in HTML
and PHP source code of Issabele. HTML code is segregated in multiple
files across the directories for obvious (security purpose)
I will provide you the exact path and the changes that need to be done.
First
of all, make sure you download or take backup of the source code
through Filezilla (or similar application), you need ideally backup
complete folder /var/www/html/ and make backups on the server for below
two files:-
/var/www/html/modules/billing_report/index.php
/var/www/html/index.php
Now follow below steps to add the Cost Center in the Search menu and hard code on the Billing report GUI page.
Procedure-
SSH to IP address of your Asterisk Issabele instance and login through root user/password.
1. cd /var/www/html/modules/billing_report/
2. vim index.php
3. Update below section of config in the index.pho file , then press Escape and followed by ":wq"
2. vim index.php
3. Update below section of config in the index.pho file , then press Escape and followed by ":wq"
-- Config to Update--
$arrTmp[9] = $sum_cost;
$arrTmp[10] = $value['costcenter'];
$arrData[] = $arrTmp;
}
}
$arrColumns = array(_tr("Date"), _tr("Rate Applied"), _tr("Rate Value"), _tr("Source"), _tr("Destination"), _tr("Dst. Channel"),_tr("Account Code"),_tr("Duration"),_tr("Cost"),_tr("Summary Cost"),_tr("Cost Center"));
}else{
$limit = 20;
$oGrid->setLimit($limit);
$oGrid->setTotal($totalbilling_report);
$offset = $oGrid->calculateOffset();
$arrResult = $pbilling_report->obtainReport($limit, $offset, $filter_field, $filter_value_tmp, $start_date, $end_date, $pDBSQLite, $time, "ANSWERED", "outgoing", $arrConfig);
$arrData = array();
// obteniendo tarifa default
$rates_default = $pbilling_report->getDefaultRate($pDBSQLite);
$rate = $rates_default['rate'];
$sum_cost = 0;
$rate_offset_default = $rates_default['rate_offset'];
if(is_array($arrResult) && $totalbilling_report>0){
foreach($arrResult as $key => $value){
$arrTmp[0] = $value['Date'];
$hidden_digits = $value['digits'];
if($value['Rate_applied'] == null){
$arrRateTmp = getRate($arr_rates, $value);
$value['Rate_applied'] = $arrRateTmp['Rate_applied'];
$value['Rate_value'] = $arrRateTmp['Rate_value'];
$value['Offset'] = $arrRateTmp['Offset'];
$hidden_digits = $arrRateTmp['digits'];
}
if($value['Rate_applied'] == null)
$rate_applied = _tr('default');
else
$rate_applied = $value['Rate_applied'];
$arrTmp[1] = $rate_applied;
if($value['Rate_value'] == null)
$rate_value = $rate;
else
$rate_value = $value['Rate_value'];
if($value['Offset'] == null)
$rate_offset = $rate_offset_default;
else
$rate_offset = $value['Offset'];
if($hidden_digits == 0)
$destination = $value['Destination'];
else{
$size_destination = strlen($value['Destination']);
if($hidden_digits < $size_destination){
$hide = getCharsAsterisk($hidden_digits);
$destination = substr($value['Destination'],0,-$hidden_digits).$hide;
}
else{
$size_destination = strlen($value['Destination']);
$destination = getCharsAsterisk($size_destination);
}
}
$arrTmp[2] = $rate_value;
$arrTmp[3] = $value['Src'];
$arrTmp[4] = $destination;
$arrTmp[5] = $value['Dst_channel'];
$arrTmp[6] = $value['accountcode'];
$iDuracion = $value['duration'];
$iSec = $iDuracion % 60; $iDuracion = (int)(($iDuracion - $iSec) / 60);
$iMin = $iDuracion % 60; $iDuracion = (int)(($iDuracion - $iMin) / 60);
$sTiempo = $value['duration']."s";
if ($value['duration'] >= 60) {
if ($iDuracion > 0) $sTiempo .= " ({$iDuracion}h {$iMin}m {$iSec}s)";
elseif ($iMin > 0) $sTiempo .= " ({$iMin}m {$iSec}s)";
}
$arrTmp[7] = $sTiempo;
$charge=(($value['duration']/60)*$rate_value)+$rate_offset;
$arrTmp[8] = number_format($charge,3);
$sum_cost = $sum_cost + $arrTmp[8];
$arrTmp[9] = $sum_cost;
$arrTmp[10] = $value['costcenter'];
$arrData[] = $arrTmp;
}
}
$arrColumns = array(_tr("Date"), _tr("Rate Applied"), _tr("Rate Value"), _tr("Source"), _tr("Destination"), _tr("Dst. Channel"),_tr("Account Code"),_tr("Duration"),_tr("Cost"),_tr("Summary Cost"),_tr("Cost Center"));
}
$arrTmp[10] = $value['costcenter'];
$arrData[] = $arrTmp;
}
}
$arrColumns = array(_tr("Date"), _tr("Rate Applied"), _tr("Rate Value"), _tr("Source"), _tr("Destination"), _tr("Dst. Channel"),_tr("Account Code"),_tr("Duration"),_tr("Cost"),_tr("Summary Cost"),_tr("Cost Center"));
}else{
$limit = 20;
$oGrid->setLimit($limit);
$oGrid->setTotal($totalbilling_report);
$offset = $oGrid->calculateOffset();
$arrResult = $pbilling_report->obtainReport($limit, $offset, $filter_field, $filter_value_tmp, $start_date, $end_date, $pDBSQLite, $time, "ANSWERED", "outgoing", $arrConfig);
$arrData = array();
// obteniendo tarifa default
$rates_default = $pbilling_report->getDefaultRate($pDBSQLite);
$rate = $rates_default['rate'];
$sum_cost = 0;
$rate_offset_default = $rates_default['rate_offset'];
if(is_array($arrResult) && $totalbilling_report>0){
foreach($arrResult as $key => $value){
$arrTmp[0] = $value['Date'];
$hidden_digits = $value['digits'];
if($value['Rate_applied'] == null){
$arrRateTmp = getRate($arr_rates, $value);
$value['Rate_applied'] = $arrRateTmp['Rate_applied'];
$value['Rate_value'] = $arrRateTmp['Rate_value'];
$value['Offset'] = $arrRateTmp['Offset'];
$hidden_digits = $arrRateTmp['digits'];
}
if($value['Rate_applied'] == null)
$rate_applied = _tr('default');
else
$rate_applied = $value['Rate_applied'];
$arrTmp[1] = $rate_applied;
if($value['Rate_value'] == null)
$rate_value = $rate;
else
$rate_value = $value['Rate_value'];
if($value['Offset'] == null)
$rate_offset = $rate_offset_default;
else
$rate_offset = $value['Offset'];
if($hidden_digits == 0)
$destination = $value['Destination'];
else{
$size_destination = strlen($value['Destination']);
if($hidden_digits < $size_destination){
$hide = getCharsAsterisk($hidden_digits);
$destination = substr($value['Destination'],0,-$hidden_digits).$hide;
}
else{
$size_destination = strlen($value['Destination']);
$destination = getCharsAsterisk($size_destination);
}
}
$arrTmp[2] = $rate_value;
$arrTmp[3] = $value['Src'];
$arrTmp[4] = $destination;
$arrTmp[5] = $value['Dst_channel'];
$arrTmp[6] = $value['accountcode'];
$iDuracion = $value['duration'];
$iSec = $iDuracion % 60; $iDuracion = (int)(($iDuracion - $iSec) / 60);
$iMin = $iDuracion % 60; $iDuracion = (int)(($iDuracion - $iMin) / 60);
$sTiempo = $value['duration']."s";
if ($value['duration'] >= 60) {
if ($iDuracion > 0) $sTiempo .= " ({$iDuracion}h {$iMin}m {$iSec}s)";
elseif ($iMin > 0) $sTiempo .= " ({$iMin}m {$iSec}s)";
}
$arrTmp[7] = $sTiempo;
$charge=(($value['duration']/60)*$rate_value)+$rate_offset;
$arrTmp[8] = number_format($charge,3);
$sum_cost = $sum_cost + $arrTmp[8];
$arrTmp[9] = $sum_cost;
$arrTmp[10] = $value['costcenter'];
$arrData[] = $arrTmp;
}
}
$arrColumns = array(_tr("Date"), _tr("Rate Applied"), _tr("Rate Value"), _tr("Source"), _tr("Destination"), _tr("Dst. Channel"),_tr("Account Code"),_tr("Duration"),_tr("Cost"),_tr("Summary Cost"),_tr("Cost Center"));
}
Below code is for Search Menu update --
function createFieldFilter(){
$arrFilter = array(
"rate_applied" => _tr("Rate Applied"),
"duration" => _tr("Duration"),
"rate_value" => _tr("Rate Value"),
"src" => _tr("Source"),
"dst" => _tr("Destination"),
"dstchannel" => _tr("Dst. Channel"),
"accountcode" => _tr("Account Code"),
"costcenter" => _tr("Cost Center"),
);
After saving this code on
the index.php file , we will get below GUI on issabele billing report
page as shown in the picture below;
Issabele
Customized Search Menu will now looks like as below, and you can see
the custom column "Cost Center" has been added to the search menu
option.
Moving to last leg of our Issabele customization i.e adding option for end user to add dynamic columns in the report.
To
get this done, we need to add a "Click"button on the GUI page and a
context bar where end user can input the name of the column , so that
when user write a custom name on the context bar followed by clicking on
the "Add Button", it should create the new custom dynamic column in the
report where user can do the real time editing or put some tags in it
manually and get option of downloading the report in three formats
1. PDF -(view on browser option also available)
2.Excel Spreadsheet
3.CSV text file
To achieve the above points you need to edit another index.php file that is stored under
harmosin-issabele# cd /var/www/html/index.php
I will use Java script to add a button and coding will be done as below;
<<For Adding a button>>>>
<script type="text/javascript">
var customize_btn=document.createElement("button");
customize_btn.innerHTML="Add Column";
customize_btn.className="neo-table-button-filter-right";
var customize_i=document.createElement("i");
customize_i.classList.add="fa";
customize_i.classList.add="fa-caret-down";
customize_btn.appendChild(customize_i);
var btn_list=document.getElementsByClassName("neo-table-header-row")[0];
btn_list.appendChild(customize_btn);
</script>
var customize_btn=document.createElement("button");
customize_btn.innerHTML="Add Column";
customize_btn.className="neo-table-button-filter-right";
var customize_i=document.createElement("i");
customize_i.classList.add="fa";
customize_i.classList.add="fa-caret-down";
customize_btn.appendChild(customize_i);
var btn_list=document.getElementsByClassName("neo-table-header-row")[0];
btn_list.appendChild(customize_btn);
</script>
<<For dynamic column and context tab>>>>
<script type="text/javascript">
var customize_btn=document.createElement("button");
customize_btn.innerHTML="Add Column";
customize_btn.className="neo-table-button-filter-right";
var customize_i=document.createElement("i");
customize_i.classList.add="fa";
customize_i.classList.add="fa-caret-down";
customize_btn.appendChild(customize_i);
customize_btn.style.border="1px solid grey";
customize_btn.style.borderRadius="4px";
customize_btn.style.marginLeft="10px";
var input_custom=document.createElement("input");
input_custom.type="text";
input_custom.classList.add="search-input";
input_custom.classList.add="neo-table-button-filter-right";
input_custom.id="custom_title";
input_custom.placeholder="Column Title";
var btn_list=document.getElementsByClassName("neo-table-header-row")[0];
btn_list.appendChild(customize_btn);
btn_list.appendChild(input_custom);
customize_btn.addEventListener("click", function(e) {
e.preventDefault();
$("body").width("+=50");
$("#neo-contentbox-maincolumn").width("+=50");
var table=document.getElementsByClassName("issabel-standard-table")[0];
$(".issabel-standard-table").width("+=100");
var tablethead=document.getElementsByClassName("issabel-standard-table")[0].getElementsByTagName("thead")[0].getElementsByTagName("tr")[0];
var title=document.getElementById("custom_title").value;
var thcustom=document.createElement("th");
thcustom.innerHTML=title;
thcustom.style.width="120%";
thcustom.id="th_"+title;
tablethead.appendChild(thcustom);
var tabletbody=document.getElementsByClassName("issabel-standard-table")[0].getElementsByTagName("tbody")[0];
var trs=tabletbody.getElementsByTagName("tr");
for (var i = 0; i < trs.length; i++) {
var td=document.createElement("td");
var input=document.createElement("input");
input.type="text";
input.style.width="70%";
input.id="input_" + i.toString() + "_" + title;
td.appendChild(input);
trs[i].appendChild(td);
}
});
</script>
var customize_btn=document.createElement("button");
customize_btn.innerHTML="Add Column";
customize_btn.className="neo-table-button-filter-right";
var customize_i=document.createElement("i");
customize_i.classList.add="fa";
customize_i.classList.add="fa-caret-down";
customize_btn.appendChild(customize_i);
customize_btn.style.border="1px solid grey";
customize_btn.style.borderRadius="4px";
customize_btn.style.marginLeft="10px";
var input_custom=document.createElement("input");
input_custom.type="text";
input_custom.classList.add="search-input";
input_custom.classList.add="neo-table-button-filter-right";
input_custom.id="custom_title";
input_custom.placeholder="Column Title";
var btn_list=document.getElementsByClassName("neo-table-header-row")[0];
btn_list.appendChild(customize_btn);
btn_list.appendChild(input_custom);
customize_btn.addEventListener("click", function(e) {
e.preventDefault();
$("body").width("+=50");
$("#neo-contentbox-maincolumn").width("+=50");
var table=document.getElementsByClassName("issabel-standard-table")[0];
$(".issabel-standard-table").width("+=100");
var tablethead=document.getElementsByClassName("issabel-standard-table")[0].getElementsByTagName("thead")[0].getElementsByTagName("tr")[0];
var title=document.getElementById("custom_title").value;
var thcustom=document.createElement("th");
thcustom.innerHTML=title;
thcustom.style.width="120%";
thcustom.id="th_"+title;
tablethead.appendChild(thcustom);
var tabletbody=document.getElementsByClassName("issabel-standard-table")[0].getElementsByTagName("tbody")[0];
var trs=tabletbody.getElementsByTagName("tr");
for (var i = 0; i < trs.length; i++) {
var td=document.createElement("td");
var input=document.createElement("input");
input.type="text";
input.style.width="70%";
input.id="input_" + i.toString() + "_" + title;
td.appendChild(input);
trs[i].appendChild(td);
}
});
</script>
Once done, you will get the below results where you see a "Add Button" and "context bar"
and on clicking this add button a new column getting dynamically added to the billing report as per the requirement.
This
covers our section of customizing the issabele billing report GUI,
where we achieved the desired results by making few changes/addition to
the PHP/HTML code in baseline of index.php source code.
I
hope it will be helpful for you if you are looking for any modification
in CDR (call detail record or billing reports) on your IP-PBX system.
By following the same suit of options and methods you can make changes
on any of the issabele PBX module as per the requirements.
"Now lets me update some of trending news i have recieved last week regarding Collab"
Collaboration FAQs
What's new in Cisco Webex Meetings update for July 2020
Customers will love these innovations, make sure to tell them about all the goodness Webex Meetings July update enhancements deliver 🙌
- Blur or Change Your Background on Mac, Windows, iOS and Android 📠
- Easily See Meeting Participants with Their Hand Raised 👆
- Participant view sharing - see the participants' view of what you’re sharing from the controls at the top of your screen 👀
- Secure Lobby Support for Video System and Webex Teams External User 🏨
- Easy Access to End-to-End Encryption Session 👮♂️
- Meetings update to AES-256-GCM Cipher Suite and Mobile apps 🚨
- Default grid views now available for iOS and Android devices (phones and tablets) 🎉
- Alexa and Amazon Echo Recording Playback for Android 📼
Cisco Webex Calling and Webex Work are expanding
The Webex Callingis now available in Iceland and the following LATAM countries: Argentina, Bolivia, Dominican Republic, Ecuador, El Salvador, Guatemala, Honduras, Nicaragua, Paraguay, and Uruguay. 🆕🌎
Webex Work is now available in the following LATAM countries: Argentina, Bolivia, Bulgaria, Chile, Colombia, Costa Rica, Dominican Republic, Ecuador, El Salvador, Guatemala, Honduras, Mexico, Nicaragua, Panama, Paraguay, Peru, Puerto Rico, and Uruguay. Brazil is targeted in Q1 FY21. ✅👍
For more about Webex Callingand Webex Work!👊 Do subscribe our blog and stay tuned !!!