This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Deon George 130a87aa9a Major work to domain and hosting
Minor updates for ADSL services
Updates to Sort::MAsort()
Move core OSB items under application/
Moved ACCOUNT functions under application
Minor updates to task
2012-01-12 19:53:55 +11:00

484 lines
15 KiB
PHP

<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides Admin Service functions
*
* @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_Admin {
protected $secure_actions = array(
'list'=>TRUE,
'listbycheckout'=>TRUE,
'listadslbilling'=>TRUE,
'listadslservices'=>TRUE,
'listdomainservices'=>TRUE,
'listhostservices'=>TRUE,
'listhspaservices'=>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 = '<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/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 .= '</table>';
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 .= '<table class="box-left">';
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 .= '</table>';
// 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 .= '<div>';
$output .= Form::file('csv');
$output .= Form::submit('submit','upload',array('class'=>'form_button'));
$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',
));
}
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;
}
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',
));
}
}
?>