'services'); protected $secure_actions = array( 'list'=>TRUE, 'listbycheckout'=>TRUE, 'listadslbilling'=>TRUE, 'listadslservices'=>TRUE, 'listhspaservices'=>TRUE, 'update'=>TRUE, ); /** * Show a list of services */ public function action_list() { $so = ORM::factory('service'); Block::add(array( 'title'=>_('System Customer Services'), 'body'=>Table::display( $so->find_all(), 25, array( 'id'=>array('label'=>'ID','url'=>'user/service/view/'), 'type'=>array('label'=>'Type'), 'name()'=>array('label'=>'Details'), 'recur_schedule'=>array('label'=>'Billing'), 'price'=>array('label'=>'Price','class'=>'right'), 'active'=>array('label'=>'Active'), 'account->accnum()'=>array('label'=>'Cust ID'), 'account->name()'=>array('label'=>'Customer'), ), array( 'page'=>TRUE, 'type'=>'select', 'form'=>'user/email/view', )), )); } /** * List all services by their default checkout method */ public function action_listbycheckout() { // @todo need to add the DB prefix here // @todo need to remove the explicit references to the group_id $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!=2 ) 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 = ''; 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/admin/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/admin/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/admin/list/bycheckout_body') ->set('service',$so) ->set('i',$i++%2); } // Last subtotal if ($sc > 1) $output .= View::factory('service/admin/list/bycheckout_subtotal') ->set('subtotal',$st) ->set('i',$i++%2); $output .= '
'; Block::add(array( 'title'=>_('List all Services by Default Payment Method'), 'body'=>$output, )); Style::add(array( 'type'=>'file', 'data'=>'css/list.css', )); } //@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 = ''; foreach ($services as $service) { $so = ORM::factory('service',$service['service_id']); if ($last_account != $so->account_id) { if ($i) $output .= ''; $output .= View::factory('service/admin/list/adslservices_header') ->set('service',$so); $last_account = $so->account_id; } $output .= View::factory('service/admin/list/adslservices_body') ->set('service',$so) ->set('i',$i++%2); } $output .= '
 
'; // 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', )); } 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 = ''; foreach ($services as $service) { $so = ORM::factory('service',$service['service_id']); if ($last_account != $so->account_id) { if ($i) $output .= ''; $output .= View::factory('service/admin/list/adslservices_header') ->set('service',$so); $last_account = $so->account_id; } $output .= View::factory('service/admin/list/adslservices_body') ->set('service',$so) ->set('i',$i++%2); } $output .= '
 
'; // 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', )); } /** * 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 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 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/admin/list/adslbilling_head'); $output .= ''; 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/admin/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/admin/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/admin/list/adslbilling_foot') ->set('total',$total); $output .= '
'; // Summary Report of remaining CSV items. if (! empty($csv)) foreach ($csv as $service => $item) { $summary .= View::factory('service/admin/list/adslbilling_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; $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; } public function action_update($id) { $so = ORM::factory('service',$id); if (! $so->loaded()) Request::current()->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 plugin 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($so->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', )); } } ?>