TRUE, 'adslstat'=>TRUE, 'listadslbilling'=>TRUE, 'listexpiring'=>TRUE, 'listdomainservicesbysupplier'=>TRUE, 'listdomainservicesbydnshost'=>TRUE, 'listhostservicesbysupplier'=>TRUE, 'listwebservices'=>TRUE, 'listinvoicesoon'=>TRUE, 'update'=>TRUE, 'view'=>TRUE, ); public function action_ajaxjson_traffic() { $result = array(); $svs = ORM::factory('Service')->list_bylistgroup('ADSL'); $data = $this->consoltraffic($svs,time()); $google = GoogleChart::factory('ComboChart') ->stacked(TRUE); foreach ($data['data'] as $key => $values) $google->sdata(array('yl'=>$key),array($key=>$values)); $google->sdata(array('yr'=>'services'),array('services'=>$data['svs'])); $this->response->headers('Content-Type','application/json'); $this->response->body($google->json()); } private function consoltraffic($svs,$date) { $data = array(); foreach ($svs as $so) { $c = array(); foreach ($so->plugin()->get_traffic_data_monthly($date) as $metric => $ma) { foreach ($ma as $month => $traffic) { // Only count the service once, not for each metric. if (! isset($c[$month])) { if (isset($data['svs'][$month])) $data['svs'][$month] += 1; else $data['svs'][$month] = 1; $c[$month] = 1; } if (isset($data['data'][$metric][$month])) $data['data'][$metric][$month] += (int)$traffic; else $data['data'][$metric][$month] = (int)$traffic; } } } ksort($data['svs']); foreach ($data['data'] as $metric => $details) ksort($data['data'][$metric]); return $data; } /** * Show a list of services that are expiring or have expired */ public function action_listexpiring() { $svs = ORM::factory('Service')->list_expiring(); Sort::MAsort($svs,'expire()'); Block::add(array( 'title'=>_('ADSL Services'), 'body'=>Table::display( $svs, 50, array( 'id'=>array('label'=>'ID','url'=>URL::link('user','service/view/')), 'service_name()'=>array('label'=>'Service'), 'expire(TRUE)'=>array('label'=>'Expires'), 'due(TRUE)'=>array('label'=>'Due'), ), array( 'type'=>'select', 'form'=>URL::link('user','service/view'), )), )); } public function action_listdomainservicesbysupplier() { $svs = ORM::factory('Service')->list_bylistgroup('DOMAIN'); Sort::MAsort($svs,'plugin()->domain_registrar_id,name()'); $list = array(); foreach ($svs as $so) $list[$so->plugin()->domain_registrar_id][] = $so; foreach (array_keys($list) as $sid) Block::add(array( 'title'=>sprintf(_('Domain Names by Supplier %s'),$sid), 'body'=>Table::display( $list[$sid], 25, array( 'id'=>array('label'=>'ID','url'=>URL::link('user','service/view/')), 'service_name()'=>array('label'=>'Details'), 'plugin()->display("domain_expire")'=>array('label'=>'Expire'), 'recur_schedule'=>array('label'=>'Billing'), 'price(TRUE,TRUE)'=>array('label'=>'Price','class'=>'right'), 'account->accnum()'=>array('label'=>'Cust ID'), 'account->name()'=>array('label'=>'Customer'), 'display("date_next_invoice")'=>array('label'=>'Next Invoice'), ), array( 'page'=>TRUE, 'type'=>'select', 'form'=>URL::link('user','service/view'), )), )); } public function action_listdomainservicesbydnshost() { $svs = ORM::factory('Service')->list_bylistgroup('DOMAIN'); Sort::MAsort($svs,'plugin()->service_plugin_host,name()'); $list = array(); foreach ($svs as $so) $list[$so->plugin()->service_plugin_host->host_server_id][] = $so; foreach (array_keys($list) as $sid) Block::add(array( 'title'=>sprintf(_('Domain Names by DNS Host [%s]'),$sid), 'body'=>Table::display( $list[$sid], 25, array( 'id'=>array('label'=>'ID','url'=>URL::link('user','service/view/')), 'service_name()'=>array('label'=>'Details'), 'plugin()->domain_registrar->id'=>array('label'=>'SID'), 'plugin()->domain_registrar->name'=>array('label'=>'Supplier'), 'display("date_next_invoice")'=>array('label'=>'Next Invoice'), ), array( 'page'=>TRUE, 'type'=>'select', 'form'=>URL::link('user','service/view'), )), )); } public function action_listhostservicesbysupplier() { $svs = ORM::factory('Service')->list_bylistgroup('HOST'); Sort::MAsort($svs,'plugin()->host_server,name()'); $list = array(); foreach ($svs as $so) $list[$so->plugin()->host_server_id][] = $so; foreach (array_keys($list) as $sid) Block::add(array( 'title'=>sprintf(_('Hosting by Supplier %s'),$sid), 'body'=>Table::display( $list[$sid], 25, array( 'id'=>array('label'=>'ID','url'=>URL::link('user','service/view/')), 'service_name()'=>array('label'=>'Details'), 'plugin()->display("host_expire")'=>array('label'=>'Expire'), 'recur_schedule'=>array('label'=>'Billing'), 'price(TRUE,TRUE)'=>array('label'=>'Price','class'=>'right'), 'account->accnum()'=>array('label'=>'Cust ID'), 'account->name()'=>array('label'=>'Customer'), 'display("date_next_invoice")'=>array('label'=>'Next Invoice'), ), array( 'page'=>TRUE, 'type'=>'select', 'form'=>URL::link('user','service/view'), )), )); } public function action_listwebservices() { $svs = ORM::factory('Service')->list_bylistgroup('WEB'); Sort::MAsort($svs,'name()'); Block::add(array( 'title'=>_('SSL Services'), 'body'=>Table::display( $svs, 25, array( 'id'=>array('label'=>'ID','url'=>URL::link('user','service/view/')), 'service_name()'=>array('label'=>'Details'), 'recur_schedule'=>array('label'=>'Billing'), 'price(TRUE,TRUE)'=>array('label'=>'Price','class'=>'right'), 'account->accnum()'=>array('label'=>'Cust ID'), 'account->name()'=>array('label'=>'Customer'), 'display("date_next_invoice")'=>array('label'=>'Next Invoice'), ), array( 'page'=>TRUE, 'type'=>'select', 'form'=>URL::link('user','service/view'), )), )); } /** * 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 = $this->request->param('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 if ($_FILES) { $files = Validation::factory($_FILES) ->rule('csv','Upload::valid') ->rule('csv','Upload::not_empty') ->rule('csv','Upload::type',array(':value',array('csv'))) ->rule('csv','Upload::size',array(':value','10M')); if ($files->check()) foreach ($files->data() as $file) $csv = $this->process($file); } // @todo add a display if there are no items $i = $j = 0; $total = 0; $summary = ''; $output = View::factory($this->viewpath().'/head'); $output .= ''; foreach ($aso->services(TRUE) as $so) { $po = $so->plugin()->product(); // Reset our uploaded data $uploaded = array(); $uploaded['excess'] = empty($csv[$so->plugin()->service_number]['excess']) ? 0 : $csv[$so->plugin()->service_number]['excess']; // If our uploaded file has some cost data. if (! empty($csv[$so->plugin()->service_number])) { $uploaded['amount'] = (empty($csv[$so->plugin()->service_number]['cost']) ? 0 : $csv[$so->plugin()->service_number]['cost']) + (empty($csv[$so->plugin()->service_number]['credit']) ? 0 : $csv[$so->plugin()->service_number]['credit']); // Record the the exception if the cost is not expected if (round($po->adsl_supplier_plan->base_cost+$po->adsl_supplier_plan->tax(),2) != $uploaded['amount']) { $summary .= View::factory($this->viewpath().'/summary') ->set('service',$so) ->set('plan',$po) ->set('planoverride',$so->plugin()->provided_adsl_plan_id ? TRUE : FALSE) ->set('amount',$uploaded['amount']) ->set('i',$j++%2); $uploaded['checked'] = ''; } else { $uploaded['checked'] = 'checked="checked"'; } unset($csv[$so->plugin()->service_number]); } else { $uploaded['checked'] = ''; $uploaded['amount'] = 0; } $total += $uploaded['amount']; $output .= View::factory($this->viewpath().'/body') ->set('service',$so) ->set('plan',$po) ->set('planoverride',$so->plugin()->provided_adsl_plan_id ? TRUE : FALSE) ->set('checked',$uploaded['checked']) ->set('amount',$uploaded['amount']) ->set('excess',$uploaded['excess']) ->set('adsl',$so->plugin()) ->set('i',$i++%2); } $output .= View::factory($this->viewpath().'/foot') ->set('total',$total); $output .= '
'; // Summary Report of remaining CSV items. if (! empty($csv)) foreach ($csv as $service => $item) { $summary .= View::factory($this->viewpath().'/summary_exception') ->set('service',$service) ->set('item',$item) ->set('i',$j++%2); } $output .= Form::open(NULL,array('enctype'=>'multipart/form-data')); $output .= '
'; $output .= Form::file('csv'); $output .= Form::submit('submit','upload',array('class'=>'form_button')); $output .= '
'; $output .= Form::close(); Block::add(array( 'title'=>_('ADSL Services'), 'body'=>$output, )); if ($summary) Block::add(array( 'title'=>_('Exception Charges'), 'body'=>''.$summary.'
', )); Style::add(array( 'type'=>'file', 'data'=>'css/list.css', )); } private function process(array $file) { $data = file_get_contents($file['tmp_name']); if (! $data) return; $start = $end = FALSE; $result = 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; } $record = explode(',',$line); // 1 = Item ID (ignore) // 2 = Reference ID (ignore - its not useful for us) // 3 = Category (always appears blank) // 4 = Item Description (has our service number, rental and excess charges description) // 0nnnnnnnnn - Monthly Internet Charge On Plan XXXXX For billing period (dd/mm/yyyy - dd/mm/yyyy) (7 FIELDED LINES) // 0nnnnnnnnn - Excess usage charges for March 2013 (8 FIELDED LINES) // 5 = Quantity // Always 1 for Plan Fees // 0nnnnnnnnn@graytech.net.au Excess Usage y GB (for excess charges) // 6 = Unit Price // Always 1 for Excess Usage (probably quantity) // 7 = Total Price // Unit price for Excess Usage // 8 = Total Price for Excess Usage if (! count($record) >= 7) throw Kohana_Exception('Format of CSV file changed? (:record)',array(':record'=>$record)); if (preg_match('/Monthly Internet Charge On Plan /',$record[3])) { list($service,$description) = explode(':',(preg_replace('/([0-9]+)\s+-\s+(.*)$/',"$1:$2",$record[3]))); $result[$service]['cost'] = str_replace('$','',$record[6]); } elseif (preg_match('/VISP Credit/',$record[3])) { list($service,$description) = explode(':',(preg_replace('/([0-9]+)\s+-\s+(.*)$/',"$1:$2",$record[3]))); $result[$service]['credit'] = str_replace('$','',$record[6]); } elseif (preg_match('/Excess usage charges for /',$record[3])) { list($service,$description) = explode(':',(preg_replace('/([0-9]+)\s+-\s+(.*)$/',"$1:$2",$record[3]))); $result[$service]['excess'] = str_replace('$','',$record[7]); // Ignore Payment For Invoice lines } elseif (preg_match('/Payment For Invoice:/',$record[3])) { } else { try { list($service,$description) = explode(':',(preg_replace('/([0-9]+)\s+-\s+(.*)$/',"$1:$2",$record[3]))); $result[$service]['info'] = $line; } catch (Exception $e) { $result['000']['info'] = $line; } } } return $result; } /** * List services that need to be invoiced. */ public function action_listinvoicesoon() { Block::add(array( 'title'=>_('Services to Invoice'), 'body'=>Table::display( ORM::factory('Service')->list_invoicesoon(ORM::factory('Invoice')->config('GEN_SOON_DAYS')), 25, array( 'id'=>array('label'=>'ID','url'=>URL::link('user','service/view/')), 'service_name()'=>array('label'=>'Details'), 'recur_schedule'=>array('label'=>'Billing'), 'date_next_invoice'=>array('label'=>'Next Invoice'), 'price(TRUE,TRUE)'=>array('label'=>'Price','class'=>'right'), 'charges()'=>array('label'=>'Charges','class'=>'right'), 'status'=>array('label'=>'Active'), 'account->accnum()'=>array('label'=>'Cust ID'), 'account->name()'=>array('label'=>'Customer'), ), array( 'page'=>TRUE, 'type'=>'select', 'form'=>URL::link('user','service/view'), )), )); } public function action_update() { $id = $this->request->param('id'); $so = ORM::factory('Service',$id); if (! $so->loaded()) HTTP::redirect('welcome/index'); if ($_POST) { if (isset($_POST['plugin']) AND $_POST['plugin']) if (! $so->plugin()->values($_POST['plugin'])->update()->saved()) throw new Kohana_Exception('Failed to save updates to plugin data for record :record',array(':record'=>$so->id())); if (! $so->values($_POST)->update()->saved()) throw new Kohana_Exception('Failed to save updates to service data for record :record',array(':record'=>$so->id())); } Block::add(array( 'title'=>sprintf('%s %s:%s',_('Update Service'),$so->id(),$so->name()), 'body'=>View::factory($this->viewpath()) ->set('so',$so) ->set('mediapath',Route::get('default/media')) ->set('plugin_form',$so->admin_update()), )); // @todo Investigate a better way of preparing for jscalendar Script::add(array( 'type'=>'file', 'data'=>'js/dhtml.calendar.js', )); Script::add(array( 'type'=>'file', 'data'=>'js/dhtml.calendar-setup.js', )); Script::add(array( 'type'=>'file', 'data'=>'js/dhtml.calendar-en.js', )); Script::add(array( 'type'=>'file', 'data'=>'js/dhtml.date_selector.js', )); Style::add(array( 'type'=>'file', 'data'=>'css/dhtml.calendar.css', )); } public function action_view() { list($id,$output) = Table::page(__METHOD__); $so = ORM::factory('Service',$id); if (! $so->loaded() OR ! Auth::instance()->authorised($so->account)) { $this->template->content = 'Unauthorised or doesnt exist?'; return FALSE; } $doutput = $loutput = ''; $loutput .= View::factory($this->viewpath()) ->set('so',$so); // Validate the transactions $bt = NULL; $save = (isset($_REQUEST['go']) && $_REQUEST['go']=1) ? 1 : 0; $xsid=197; foreach ($so->transactions()->where('item_type','=',0)->find_all() as $iio) { if (! $iio->invoice->status) continue; // @todo This hard coding of 3070 should be removed. if ($iio->service_id == $xsid AND $iio->invoice_id < 3070) continue; if ($iio->quantity < 0 OR $iio->price_base < 0) continue; if (in_array($iio->id,array(960))) continue; if ($iio->invoice_id > 4000 OR $iio->product->prod_plugin_file=="ADSL") $a = FALSE; else $a = TRUE; if (is_null($bt)) $bt = $iio->date_start; $pdata = Period::details($iio->recurring_schedule,$a ? NULL : $iio->product->price_recurr_weekday,$bt,TRUE,TRUE); switch ($iio->recurring_schedule) { case 1: case 2: case 4: case 5: if ($iio->date_start != $pdata['start_time']) { $doutput .= sprintf('%s: Set start_time: %s [%s]
',$iio->id,Config::date($pdata['start_time']),$pdata['start_time']); $iio->date_start=$pdata['start_time']; } if ($iio->date_stop != $pdata['end_time']) { $doutput .= sprintf('%s: Set end_time: %s [%s]
',$iio->id,Config::date($pdata['end_time']),$pdata['end_time']); $iio->date_stop=$pdata['end_time']; } $bt = $pdata['end_time']+86400; //$doutput .= sprintf('%s: BT now: %s (%s) [%s]
',$iio->id,Config::date($bt),Config::date($pdata['end_time']),$bt); break; default: $doutput .= sprintf('%s: %s Not handled',$iio->id,$iio->recurring_schedule); } //$doutput .= '
'; if ($save) { $iio->save(); } } if (isset($_REQUEST['go'])) HTTP::redirect(URL::link('admin','service/view/'.$so->id)); Block::add(array( 'title'=>sprintf('Transaction History for %s: %s',$so->id(),$so->name()), 'body'=>$loutput, )); Block::add(array( 'title'=>sprintf('Transaction Debug for %s: %s',$so->id(),$so->name()), 'body'=>$doutput, )); $output .= View::factory('service/user/view') ->set('so',$so); Block::add(array( 'title'=>sprintf('%s: %s',$so->id(),$so->service_name()), 'body'=>$output, )); } public function action_adslstat() { $output = ''; $svs = ORM::factory('Service')->list_bylistgroup('ADSL'); $stats = array(); // @todo This needs to be configurable. $traffic = array(1000,2000,5000,10000,25000,50000,75000,100000); $ts = 0; foreach ($svs as $a=>$so) { // Number of services if (! isset($stats[$so->product->plugin()->adsl_supplier_plan->speed]['c'])) $stats[$so->product->plugin()->adsl_supplier_plan->speed]['c'] = 0; $stats[$so->product->plugin()->adsl_supplier_plan->speed]['c']++; $ts++; // Amount of traffic $t = array_sum($so->plugin()->traffic_lastmonth(FALSE)); $a = 0; foreach (array_reverse($traffic) as $i) { if ($i < $t) break; $a = $i; } if (! isset($stats[$so->product->plugin()->adsl_supplier_plan->speed]['d'][$a])) $stats[$so->product->plugin()->adsl_supplier_plan->speed]['d'][$a] = 0; $stats[$so->product->plugin()->adsl_supplier_plan->speed]['d'][$a]++; } if (count($stats)) { $output .= View::factory($this->viewpath().'/head') ->set('name','SPEED'); $output .= View::factory($this->viewpath().'/head_data') ->set('name','#'); foreach ($traffic as $i) $output .= View::factory($this->viewpath().'/head_data') ->set('name',$i); $output .= View::factory($this->viewpath().'/head_data') ->set('name','Other'); $output .= View::factory($this->viewpath().'/head_end'); foreach ($stats as $speed => $details) { $output .= View::factory($this->viewpath().'/body_head') ->set('count',$details['c']) ->set('percent',sprintf('%2.1f',$details['c']/$ts*100)) ->set('speed',$speed); foreach ($traffic as $i) { $output .= View::factory($this->viewpath().'/body_data') ->set('count',$c=isset($details['d'][$i]) ? $details['d'][$i] : 0) ->set('percent',sprintf('%2.1f',$c/$details['c']*100)); } $output .= View::factory($this->viewpath().'/body_data') ->set('count',$c=isset($details['d'][0]) ? $details['d'][0] : 0) ->set('percent',sprintf('%2.1f',$c/$details['c']*100)); $output .= View::factory($this->viewpath().'/body_end'); } $output .= View::factory($this->viewpath().'/foot'); } Block::add(array( 'title'=>_('ADSL Traffic Summary Stats - Last Month'), 'body'=>$output, )); } } ?>