TRUE, 'listbycheckout'=>TRUE, 'listadslbilling'=>TRUE, 'listadslservices'=>TRUE, 'listdomainservices'=>TRUE, 'listhostservices'=>TRUE, 'listhspaservices'=>TRUE, 'listinvoicesoon'=>TRUE, 'update'=>TRUE, ); /** * Show a list of services */ public function action_list() { Block::add(array( 'title'=>_('Customer Services'), 'body'=>Table::display( ORM::factory('service')->find_all(), 25, array( 'id'=>array('label'=>'ID','url'=>'user/service/view/'), 'service_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/service/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', )); } 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; } public function action_listadslservices() { $svs = ORM::factory('service')->list_bylistgroup('ADSL'); $data = $this->consoltraffic($svs,time()); $google = GoogleChart::factory('vertical_bar'); $google->title = sprintf('ADSL traffic as at %s',date('Y-m-d',strtotime('yesterday'))); $google->series(array('title'=>array_keys($data['data']),'axis'=>'x','data'=>$data['data'])); $google->series(array('title'=>'Services','axis'=>'r','data'=>array('Services'=>$data['svs']))); Block::add(array('body'=>$google)); Block::add(array( 'title'=>_('ADSL Services'), 'body'=>Table::display( $svs, NULL, array( 'id'=>array('label'=>'ID','url'=>'user/service/view/'), 'name()'=>array('label'=>'Service'), 'plugin()->ipaddress()'=>array('label'=>'IP Address'), 'product->plugin()->allowance()'=>array('label'=>'Allowance'), 'plugin()->traffic_thismonth()'=>array('label'=>'This Month'), 'plugin()->traffic_lastmonth()'=>array('label'=>'Last Month'), 'recur_schedule'=>array('label'=>'Billing'), 'price'=>array('label'=>'Price','class'=>'right'), 'account->accnum()'=>array('label'=>'Cust ID'), 'account->name()'=>array('label'=>'Customer'), 'date_next_invoice'=>array('label'=>'Next Invoice'), ), array( 'type'=>'select', 'form'=>'user/service/view', )), )); } public function action_listhspaservices() { $svs = ORM::factory('service')->list_bylistgroup('HSPA'); $data = $this->consoltraffic($svs,time()); $google = GoogleChart::factory('vertical_bar'); $google->title = sprintf('HSPA traffic as at %s',date('Y-m-d',strtotime('yesterday'))); $google->series(array('title'=>array_keys($data['data']),'axis'=>'x','data'=>$data['data'])); $google->series(array('title'=>'Services','axis'=>'r','data'=>array('Services'=>$data['svs']))); Block::add(array('body'=>$google)); Block::add(array( 'title'=>_('HSPA Services'), 'body'=>Table::display( $svs, NULL, array( 'id'=>array('label'=>'ID','url'=>'user/service/view/'), 'name()'=>array('label'=>'Service'), 'plugin()->ipaddress()'=>array('label'=>'IP Address'), 'product->plugin()->allowance()'=>array('label'=>'Allowance'), 'plugin()->traffic_thismonth()'=>array('label'=>'This Month'), 'plugin()->traffic_lastmonth()'=>array('label'=>'Last Month'), 'recur_schedule'=>array('label'=>'Billing'), 'price'=>array('label'=>'Price','class'=>'right'), 'account->accnum()'=>array('label'=>'Cust ID'), 'account->name()'=>array('label'=>'Customer'), 'date_next_invoice'=>array('label'=>'Next Invoice'), ), array( 'type'=>'select', 'form'=>'user/service/view', )), )); } public function action_listdomainservices() { $svs = ORM::factory('service')->list_bylistgroup('DOMAIN'); Sort::MAsort($svs,'name()'); Block::add(array( 'title'=>_('Domain Names'), 'body'=>Table::display( $svs, 25, array( 'id'=>array('label'=>'ID','url'=>'user/service/view/'), 'service_name()'=>array('label'=>'Details'), 'plugin()->display("domain_expire")'=>array('label'=>'Expire'), 'recur_schedule'=>array('label'=>'Billing'), 'price'=>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'=>'user/service/view', )), )); } public function action_listhostservices() { $svs = ORM::factory('service')->list_bylistgroup('HOST'); Sort::MAsort($svs,'name()'); Block::add(array( 'title'=>_('Hosting Services'), 'body'=>Table::display( $svs, 25, array( 'id'=>array('label'=>'ID','url'=>'user/service/view/'), 'service_name()'=>array('label'=>'Details'), 'plugin()->display("host_expire")'=>array('label'=>'Expire'), 'recur_schedule'=>array('label'=>'Billing'), 'price'=>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'=>'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) { $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) { $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('service/admin/list/adslbilling_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('service/admin/list/adslbilling_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('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 excess charges. elseif (preg_match('/^Excess usage/',$description)) $return[$service]['excess'] = preg_replace('/\$/','',$total); else $return[$service]['info'] = $line; } return $return; } /** * 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(), 25, array( 'id'=>array('label'=>'ID','url'=>'user/service/view/'), 'service_name()'=>array('label'=>'Details'), 'recur_schedule'=>array('label'=>'Billing'), 'date_next_invoice'=>array('label'=>'Next Invoice'), '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/service/view', )), )); } 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', )); } } ?>