OSB enhancements to date

This commit is contained in:
Deon George
2010-11-30 09:41:08 +11:00
parent 8715a2059b
commit ec6a542bc3
478 changed files with 23423 additions and 9309 deletions

View File

@@ -0,0 +1,425 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides OSB service admin capabilities.
*
* @package OSB
* @subpackage Service
* @category Controllers/Admin
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Controller_Admin_Service extends Controller_TemplateDefault {
protected $control = array('Services'=>'services');
public $secure_actions = array(
'listbycheckout'=>TRUE,
'listadslservices'=>TRUE,
'listhspaservices'=>TRUE,
);
/**
* List all services by their default checkout method
*/
public function action_listbycheckout() {
// @todo need to add the DB prefix here
$services = DB::query(Database::SELECT,'
SELECT c.id AS cid,c.name as checkout_plugin_name,s.id AS sid,a.company,a.first_name,a.last_name,a.id as aid
FROM ab_service s LEFT JOIN ab_account_billing ab ON (s.account_billing_id=ab.id) LEFT JOIN ab_checkout c ON (ab.checkout_plugin_id=c.id),ab_account a, ab_account_group ag
WHERE s.active=1 AND s.price > 0 AND s.account_id=a.id AND a.id=ag.account_id AND ((s.account_billing_id IS NOT NULL AND ag.group_id IS NOT NULL) OR (a.id=ag.account_id and ag.group_id=1003))
ORDER BY c.id,s.recur_schedule,c.name,a.company,a.last_name,a.first_name
')
->execute();
// @todo If no items, show a nice message. This is not correct for ORM.
if (! count($services)) {
echo Kohana::debug('No services with account_billing');
die();
}
$last_checkout = '';
$last_account = '';
$i = 0;
$sc = $st = 0;
$output = '<table class="box-left">';
foreach ($services as $service) {
$so = ORM::factory('service',$service['sid']);
$si = $so->account_id.$so->recur_schedule;
if (($si != $last_account) AND $last_account) {
if ($sc > 1)
$output .= View::factory('service/list/bycheckout_subtotal')
->set('subtotal',Currency::display($st))
->set('i',$i++%2);
$sc = $st = 0;
}
if (($service['cid'] != $last_checkout) OR (! is_null($last_checkout) AND ! $last_checkout)) {
$output .= View::factory('service/list/bycheckout_header')
->set('checkout_name',$service['checkout_plugin_name'])
->set('last_checkout',$last_checkout);
}
$last_checkout = $service['cid'];
$last_account = $si;
// @todo This rounding should be a system default
$st += round($so->price+$so->tax(),2);
$sc++;
$output .= View::factory('service/list/bycheckout_body')
->set('service',$so)
->set('i',$i++%2);
}
// Last subtotal
if ($sc > 1)
$output .= View::factory('service/list/bycheckout_subtotal')
->set('subtotal',$st)
->set('i',$i++%2);
$output .= '</table>';
Block::add(array(
'title'=>_('List all Services by Default Payment Method'),
'body'=>$output,
));
Style::add(array(
'type'=>'file',
'data'=>'css/list.css',
));
$this->template->content = Block::factory();
}
//@todo this should really be in a different class, since adsl wont be part of the main app
public function action_listadslservices() {
// @todo need to add the DB prefix here
$services = DB::query(Database::SELECT,'
SELECT A.service_id
FROM ab_service__adsl A,ab_service B,ab_account C,ab_service D,ab_product E
WHERE B.active=1 AND A.service_id=B.id AND A.site_id=B.site_id
AND B.account_id=C.id AND B.site_id=C.site_id
AND A.service_id=D.id AND A.site_id=D.site_id
AND D.product_id=E.id AND D.site_id=E.site_id
AND E.sku like "%ADSL%"
ORDER BY C.last_name,B.account_id,A.service_number
')
->execute();
// @todo If no items, show a nice message. This is not correct for ORM.
if (! count($services)) {
echo Kohana::debug('No services for ADSL');
die();
}
$last_account = '';
$i = 0;
$output = '<table class="box-left">';
foreach ($services as $service) {
$so = ORM::factory('service',$service['service_id']);
if ($last_account != $so->account_id) {
if ($i)
$output .= '<tr><td colspan="10">&nbsp;</td></tr>';
$output .= View::factory('service/list/adslservices_header')
->set('service',$so);
$last_account = $so->account_id;
}
$output .= View::factory('service/list/adslservices_body')
->set('service',$so)
->set('i',$i++%2);
}
$output .= '</table>';
// Chart the traffic for the last 12 months.
// @todo need to add the DB prefix here
$traffic = DB::query(Database::SELECT,sprintf('
SELECT DATE_FORMAT(DATE,"%%y-%%m") AS MONTH,SID,MAX(NUM) AS NUM,SUM(DOWN_PEAK) AS DOWN_PEAK,SUM(IFNULL(DOWN_OFFPEAK,0)+IFNULL(PEER,0)+IFNULL(INTERNAL,0)) AS DOWN_OFFPEAK
FROM ab_view_traffic_adsl_daily
WHERE SID in (%s) AND DATE>"%s"
GROUP BY DATE_FORMAT(DATE,"%%Y-%%m"),SID
','1,2',date('Y-m',time()-365*86400)))
->execute();
$peak = $offpeak = $services = array();
foreach ($traffic as $a => $v) {
$peak[$v['SID']]['Peak'][$v['MONTH']] = $v['DOWN_PEAK'];
$peak[$v['SID']]['OffPeak'][$v['MONTH']] = $v['DOWN_OFFPEAK'];
$peak[$v['SID']]['Services'][$v['MONTH']] = $v['NUM'];
}
$google = GoogleChart::factory('vertical_bar');
$google->title = sprintf('ADSL traffic as at %s',date('Y-m-d',strtotime('yesterday')));
$google->series(array(
'title'=>array('Exetel-Peak','Exetel-Offpeak'),
'axis'=>'x',
'data'=>array('Exetel-Peak'=>$peak[1]['Peak'],'Exetel-OffPeak'=>$peak[1]['OffPeak'])));
$google->series(array(
'title'=>array('People-Peak','People-Offpeak'),
'axis'=>'x',
'data'=>array('People-Peak'=>$peak[2]['Peak'],'People-OffPeak'=>$peak[2]['OffPeak'])));
$google->series(array(
'title'=>'Exetel-Services',
'axis'=>'r',
'data'=>array('Exetel-Services'=>$peak[1]['Services'])));
$google->series(array(
'title'=>'People-Services',
'axis'=>'r',
'data'=>array('People-Services'=>$peak[2]['Services'])));
Block::add(array(
'body'=>$google,
));
Block::add(array(
'title'=>_('List all ADSL Services'),
'body'=>$output,
));
Style::add(array(
'type'=>'file',
'data'=>'css/list.css',
));
$this->template->content = Block::factory();
}
public function action_listhspaservices() {
// @todo need to add the DB prefix here
$services = DB::query(Database::SELECT,'
SELECT A.service_id
FROM ab_service__adsl A,ab_service B,ab_account C,ab_service D,ab_product E
WHERE B.active=1 AND A.service_id=B.id AND A.site_id=B.site_id
AND B.account_id=C.id AND B.site_id=C.site_id
AND A.service_id=D.id AND A.site_id=D.site_id
AND D.product_id=E.id AND D.site_id=E.site_id
AND E.sku like "%HSPA%"
ORDER BY C.last_name,B.account_id,A.service_number
')
->execute();
// @todo If no items, show a nice message. This is not correct for ORM.
if (! count($services)) {
echo Kohana::debug('No services for HSPA');
die();
}
$last_account = '';
$i = 0;
$output = '<table class="box-left">';
foreach ($services as $service) {
$so = ORM::factory('service',$service['service_id']);
if ($last_account != $so->account_id) {
if ($i)
$output .= '<tr><td colspan="10">&nbsp;</td></tr>';
$output .= View::factory('service/list/adslservices_header')
->set('service',$so);
$last_account = $so->account_id;
}
$output .= View::factory('service/list/adslservices_body')
->set('service',$so)
->set('i',$i++%2);
}
$output .= '</table>';
// Chart the traffic for the last 12 months.
// @todo need to add the DB prefix here
$traffic = DB::query(Database::SELECT,sprintf('
SELECT DATE_FORMAT(DATE,"%%y-%%m") AS MONTH,SID,MAX(NUM) AS NUM,SUM(DOWN_PEAK)*1000 AS DOWN_PEAK,SUM(IFNULL(DOWN_OFFPEAK,0)+IFNULL(PEER,0)+IFNULL(INTERNAL,0))*1000 AS DOWN_OFFPEAK
FROM ab_view_traffic_adsl_daily
WHERE SID=%s AND DATE>"%s"
GROUP BY DATE_FORMAT(DATE,"%%Y-%%m"),SID
',3,date('Y-m',time()-365*86400)))
->execute();
$peak = $offpeak = $services = array();
foreach ($traffic as $a => $v) {
$peak['Peak'][$v['MONTH']] = $v['DOWN_PEAK'];
$peak['OffPeak'][$v['MONTH']] = $v['DOWN_OFFPEAK'];
$peak['Services'][$v['MONTH']] = $v['NUM'];
}
$google = GoogleChart::factory('vertical_bar');
$google->title = sprintf('HSPA traffic as at %s',date('Y-m-d',strtotime('yesterday')));
$google->series(array('title'=>array('Peak','Offpeak'),'axis'=>'x','data'=>array('Peak'=>$peak['Peak'],'OffPeak'=>$peak['OffPeak'])));
$google->series(array('title'=>'Services','axis'=>'r','data'=>array('Services'=>$peak['Services'])));
Block::add(array(
'body'=>$google,
));
Block::add(array(
'title'=>_('List all HSPA Services'),
'body'=>$output,
));
Style::add(array(
'type'=>'file',
'data'=>'css/list.css',
));
$this->template->content = Block::factory();
}
/**
* Reconcile billing for an ADSL supplier
*
* @todo this should really be in a different class, since adsl wont be part of the main app
*/
public function action_listadslbilling($id) {
$aso = ORM::factory('adsl_supplier',$id);
// Process upload
// @todo This should be separated out by supplier in case each supplier has a different format
$files = Validate::factory($_FILES);
$files->rules('csv',array(
'Upload::valid'=>array(),
'Upload::not_empty'=>array(),
'Upload::type'=>array('Upload::type' => array('csv')),
'Upload::size'=>array('10M'))
);
if ($files->check()) {
foreach ($files as $file) {
$csv = $this->process($file);
}
}
// @todo add a display if there are no items
$i = $j = 0;
$total = 0;
$summary = '';
$output = View::factory('service/list/adslbilling_head');
$output .= '<table class="box-left">';
foreach ($aso->services(TRUE) as $so) {
// Reset our uploaded data
$uploaded = array();
// If our uploaded file has some cost data.
if (! empty($csv[$so->service_adsl->service_number])) {
$uploaded['amount'] =
(empty($csv[$so->service_adsl->service_number]['cost']) ? 0 : $csv[$so->service_adsl->service_number]['cost']) +
(empty($csv[$so->service_adsl->service_number]['credit']) ? 0 : $csv[$so->service_adsl->service_number]['credit']);
// Record the the exception if the cost is not expected
if (round($so->service_adsl->adsl_plan->adsl_supplier_plan->base_cost+$so->service_adsl->adsl_plan->adsl_supplier_plan->tax(),2) != $uploaded['amount']) {
$summary .= View::factory('service/list/adslbilling_summary')
->set('service',$so)
->set('amount',$uploaded['amount'])
->set('i',$j++%2);
$uploaded['checked'] = '';
} else {
$uploaded['checked'] = 'checked="checked"';
}
unset($csv[$so->service_adsl->service_number]);
} else {
$uploaded['checked'] = '';
$uploaded['amount'] = 0;
}
$total += $uploaded['amount'];
$output .= View::factory('service/list/adslbilling_body')
->set('service',$so)
->set('checked',$uploaded['checked'])
->set('amount',$uploaded['amount'])
->set('adsl',$so->service_adsl)
->set('i',$i++%2);
}
$output .= View::factory('service/list/adslbilling_foot')
->set('total',$total);
$output .= '</table>';
// Summary Report of remaining CSV items.
if (! empty($csv))
foreach ($csv as $service => $item) {
$summary .= View::factory('service/list/adslbilling_summary_exception')
->set('service',$service)
->set('item',$item)
->set('i',$j++%2);
}
$output .= Form::open(NULL,array('enctype'=>'multipart/form-data'));
$output .= '<div>';
$output .= Form::file('csv');
$output .= Form::submit('submit','upload');
$output .= '</div>';
$output .= Form::close();
Block::add(array(
'title'=>_('ADSL Services'),
'body'=>$output,
));
if ($summary)
Block::add(array(
'title'=>_('Exception Charges'),
'body'=>'<table class="box-left">'.$summary.'</table>',
));
Style::add(array(
'type'=>'file',
'data'=>'css/list.css',
));
$this->template->content = Block::factory();
}
private function process(array $file) {
$data = file_get_contents($file['tmp_name']);
if (! $data)
return;
$start = $end = FALSE;
$return = array();
foreach (preg_split("/\n/",$data) as $line) {
// Items start after "Item ID"
if (! $start && preg_match('/^Item ID,/',$line)) {
$start = true;
continue;
// Items end after "Subtotal"
} elseif ($start && ! $end && preg_match('/^Subtotal:,/',$line)) {
$end = true;
continue;
// If we havent started or not ended, continue
} elseif (! $start || $end) {
continue;
}
list($id,$ref,$unknown,$linedata,$q,$cost,$total) = explode(',',$line);
// Extract the phone number from the $linedata
@list($service,$description) = explode(':',(preg_replace('/([0-9]+)\s+-\s+(.*)$/',"$1:$2",$linedata)));
// If the description says Monthly Charge, we know its the monthly fee.
if (preg_match('/^Monthly Charge/',$description))
$return[$service]['cost'] = preg_replace('/\$/','',$total);
// If the description says VISP credit, we know this is commission.
elseif (preg_match('/^VISP Credit/',$description))
$return[$service]['credit'] = preg_replace('/\$/','',$total);
// If the description says Excess, we know this is commission.
elseif (preg_match('/^Excess usage/',$description))
$return[$service]['excess'] = preg_replace('/\$/','',$total);
else
$return[$service]['info'] = $line;
}
return $return;
}
}
?>

View File

@@ -0,0 +1,50 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides OSB service task capabilities.
*
* @package OSB
* @subpackage Service
* @category Controllers/Task
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Controller_Task_Service extends Controller_Template {
/**
* List all services by their default checkout method
*/
public function action_gettraffic() {
// @todo This things to collect traffic on needs to be configurable
foreach (array('ExetelVisp','ExetelHSPA','PeopleAgent','iiNetADSL') as $source) {
$traffic = Service_Traffic_ADSL::instance($source);
$traffic->update_traffic();
}
}
/**
* Charges for excess traffic usage
*/
public function action_chargetraffic() {
// @todo This things to collect traffic on needs to be configurable
foreach (array('ExetelVisp','ExetelHSPA','PeopleAgent','iiNetADSL') as $source) {
$traffic = Service_Traffic_ADSL::instance($source);
$traffic->charge_excess_traffic();
}
}
/**
* Send alerts to users when they exceed their traffic allowance
*/
public function action_alerttraffic() {
// @todo This things to collect traffic on needs to be configurable
foreach (array('ExetelVisp','ExetelHSPA','PeopleAgent','iiNetADSL') as $source) {
$traffic = Service_Traffic_ADSL::instance($source);
$traffic->alert_traffic();
}
}
}
?>

View File

@@ -0,0 +1,110 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides User Service functions
*
* @package OSB
* @subpackage Service
* @category Controllers/User
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Controller_User_Service extends Controller_TemplateDefault {
public $secure_actions = array(
'list'=>TRUE,
'view'=>TRUE,
);
// Our acccount object
private $ao;
public function before() {
parent::before();
$this->ao = ORM::factory('account',Auth::instance()->get_user()->id);
if (! $this->ao->loaded())
throw new Kohana_Exception('Account doesnt exist :account ?',array(':account'=>Auth::instance()->get_user()->id));
}
/**
* Show a product
*/
public function action_list() {
Block::add(array(
'title'=>sprintf('%s: %s - %s',_('Services For'),$this->ao->accnum(),$this->ao->name(TRUE)),
'body'=>View::factory('service/list')
->set('services',$this->ao->service->find_all()),
));
$this->template->content = Block::factory();
}
public function action_view($id) {
$so = ORM::factory('service',$id);
if (! $so->loaded() OR ! Auth::instance()->authorised($so->account_id)) {
$this->template->content = 'Unauthorised or doesnt exist?';
return FALSE;
}
$graph = $graph_data = $product_info = $product_detail = '';
// @todo Work this out dynamically
if ($so->product->prod_plugin AND in_array($so->product->prod_plugin_file,array('ADSL'))) {
$google = GoogleChart::factory('vertical_bar');
// If we came in via a post to show a particular month, then show that, otherwise show the yearly result
if ($_POST AND isset($_POST['month'])) {
$google->title = sprintf('DSL traffic usage for %s',$_POST['month']);
$traffic_data = $so->service_adsl->get_traffic_data_daily(strtotime($_POST['month'].'-01'));
foreach ($traffic_data as $k => $details)
$google->series(array(
'title'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)),
'axis'=>'x',
'data'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)=>$traffic_data[$k])));
foreach ($traffic_data as $k => $details)
$google->series(array(
'title'=>array((isset($friendly['cumulative'.$k]) ? $friendly['cumulative'.$k] : 'cumulative'.$k)),
'axis'=>'r',
'data'=>array((isset($friendly['cumulative'.$k]) ? $friendly['cumulative'.$k] : 'cumulative'.$k)=>$so->service_adsl->cumulative($traffic_data[$k]))));
$graph_data = View::factory('service/view_detail_adsl_traffic')
->set('traffic',$so->service_adsl->traffic_month(strtotime($_POST['month'].'-01'),FALSE));
} else {
// @todo Change the date to the last record date
$google->title = sprintf('Monthly DSL traffic usage as at %s',Config::date(strtotime('yesterday')));
$traffic_data = $so->service_adsl->get_traffic_data_monthly();
foreach ($traffic_data as $k => $details)
$google->series(array(
'title'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)),
'axis'=>'x',
'data'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)=>$traffic_data[$k])));
}
$graph = (string)$google;
$product_info = ADSL::instance()->product_view($so->service_adsl->adsl_plan_id,$so->price,$so->product->price_setup);
$product_detail = View::factory('service/view_detail_adsl')
->set('graph',$graph)
->set('graph_data',$graph_data)
->set('service',$so);
}
// @todo need to get the monthly price
Block::add(array(
'title'=>sprintf('%06s: %s',$so->id,$so->product->product_translate->find()->name),
'body'=>View::factory('service/view')
->set('service',$so)
->set('product_info',$product_info)
->set('product_detail',$product_detail),
));
$this->template->content = Block::factory();
}
}
?>

View File

@@ -0,0 +1,101 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class supports Services
*
* @package OSB
* @subpackage Service
* @category Models
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Model_Service extends ORMOSB {
// Relationships
protected $_has_many = array(
'invoice'=>array('through'=>'invoice_item'),
'adsl_plan'=>array('through'=>'service__adsl'),
);
protected $_has_one = array(
'service_adsl'=>array(),
);
protected $_belongs_to = array(
'product'=>array(),
'account'=>array(),
);
protected $_formats = array(
'active'=>array('StaticList_YesNo::display'=>array()),
'date_next_invoice'=>array('Config::date'=>array()),
'recur_schedule'=>array('StaticList_RecurSchedule::display'=>array()),
'price'=>array(
'Tax::add'=>array(),
'Currency::display'=>array(),
),
);
/**
* Display the service number
*/
public function svcnum() {
return sprintf('%05s',$this->id);
}
// Nothing to directly display on invoices for this module.
public function invoice_display() {
if ($this->sku)
return sprintf('%s: %s',_('Service'),$this->sku);
else
return '';
}
public function name() {
return $this->product->product_translate->find()->name;
}
/**
* Find invoices associated with this service
*/
public function invoices() {
$return = array();
foreach ($this->invoice->distinct('id')->find_all() as $invoice) {
$return[$invoice->id]['due'] = $invoice->due();
}
return $return;
}
/**
* Find invoices currently outstanding associated with this service
*/
public function invoices_due() {
$return = array();
foreach ($this->invoices() as $id => $invoice)
if ($invoice['due'])
array_push($return,$invoice);
return $return;
}
/**
* Calculate the total of invoices due for this service
*/
public function invoices_due_total() {
$total = 0;
foreach ($this->invoices_due() as $invoice)
$total += $invoice['due'];
return $total;
}
// @todo To implement
/**
* Calculate the tax for this item
*/
public function tax() {
return $this->price * .1;
}
}
?>

View File

@@ -0,0 +1,328 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class supports Services
*
* @package OSB
* @subpackage ADSL
* @category Models
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Model_Service_ADSL extends ORMOSB {
protected $_table_name = 'service__adsl';
protected $_updated_column = FALSE;
// Relationships
protected $_belongs_to = array(
'adsl_plan'=>array('foreign_key'=>'adsl_plan_id'),
'service'=>array(),
);
/**
* Return the IP Address for the service
*/
public function ipaddress() {
return $this->ipaddress ? $this->ipaddress : _('Dynamic');
}
public function contract_date_start() {
//@todo Use the system configured date format
return date('Y-m-d',$this->service_connect_date);
}
public function contract_date_end() {
//@todo Use the system configured date format
return date('Y-m-d',strtotime(sprintf('+%s months',$this->adsl_plan->contract_term),$this->service_connect_date));
}
/**
* This function will return the months that have traffic data.
* This array can be used in a select list to display the traffic for that month
*/
public function get_traffic_months() {
$keys = $months = array();
foreach ($this->get_traffic_data_monthly() as $metric => $data)
$keys = array_unique(array_merge($keys,array_keys($data)));
foreach ($keys as $v)
$months[$v] = $v;
arsort($months);
return $months;
}
/**
* Calculate the total traffic used in a month
*/
private function get_traffic_data_month($period=NULL) {
$return = array();
foreach ($this->get_traffic_data_daily($period,TRUE) as $tdata)
foreach ($tdata as $k => $v)
if (isset($return[$k]))
$return[$k] += $v;
else
$return[$k] = $v;
return $return;
}
/**
* Return an array of the data used in a month by day
*/
public function get_traffic_data_daily($period=NULL,$bydate=FALSE) {
$cacheable = TRUE;
if (is_null($period))
$period = strtotime('yesterday');
$cache = $this->service_id.date('M-Y',$period).$bydate;
// @todo This cache needs to be improved, so that we cache the query regardless of bydate setting
if ($cacheable AND $return = Cache::instance(Config::cachetype())->get($cache))
return $return;
$return = array();
$to = ORM::factory('service_adsl_traffic')
->where('service','=',$this->service_username)
->and_where('date','>=',date('Y-m-d',mktime(0,0,0,date('m',$period),1,date('Y',$period))))
->and_where('date','<=',date('Y-m-d',strtotime('last day of '.date('M Y',$period))));
foreach ($to->find_all() as $traffic) {
// Roll up the charges according to the configuration
$data = ADSL::allowance(array(
'base_down_peak'=>is_null($this->adsl_plan->base_down_peak) ? NULL : $traffic->down_peak,
'base_down_offpeak'=>is_null($this->adsl_plan->base_down_offpeak) ? NULL : $traffic->down_offpeak,
'base_up_peak'=>is_null($this->adsl_plan->base_up_peak) ? NULL : $traffic->up_peak,
'base_up_offpeak'=>is_null($this->adsl_plan->base_up_offpeak) ? NULL : $traffic->up_offpeak,
'extra_down_peak'=>$this->adsl_plan->extra_down_peak,
'extra_down_offpeak'=>$this->adsl_plan->extra_down_offpeak,
'extra_up_peak'=>$this->adsl_plan->extra_up_peak,
'extra_up_offpeak'=>$this->adsl_plan->extra_up_offpeak,
));
$day = date('d',strtotime($traffic->date));
if ($bydate)
$return[$day] = $data;
else
foreach ($data as $k => $v)
$return[$k][$day] = $v;
}
// Cache our data
// @todo Our cache time should be a configuration parameter
Cache::instance(Config::cachetype())->set($cache,$return,43200);
return $return;
}
/**
* Return an array of the data used in a year by month
*/
public function get_traffic_data_monthly($period=NULL,$bydate=FALSE) {
$cacheable = FALSE;
if (is_null($period))
$period = strtotime('yesterday');
$cache = $this->service_id.date('M-Y',$period).$bydate.__METHOD__;
// @todo This cache needs to be improved, so that we cache the query regardless of bydate setting
if ($cacheable AND $return = Cache::instance(Config::cachetype())->get($cache))
return $return;
$return = array();
$to = ORM::factory('service_adsl_traffic')
->select(
array('date_format(date,\'%y-%m\')','month'),
array('sum(up_peak)','up_peak'),
array('sum(up_offpeak)','up_offpeak'),
array('sum(down_peak)','down_peak'),
array('sum(down_offpeak)','down_offpeak')
)
->where('service','=',$this->service_username)
->and_where('date','>=',date('Y-m-d',mktime(0,0,0,date('m',$period),1,date('Y',$period)-1)))
->and_where('date','<=',date('Y-m-d',strtotime('last day of '.date('M Y',$period))))
->group_by('date_format(date,\'%Y-%m\')');
foreach ($to->find_all() as $traffic) {
// Roll up the charges according to the configuration
$data = ADSL::allowance(array(
'base_down_peak'=>is_null($this->adsl_plan->base_down_peak) ? NULL : $traffic->down_peak,
'base_down_offpeak'=>is_null($this->adsl_plan->base_down_offpeak) ? NULL : $traffic->down_offpeak,
'base_up_peak'=>is_null($this->adsl_plan->base_up_peak) ? NULL : $traffic->up_peak,
'base_up_offpeak'=>is_null($this->adsl_plan->base_up_offpeak) ? NULL : $traffic->up_offpeak,
'extra_down_peak'=>$this->adsl_plan->extra_down_peak,
'extra_down_offpeak'=>$this->adsl_plan->extra_down_offpeak,
'extra_up_peak'=>$this->adsl_plan->extra_up_peak,
'extra_up_offpeak'=>$this->adsl_plan->extra_up_offpeak,
));
if ($bydate)
$return[$traffic->month] = $data;
else
foreach ($data as $k => $v)
$return[$k][$traffic->month] = $v;
}
// Cache our data
// @todo Our cache time should be a configuration parameter
Cache::instance(Config::cachetype())->set($cache,$return,43200);
return $return;
}
public function traffic_month($month,$string=TRUE) {
return $string ? implode('/',$this->get_traffic_data_month($month)) :
$this->get_traffic_data_month($month);
}
public function traffic_lastmonth($string=TRUE) {
return $this->traffic_month(strtotime('last month'),$string);
}
public function traffic_thismonth($string=TRUE) {
return $this->traffic_month(strtotime('yesterday'),$string);
}
public function traffic_lastmonth_exceed($all=FALSE) {
$return = array();
foreach ($this->traffic_month(strtotime('last month'),FALSE) as $k => $v) {
// We shouldnt need to eval for nulls, since the traffic calc does that
if ($all OR ($v > $this->adsl_plan->$k)) {
$return[$k]['allowance'] = $this->adsl_plan->$k;
$return[$k]['used'] = $v;
$return[$k]['shaped'] = (! empty($this->adsl_plan->extra_shaped) AND $this->adsl_plan->extra_shaped AND $v > $this->adsl_plan->$k) ? TRUE : FALSE;
$return[$k]['excess'] = (! empty($this->adsl_plan->extra_charged) AND $this->adsl_plan->extra_charged AND $v > $this->adsl_plan->$k) ? $v-$this->adsl_plan->$k : 0;
$return[$k]['rate'] = $this->adsl_plan->{ADSL::map($k)};
$return[$k]['charge'] = ceil(($return[$k]['excess'])/1000)*$return[$k]['rate'];
}
}
return $return;
}
public function template_variables($array) {
$friendly = array(
'base_down_peak'=>'Peak',
'base_down_offpeak'=>'OffPeak',
'cumulative_base_down_peak'=>'Total Peak',
'cumulative_base_down_offpeak'=>'Total OffPeak',
);
$return = array();
$allowance = $this->adsl_plan->allowance(FALSE);
$period = strtotime('yesterday');
$traffic_data = $this->get_traffic_data_daily($period,FALSE);
$traffic = $this->get_traffic_data_month($period);
$traffic_type = $this->get_traffic_data_daily($period,TRUE);
$day = count($traffic_type) ? max(array_keys($traffic_type)) : 1;
$date = mktime(0,0,0,date('m',$period),$day,date('Y',$period));
$daysleft = date('d',strtotime('last day ',$date))-$day;
$google = GoogleChart::factory('vertical_bar');
$google->title = sprintf('DSL traffic usage as at %s',Config::date($date));
foreach ($traffic_data as $k => $details)
$google->series(array(
'title'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)),
'axis'=>'x',
'data'=>array((isset($friendly[$k]) ? $friendly[$k] : $k)=>$traffic_data[$k])));
// Work out comulative numbers
foreach ($traffic_data as $k => $details)
$google->series(array(
'title'=>array((isset($friendly['cumulative_'.$k]) ? $friendly['cumulative_'.$k] : 'cumulative_'.$k)),
'axis'=>'r',
'data'=>array((isset($friendly['cumulative_'.$k]) ? $friendly['cumulative_'.$k] : 'cumulative_'.$k)=>$this->cumulative($traffic_data['cumulative_'.$k]))));
foreach ($array as $item) {
switch ($item) {
case 'MONTH_GRAPH': $value = (string)$google; break;
case 'MONTH_TABLE': $value = $google->html_table(FALSE,array(
'table'=>'style="border: 1px solid #bebcb7; padding: 5px 5px; background: none repeat scroll 0% 0% #f8f7f5;"',
)); break;
case 'OFFPEAK_ALLOWANCE': $value = isset($allowance['base_down_offpeak']) ? $allowance['base_down_offpeak'].' MB' : '-'; break;
case 'OFFPEAK_USAGE': $value = isset($traffic['base_down_offpeak']) ? $traffic['base_down_offpeak'].' MB' : '-'; break;
case 'PEAK_ALLOWANCE': $value = isset($allowance['base_down_peak']) ? $allowance['base_down_peak'].' MB' : '-'; break;
case 'PEAK_USAGE': $value = isset($traffic['base_down_peak']) ? $traffic['base_down_peak'].' MB' : '-'; break;
case 'OFFPEAK_AVERAGE': $value = isset($traffic['base_down_offpeak']) ? round($traffic['base_down_offpeak']/$day,2).' MB' : '-'; break;
case 'OFFPEAK_AVERAGE_REMAIN': $value = ((isset($traffic['base_down_offpeak']) AND ($allowance['base_down_offpeak'] > $traffic['base_down_offpeak']) AND $daysleft) ? round(($allowance['base_down_offpeak']-$traffic['base_down_offpeak'])/$daysleft,2).' MB' : '-'); break;
case 'PEAK_AVERAGE': $value = isset($traffic['base_down_peak']) ? round($traffic['base_down_peak']/$day,2).' MB' : '-'; break;
case 'PEAK_AVERAGE_REMAIN': $value = ((isset($traffic['base_down_peak']) AND ($allowance['base_down_peak'] > $traffic['base_down_peak']) AND $daysleft) ? round(($allowance['base_down_peak']-$traffic['base_down_peak'])/$daysleft,2).' MB' : '-'); break;
case 'SERVICE_NUMBER': $value = $this->service_number; break;
case 'USAGE_DATE': $value = Config::date($date); break;
case 'USER_NAME': $value = $this->service->account->name(); break;
default:
$value = '';
}
$return[$item] = $value;
}
return $return;
}
/**
* This function will take an array of numbers and change it into a cumulative array
*/
public function cumulative($array) {
$result = array();
$s = 0;
foreach ($array as $k => $v)
$result[$k] = ($s += $v);
return $result;
}
/**
* Determine if we alert traffic
*
* We alert traffic if:
* + 80% of usage every 3 days
* + average daily usage > allowance every 5 days
* + last day of the period
*/
public function report_traffic() {
$allowance = $this->adsl_plan->allowance(FALSE);
$period = strtotime('yesterday');
$traffic_data = $this->get_traffic_data_daily($period,FALSE);
$traffic = $this->get_traffic_data_month($period);
$traffic_type = $this->get_traffic_data_daily($period,TRUE);
$day = count($traffic_type) ? max(array_keys($traffic_type)) : 1;
$lastday = date('d',strtotime('last day of',$period));
foreach ($traffic as $k => $v) {
// If we are the last day of the period
if ($day == $lastday AND $v)
return TRUE;
// If we are at 80% usage
if ($v/($allowance[$k] > 0 ? $allowance[$k] : 1) >= .8 AND $day%3 == 3)
return TRUE;
// If our average is greater than our allowance
if ($day%5 == 5 AND ($v/$day > $allowance[$k]/$day))
return TRUE;
}
// If we get here, then we dont need to report usage.
return FALSE;
}
}
?>

View File

@@ -0,0 +1,23 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class supports Services Traffic for ADSL
*
* @package OSB
* @subpackage Service
* @category Models
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Model_Service_ADSL_Traffic extends ORMOSB {
protected $_table_name = 'service__adsl_traffic';
protected $_primary_key = 'service';
protected $_callbacks = array(
'site_id'=>array('set_site_id'),
);
protected $_created_column = FALSE;
protected $_updated_column = FALSE;
}
?>

View File

@@ -0,0 +1,158 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class will take care of ADSL Traffic.
*
* @package OSB
* @subpackage Service
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Service_Traffic_ADSL {
protected $so;
protected $today;
protected $fetchresult = NULL;
protected $curlopts = array(
CURLOPT_CONNECTTIMEOUT => 60,
CURLOPT_FAILONERROR => TRUE,
CURLOPT_FOLLOWLOCATION => FALSE,
CURLOPT_HEADER => FALSE,
CURLOPT_HTTPPROXYTUNNEL => FALSE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYHOST => FALSE,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_VERBOSE => FALSE,
);
/**
* Setup this class. We need to get our supplier details out of the database.
*/
public function __construct() {
// Our DB record must be the suffix of this class name
$supplier = preg_replace('/^'.get_parent_class($this).'_/','',get_class($this));
$so = ORM::factory('adsl_supplier')
->where('name','=',$supplier)
->find();
if (! $so->loaded())
throw new Kohana_Exception('Supplier :supplier not defined in the database',array(':supplier'=>$supplier));
$this->so = $so;
$this->today = date('Y-m-d',strtotime('yesterday'));
}
/**
* Return an instance of this class
*
* @return HeadImage
*/
public static function instance($supplier) {
$sc = sprintf('%s_%s',get_called_class(),$supplier);
if (! class_exists($sc))
throw new Kohana_Exception('Class doesnt exist for :supplier',array(':supplier'=>$supplier));
else
return new $sc;
}
/**
* Get the last date we obtained the stats.
*/
private function last_update() {
return $this->so->stats_lastupdate;
}
/**
* Traffic data from supplier
*/
public function update_traffic() {
$alreadyrun = FALSE;
for ($querydate=date('Y-m-d',strtotime($this->last_update().'+1 day'));
$querydate<=$this->today;
$querydate=date('Y-m-d',strtotime($querydate.'+1 day'))) {
$goodfetch = false;
// @todo log this fetch in a "log"
// Supplier specific output
// Data returned should be in MB's
$data = $this->getdata($querydate);
if (! $this->fetchresult) {
echo 'Bad fetch'.get_class($this);
break;
}
$traffic = ORM::factory('service_adsl_traffic');
foreach ($data as $item) {
$traffic->values($item);
$traffic->supplier_id = $this->so->id;
if ($traffic->check())
$traffic->save();
if (! $traffic->saved())
throw new Kohana_Exception('Unable to save traffic record');
$traffic->clear();
}
}
$this->so->stats_lastupdate = $this->today;
$this->so->save();
}
public function charge_excess_traffic() {
// @todo need a way to find out services that have traffic charges dynamically.
foreach ($this->so->services() as $so) {
if ($charge = $so->service_adsl->traffic_lastmonth_exceed(FALSE)) {
foreach ($charge as $metric => $details) {
$co = ORM::factory('charge');
$co->status = 0;
$co->sweep_type = 6;
$co->account_id = $so->account_id;
$co->service_id = $so->id;
$co->amount = $details['rate'];
// @todo This needs to be calculated.
$co->taxable = TRUE;
$co->quantity = ceil($details['excess']/1000);
$co->description = _('Excess Traffic');
// @todo This need to be improved = strtotime function should be the one used in the function call
$co->attributes = implode("\n",array(
sprintf('ADSL Service==%s',$so->service_adsl->service_number),
sprintf('Allowance==%s',$details['allowance']),
sprintf('Metric==%s',$metric),
sprintf('Used==%s',$details['used']),
sprintf('Month==%s',date('Y-m',strtotime('last month'))),
));
$co->check();
$co->save();
}
print_r(array('s'=>$so->id,'a'=>$so->service_adsl->service_number,'al'=>$so->service_adsl->adsl_plan->allowance(FALSE),'charge'=>$charge));
}
}
}
public function alert_traffic() {
$et = EmailTemplate::instance('adsl_traffic_notice');
foreach ($this->so->services() as $so) {
if (! $so->service_adsl->report_traffic())
continue;
// Get our variable data
$et->to = array($so->account->email=>sprintf('%s %s',$so->account->first_name,$so->account->last_name));
$et->variables = $so->service_adsl->template_variables($et->variables());
$et->send();
}
}
}
?>

View File

@@ -0,0 +1,176 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
include_once 'includes/kohana/modules/simplehtmldom/classes/simple_html_dom.php';
/**
* This class is able to collect traffic information for Exetel HSPA
*
* Traffic information is collected by each service, and cached,
* returning just the date in question.
*
* @package OSB
* @subpackage Service
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Service_Traffic_ADSL_ExetelHSPA extends Service_Traffic_ADSL {
private $login_user_field = 'login_name';
private $login_pass_field = 'password';
private $date_field = 'date';
static $return = array();
/**
* Get the data for Exetel HSPA services
*
* @return array
*/
protected function getdata($date) {
// Assume we have a good fetch, unless otherwise specified.
$this->fetchresult = TRUE;
// If we have already collected the date data, return it.
if (! empty(Service_Traffic_ADSL_ExetelHSPA::$return[$date]))
return Service_Traffic_ADSL_ExetelHSPA::$return[$date];
// Find our services that need to be collected this way.
$update = array();
foreach ($this->so->services() as $so) {
if ($so->service_adsl->service_stats_collect AND $so->service_adsl->service_stats_lastupdate < $date) {
$postfields = http_build_query(array(
$this->login_user_field=>$so->service_adsl->service_username,
$this->login_pass_field=>$so->service_adsl->service_password,
'doLogin'=>1,
'submit'=>'Login',
));
// Start Session
Remote::clear();
$data = Remote::get($this->so->stats_url,
$this->curlopts+array(
CURLOPT_POSTFIELDS=>$postfields,
CURLOPT_COOKIEJAR=>sprintf('/tmp/usage.cookies.%s.txt',$so->service_adsl->service_number),
),
TRUE);
if (! $data) {
// @todo Log into a log file
printf('Bad fetch for %s [%s]',$so->service_adsl->service_number,$this->so->stats_lastupdate);
#$html = new simple_html_dom();
#$html->load($data);
#$html->save(sprintf('/afs/local/tmp/usage.%s.%s.login.html',$so->service_adsl->service_number,'login'));
continue;
}
for ($servicedate=date('Y-m-d',strtotime($this->so->stats_lastupdate.'+1 day'));
$servicedate <= $this->today;
$servicedate=date('Y-m-d',strtotime('+1 month',strtotime(date('Y-m',strtotime($servicedate)).'-01')))) {
$lastday = date('Y-m-d',strtotime('-1 second',strtotime('+1 month',strtotime(date('Y-m',strtotime($servicedate)).'-01'))));
if (strtotime($lastday) > time())
$lastday = date('Y-m-d',strtotime('yesterday'));
$postfields = http_build_query(array(
'year_search_key'=>date('Y',strtotime($servicedate)),
'month_search_key'=>date('m',strtotime($servicedate)),
'start_day_search_key'=>date('d',strtotime($servicedate)),
'end_day_search_key'=>date('d',strtotime($lastday)),
'do_usage_search'=>1,
));
$html = new simple_html_dom();
$notdebug = TRUE;
if ($notdebug) {
$result = Remote::get($this->so->stats_url.'usage_customize_query.php',$this->curlopts+array(CURLOPT_POSTFIELDS=>$postfields),TRUE);
$html->load($result);
$html->save(sprintf('/afs/local/tmp/usage.%s.%s.html',$so->service_adsl->service_number,$servicedate));
} else {
$html->load_file(sprintf('/tmp/usage.%s.%s.txt',$so->service_adsl->service_number,$servicedate));
}
$header = array();
$data = array();
foreach ($html->find('fieldset') as $index => $fieldset) {
if (! preg_match('/^Usage Detail/',$fieldset->find('legend',0)->plaintext))
continue;
#echo "X:";print_r($fieldset->find('legend',0)->plaintext); echo "\n";
foreach ($fieldset->find('table',0)->find('tr') as $key => $values) {
foreach ($values->children() as $a => $b) {
#print_r(array('a'=>$a,'b'=>$b));
# Header
if ($key == 0) {
switch ($b->plaintext) {
case 'Date': $header[$a] = 'date'; break;
case 'OffPeak Upload': $header[$a] = 'up_offpeak'; break;
case 'Peak Upload': $header[$a] = 'up_peak'; break;
case 'Upload': $header[$a] = 'up_peak'; break;
case 'OffPeak Download': $header[$a] = 'down_offpeak'; break;
case 'Peak Download': $header[$a] = 'down_peak'; break;
case 'Download': $header[$a] = 'down_peak'; break;
case 'Duration': break;
default:
printf('Unkown header :%s',$b->plaintext);
$this->fetchresult = FALSE;
continue;
}
#echo "INDEX: $key:$a\n";
#echo "TAG: ".$b->tag."\n";
#echo "HEADER: ".$b->plaintext."\n";
# Data
} else {
if (isset($header[$a]))
$data[$header[$a]] = $b->plaintext;
#echo "INDEX: $key:$a\n";
#echo "TAG: ".$b->tag."\n";
#echo "VALUES: ".$b->plaintext."\n";
}
}
if (isset($data['date']) && preg_match('/^[0-9]{4}/',$data['date'])) {
$sdate = date('Y-m-d',strtotime($data['date']));
unset($data['date']);
if (isset($update[$so->service_adsl->service_number][$sdate]))
foreach ($data as $key => $value)
$update[$so->service_adsl->service_number][$sdate][$key] += $value;
else
$update[$so->service_adsl->service_number][$sdate] = $data;
$update[$so->service_adsl->service_number][$sdate]['service'] = $so->service_adsl->service_number;
$update[$so->service_adsl->service_number][$sdate]['date'] = $sdate;
}
}
}
}
// If we got here and have data, we had a good fetch, update the stats date
$so->service_adsl->service_stats_lastupdate = $lastday;
$so->service_adsl->save();
}
}
// If there are no updates, return an empty array
if (! $update)
return array();
// Reformat the data into date order.
foreach ($update as $service => $sdata)
foreach ($sdata as $sdate => $details)
Service_Traffic_ADSL_ExetelHSPA::$return[$sdate][$service] = $details;
// If the date we want is empty, return an array
if (empty(Service_Traffic_ADSL_ExetelHSPA::$return[$date]))
return array();
// Return the date we asked for
return Service_Traffic_ADSL_ExetelHSPA::$return[$date];
}
}
?>

View File

@@ -0,0 +1,65 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is able to collect traffic information for Exetel VISP
*
* @package OSB
* @subpackage Service
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Service_Traffic_ADSL_ExetelVisp extends Service_Traffic_ADSL {
private $login_user_field = 'username';
private $login_pass_field = 'password';
private $date_field = 'date';
protected function getdata($date) {
// Assume we have a bad fetch, unless otherwise specified.
$this->fetchresult = FALSE;
$return = array();
$data = Remote::get($this->so->stats_url,$this->curlopts+array(
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => http_build_query(array(
$this->login_user_field=>$this->so->stats_username,
$this->login_pass_field=>$this->so->stats_password,
$this->date_field=>$date,
)
))
);
$resultarray = explode("\n",$data);
// The first field should be a header, so we can ignore it:
if (preg_match('/^Login/',$resultarray[0])) {
array_shift($resultarray);
$this->fetchresult = TRUE;
}
// If we got the expected data, we can parse it.
if ($this->fetchresult)
foreach ($resultarray as $details) {
if (! trim($details))
continue;
$valuesarray = explode(',',$details);
// Extel VISP stores data in MB's*100.
$attrs = array();
$attrs['service'] = $valuesarray[0];
$attrs['date'] = $valuesarray[1];
$attrs['up_peak'] = $valuesarray[2]/100;
$attrs['down_peak'] = $valuesarray[3]/100;
$attrs['up_offpeak'] = $valuesarray[4]/100;
$attrs['down_offpeak'] = $valuesarray[5]/100;
array_push($return,$attrs);
}
return $return;
}
}
?>

View File

@@ -0,0 +1,124 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is able to collect traffic information for iiNet ADSL
*
* Traffic information is collected by each service, and cached,
* returning just the date in question.
*
* @package OSB
* @subpackage Service
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Service_Traffic_ADSL_iiNetADSL extends Service_Traffic_ADSL {
private $login_user_field = 'username';
private $login_pass_field = 'password';
private $date_field = 'period';
static $return = array();
// The fields in the XML which are translated into database columns
private $fields = array(
'peak'=>'down_peak',
'offpeak'=>'down_offpeak',
'uploads'=>'up_peak',
'freezone'=>'internal',
);
/**
* Get the data for iiNet ADSL services
*
* @return array
*/
protected function getdata($date) {
// Assume we have a bad fetch, unless otherwise specified.
$this->fetchresult = FALSE;
// If we have already collected the date data, return it.
if (! empty(Service_Traffic_ADSL_iiNetADSL::$return[$date]))
return Service_Traffic_ADSL_iiNetADSL::$return[$date];
// Find our services that need to be collected this way.
$update = array();
foreach ($this->so->services() as $so) {
if ($so->service_adsl->service_stats_collect AND $so->service_adsl->service_stats_lastupdate < $date) {
$lastperiod = '';
for ($servicedate=date('Y-m-d',strtotime($this->so->stats_lastupdate.'+1 day'));
$servicedate <= $this->today;
$servicedate=date('Y-m-d',strtotime('+1 day',strtotime($servicedate)))) {
$debug = FALSE;
$debug_file = '/tmp/data';
// IINET gives us data a month at a time.
if ($lastperiod != date('Ym',strtotime($servicedate))) {
$lastperiod = date('Ym',strtotime($servicedate));
$postfields = http_build_query(array(
$this->login_user_field=>$so->service_adsl->service_username,
$this->login_pass_field=>$so->service_adsl->service_password,
'period'=>$lastperiod,
'usage_view'=>'month',
'action'=>'login',
));
if ($debug AND file_exists($debug_file))
$data = file_get_contents($debug_file);
else
$data = Remote::get($this->so->stats_url,$this->curlopts+array(CURLOPT_POSTFIELDS=>$postfields));
// @todo There exists a possibility to skip a month, if we get a bad fetch on a previous month.
if ($data)
$this->fetchresult = TRUE;
if ($debug AND ! file_exists($debug_file))
file_put_contents($debug_file,$data);
}
$return = array();
foreach (XML::factory(null,'ii_feed',$data)->volume_usage->volume_usage->get('day_hour') as $day_hour) {
$attrs = array();
$period = $day_hour->attributes();
// If we find a field we dont understand, we'll return.
if (empty($period['period']))
return array();
foreach ($day_hour->get('usage') as $usage) {
$fields = $usage->attributes();
// If we find a field we dont understand, we'll return.
if (empty($fields['type']) OR empty($this->fields[$fields['type']]))
return array();
// Traffic is in bytes, need to convert to MB
if (empty($attrs[$this->fields[$fields['type']]]))
$attrs[$this->fields[$fields['type']]] = $usage->value()/1000/1000;
else
$attrs[$this->fields[$fields['type']]] += $usage->value()/1000/1000;
}
Service_Traffic_ADSL_iiNetADSL::$return[$period['period']][$so->service_adsl->service_username] = $attrs;
Service_Traffic_ADSL_iiNetADSL::$return[$period['period']][$so->service_adsl->service_username]['date'] = $period['period'];
Service_Traffic_ADSL_iiNetADSL::$return[$period['period']][$so->service_adsl->service_username]['service'] = $so->service_adsl->service_username;
}
}
// If we got here and have data, we had a good fetch, update the stats date
$so->service_adsl->service_stats_lastupdate = $date;
$so->service_adsl->save();
}
}
// If the date we want is empty, return an array
if (empty(Service_Traffic_ADSL_iiNetADSL::$return[$date]))
return array();
// Return the date we asked for
return Service_Traffic_ADSL_iiNetADSL::$return[$date];
}
}
?>

View File

@@ -0,0 +1,62 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is able to collect traffic information for People Agent
*
* @package OSB
* @subpackage Service
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Service_Traffic_ADSL_PeopleAgent extends Service_Traffic_ADSL {
private $login_user_field = 'username';
private $login_pass_field = 'password';
private $date_field = 'date';
protected function getdata($date) {
// Assume we have a bad fetch, unless otherwise specified.
$this->fetchresult = FALSE;
$return = array();
$url_suffix = sprintf('traffic_V34_%s.xml',date('Ymd',strtotime($date)));
try {
$data = Remote::get($this->so->stats_url.$url_suffix,$this->curlopts+array(
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_USERPWD => sprintf('%s:%s',$this->so->stats_username,$this->so->stats_password),
));
}
catch (Exception $e) {
return;
}
$this->fetchresult = TRUE;
foreach (XML::factory(null,null,$data)->get('user') as $user) {
$attrs = array();
$userattrs = $user->attributes();
$attrs['service'] = $userattrs['username'];
$attrs['date'] = $date;
foreach ($user->year->month->day->get('hour') as $hour => $traffic) {
foreach (array('external'=>'down_peak','internal'=>'internal','peering'=>'peer') as $t => $k) {
$tatters = $traffic->$t->attributes();
// Traffic is in bytes, need to convert to MB
if (empty($attrs[$k]))
$attrs[$k] = $tatters['bytes']/1000/1000;
else
$attrs[$k] += $tatters['bytes']/1000/1000;
}
}
array_push($return,$attrs);
}
return $return;
}
}
?>