Open Source Billing

This commit is contained in:
Deon George
2013-10-10 13:44:53 +11:00
commit b02d70adf0
2344 changed files with 392978 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class will take care of ADSL Traffic.
*
* @package ADSL
* @category Service
* @author Deon George
* @copyright (c) 2009-2013 Open Source Billing
* @license http://dev.osbill.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 = Kohana::classname(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() {
if (Minion_CLI::options('verbose'))
echo ' - Last: '.date('Y-m-d',strtotime($this->last_update().'+1 day'))."\n";
$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'))) {
if (Minion_CLI::options('verbose'))
echo " - Date: $querydate\n";
$goodfetch = false;
// @todo log this fetch in a "log"
// Supplier specific output
// Data returned should be in MB's
$data = $this->getdata($querydate);
if (Minion_CLI::options('verbose'))
print_r($data);
if (! $this->fetchresult) {
echo 'Bad fetch'.get_class($this);
break;
}
$traffic = ORM::factory('Service_Plugin_Adsl_Traffic');
foreach ($data as $item) {
$traffic->values($item,array_keys($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() {
$date = strtotime('last month');
// @todo need a way to find out services that have traffic charges dynamically.
foreach ($this->so->services() as $so) {
if ($charge = $so->plugin()->traffic_lastmonth_exceed(FALSE,$date)) {
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->plugin()->service_number),
sprintf('Allowance==%s',$details['allowance']),
sprintf('Metric==%s',$metric),
sprintf('Used==%s',$details['used']),
sprintf('Month==%s',date('Y-m',$date)),
));
$co->check();
$co->save();
}
}
}
}
public function alert_traffic() {
$et = Email_Template::instance('adsl_traffic_notice');
foreach ($this->so->services() as $so) {
if (! $so->plugin()->report_traffic())
continue;
// Get our variable data
$et->to = array('account'=>array($so->account_id));
$et->variables = $so->plugin()->template_variables($et->variables());
$et->send();
}
}
}
?>

View File

@@ -0,0 +1,186 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* 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 ADSL
* @category Service
* @author Deon George
* @copyright (c) 2009-2013 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 $result = 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::$result[$date]))
return Service_Traffic_Adsl_Exetelhspa::$result[$date];
include_once 'includes/kohana/modules/simplehtmldom/classes/simple_html_dom.php';
// Find our services that need to be collected this way.
$update = array();
foreach ($this->so->services() as $so) {
if (Minion_CLI::options('verbose'))
echo " = Service: ".$so->name()."\n";
if ($so->plugin()->service_stats_collect AND $so->plugin()->service_stats_lastupdate < $date) {
// Start Session
$request = Request::factory($this->so->stats_url)
->method('POST')
->post($this->login_user_field,$so->plugin()->service_username)
->post($this->login_pass_field,$so->plugin()->service_password)
->post('doLogin',1)
->post('submit','Login');
$request->client()->options($this->curlopts+array(
CURLOPT_COOKIEJAR=>sprintf('/tmp/usage.cookies.%s.txt',$so->plugin()->service_number),
));
$response = $request->execute();
$data = $response->body();
if (! $data) {
// @todo Log into a log file
printf('Bad fetch for %s [%s]',$so->plugin()->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->plugin()->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')))) {
#print_r(array('sn'=>$so->plugin()->service_number,'sd'=>$servicedate));
$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'));
$html = new simple_html_dom();
$notdebug = TRUE;
if ($notdebug) {
$request = Request::factory($this->so->stats_url.'usage_customize_query.php')
->method('POST')
->post('year_search_key',date('Y',strtotime($servicedate)))
->post('month_search_key',date('m',strtotime($servicedate)))
->post('start_day_search_key',date('d',strtotime($servicedate)))
->post('end_day_search_key',date('d',strtotime($lastday)))
->post('do_usage_search',1);
$request->client()->options($this->curlopts+array(
CURLOPT_COOKIEFILE=>sprintf('/tmp/usage.cookies.%s.txt',$so->plugin()->service_number),
));
$response = $request->execute();
$result = $response->body();
$html->load($result);
#$html->save(sprintf('/afs/local/tmp/usage.%s.%s.html',$so->plugin()->service_number,$servicedate)); die();
} else {
$html->load_file(sprintf('/afs/local/tmp/usage.%s.%s.html',$so->plugin()->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('table',0)->find('tr')->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;
case 'Total': 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";
}
}
#print_r($data);
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->plugin()->service_number][$sdate]))
foreach ($data as $key => $value)
$update[$so->plugin()->service_number][$sdate][$key] += $value;
else
$update[$so->plugin()->service_number][$sdate] = $data;
$update[$so->plugin()->service_number][$sdate]['service'] = $so->plugin()->service_number;
$update[$so->plugin()->service_number][$sdate]['date'] = $sdate;
}
}
}
}
// If we got here and have data, we had a good fetch, update the stats date
$so->plugin()->service_stats_lastupdate = $lastday;
$so->plugin()->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::$result[$sdate][$service] = $details;
// If the date we want is empty, return an array
if (empty(Service_Traffic_Adsl_Exetelhspa::$result[$date]))
return array();
// Return the date we asked for
return Service_Traffic_Adsl_Exetelhspa::$result[$date];
}
}
?>

View File

@@ -0,0 +1,179 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is able to collect traffic information for Exetel PE
*
* Traffic information is collected by each service, and cached,
* returning just the date in question.
*
* @package ADSL
* @category Service
* @author Deon George
* @copyright (c) 2009-2013 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Service_Traffic_Adsl_Exetelpe extends Service_Traffic_Adsl {
private $login_user_field = 'login_name';
private $login_pass_field = 'password';
private $date_field = 'date';
static $result = array();
/**
* Get the data for Exetel PE 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_Exetelpe::$result[$date]))
return Service_Traffic_Adsl_Exetelpe::$result[$date];
include_once 'includes/kohana/modules/simplehtmldom/classes/simple_html_dom.php';
// Find our services that need to be collected this way.
$update = array();
foreach ($this->so->services() as $so) {
if ($so->plugin()->service_stats_collect AND $so->plugin()->service_stats_lastupdate < $date) {
// Start Session
$request = Request::factory($this->so->stats_url)
->method('POST')
->post($this->login_user_field,$so->plugin()->service_username == NULL ? '' : $so->plugin()->service_username)
->post($this->login_pass_field,$so->plugin()->service_password == NULL ? '' : $so->plugin()->service_password)
->post('doLogin',1)
->post('submit','Login');
$request->client()->options($this->curlopts+array(
CURLOPT_COOKIEJAR=>sprintf('/tmp/usage.cookies.%s.txt',$so->plugin()->service_number),
));
$response = $request->execute();
$data = $response->body();
if (! $data) {
// @todo Log into a log file
printf('Bad fetch for %s [%s]',$so->plugin()->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->plugin()->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'));
$html = new simple_html_dom();
$notdebug = TRUE;
if ($notdebug) {
$request = Request::factory($this->so->stats_url.'usage_customize_query.php')
->method('POST')
->post('year_search_key',date('Y',strtotime($servicedate)))
->post('month_search_key',date('m',strtotime($servicedate)))
->post('start_day_search_key',date('d',strtotime($servicedate)))
->post('end_day_search_key',date('d',strtotime($lastday)))
->post('do_usage_search',1);
$request->client()->options($this->curlopts+array(
CURLOPT_COOKIEFILE=>sprintf('/tmp/usage.cookies.%s.txt',$so->plugin()->service_number),
));
$response = $request->execute();
$result = $response->body();
$html->load($result);
#$html->save(sprintf('/afs/local/tmp/usage.%s.%s.html',$so->plugin()->service_number,$servicedate));
} else {
$html->load_file(sprintf('/afs/local/tmp/usage.%s.%s.html',$so->plugin()->service_number,$servicedate));
}
$header = array();
$data = array();
foreach ($html->find('td') as $index => $fieldset) {
if (! preg_match('/Usage Detail/',$fieldset->plaintext))
continue;
foreach ($fieldset->find('table',0)->find('tr',0)->find('td',0)->find('table',0)->find('tr') as $key => $values) {
foreach ($values->children() as $a => $b) {
#print_r(array('a'=>$a,'b'=>$b->plaintext));
# 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(str_replace('/','-',$data['date'])));
unset($data['date']);
if (isset($update[$so->plugin()->service_number][$sdate]))
foreach ($data as $key => $value)
$update[$so->plugin()->service_number][$sdate][$key] += $value;
else
$update[$so->plugin()->service_number][$sdate] = $data;
$update[$so->plugin()->service_number][$sdate]['service'] = $so->plugin()->service_number;
$update[$so->plugin()->service_number][$sdate]['date'] = $sdate;
}
}
}
}
// If we got here and have data, we had a good fetch, update the stats date
$so->plugin()->service_stats_lastupdate = $lastday;
$so->plugin()->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_Exetelpe::$result[$sdate][$service] = $details;
// If the date we want is empty, return an array
if (empty(Service_Traffic_Adsl_Exetelpe::$result[$date]))
return array();
// Return the date we asked for
return Service_Traffic_Adsl_Exetelpe::$result[$date];
}
}
?>

View File

@@ -0,0 +1,67 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is able to collect traffic information for Exetel VISP
*
* @package ADSL
* @category Service
* @author Deon George
* @copyright (c) 2009-2013 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) {
$result = array();
// Assume we have a bad fetch, unless otherwise specified.
$this->fetchresult = FALSE;
$request = Request::factory($this->so->stats_url)
->method('POST')
->post($this->login_user_field,$this->so->stats_username)
->post($this->login_pass_field,$this->so->stats_password)
->post($this->date_field,$date);
$request->client()->options($this->curlopts+array(
CURLOPT_POST => TRUE,
));
$response = $request->execute();
$data = $response->body();
$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($result,$attrs);
}
return $result;
}
}
?>

View File

@@ -0,0 +1,61 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class is able to collect traffic information for People Agent
*
* @package ADSL
* @category Service
* @author Deon George
* @copyright (c) 2009-2013 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;
$result = 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($result,$attrs);
}
return $result;
}
}
?>

View File

@@ -0,0 +1,123 @@
<?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 ADSL
* @category Service
* @author Deon George
* @copyright (c) 2009-2013 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 $result = 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::$result[$date]))
return Service_Traffic_ADSL_iiNetADSL::$result[$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);
}
$result = 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::$result[$period['period']][$so->service_adsl->service_username] = $attrs;
Service_Traffic_ADSL_iiNetADSL::$result[$period['period']][$so->service_adsl->service_username]['date'] = $period['period'];
Service_Traffic_ADSL_iiNetADSL::$result[$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::$result[$date]))
return array();
// Return the date we asked for
return Service_Traffic_ADSL_iiNetADSL::$result[$date];
}
}
?>