diff --git a/application/bootstrap.php b/application/bootstrap.php index 3d02bf9d..974beed3 100644 --- a/application/bootstrap.php +++ b/application/bootstrap.php @@ -102,6 +102,7 @@ Kohana::$config->attach(new Config_File); Kohana::modules(array( 'auth' => SMDPATH.'auth', // Basic authentication 'cache' => SMDPATH.'cache', // Caching with multiple backends + 'cron' => SMDPATH.'cron', // Kohana Cron Module // 'codebench' => SMDPATH.'codebench', // Benchmarking tool 'database' => SMDPATH.'database', // Database access // 'image' => SMDPATH.'image', // Image manipulation diff --git a/application/classes/block/sub.php b/application/classes/block/sub.php new file mode 100644 index 00000000..2304a537 --- /dev/null +++ b/application/classes/block/sub.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/controller/admin/welcome.php b/application/classes/controller/admin/welcome.php new file mode 100644 index 00000000..9226983f --- /dev/null +++ b/application/classes/controller/admin/welcome.php @@ -0,0 +1,70 @@ +TRUE, + ); + + public function action_index() { + $ao = ORM::factory('account',Auth::instance()->get_user()->id); + $t = time(); + + // Show outstanding invoices + $o = ORM::factory('invoice'); + + Block_Sub::add(array( + 'title'=>'Invoices Overdue', + 'body'=>Table::limit( + $o->list_overdue($t), + 30, + array('Due Date'=>'display("due_date")','Account'=>'account->name()','Active'=>'account->display("status")','ID'=>'id()','Amount Due'=>'due(TRUE)'), + 'due()'), + 'position'=>1, + 'order'=>1, + )); + + Block_Sub::add(array( + 'title'=>'Invoices Due', + 'body'=>Table::limit( + $o->list_due($t), + 30, + array('Due Date'=>'display("due_date")','Account'=>'account->name()','Active'=>'account->display("status")','ID'=>'id()','Amount Due'=>'due(TRUE)'), + 'due()'), + 'position'=>2, + 'order'=>1, + )); + + // Show un-applied payments + $o = ORM::factory('payment'); + + Block_Sub::add(array( + 'title'=>'Unapplied Payments', + 'body'=>Table::limit( + $o->list_unapplied(), + 30, + array('ID'=>'id','Account'=>'account->name()','Total'=>'display("total_amt")','Balance'=>'balance(TRUE)'), + 'balance(TRUE)'), + 'position'=>3, + 'order'=>1, + )); + + Block::add(array( + 'title'=>sprintf('%s: %s %s',$ao->accnum(),$ao->first_name,$ao->last_name), + 'subtitle'=>_('Administrator Overview'), + 'body'=>(string)Block_Sub::factory(), + )); + + } +} +?> diff --git a/application/classes/controller/lnapp/task.php b/application/classes/controller/lnapp/task.php new file mode 100644 index 00000000..75dec4d0 --- /dev/null +++ b/application/classes/controller/lnapp/task.php @@ -0,0 +1,21 @@ +$this->request->action())); + + parent::before(); + } +} +?> diff --git a/application/classes/controller/task.php b/application/classes/controller/task.php new file mode 100644 index 00000000..0ca5210f --- /dev/null +++ b/application/classes/controller/task.php @@ -0,0 +1,4 @@ + diff --git a/application/classes/controller/user/welcome.php b/application/classes/controller/user/welcome.php index 4690c74a..635a7e8f 100644 --- a/application/classes/controller/user/welcome.php +++ b/application/classes/controller/user/welcome.php @@ -14,7 +14,7 @@ class Controller_User_Welcome extends Controller_TemplateDefault { protected $auth_required = TRUE; public function action_index() { - $ao = ORM::factory('account',Auth::instance()->get_user()->id); + $ao = ORM::factory('account',Auth::instance()->get_user()->id); Block::add(array( 'title'=>sprintf('%s: %s %s',$ao->accnum(),$ao->first_name,$ao->last_name), diff --git a/application/classes/http/exception/404.php b/application/classes/http/exception/404.php index a72b75d6..c810aeaf 100644 --- a/application/classes/http/exception/404.php +++ b/application/classes/http/exception/404.php @@ -28,3 +28,4 @@ class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 { Request::factory()->redirect('welcome'); } } +?> diff --git a/application/classes/lnapp/block/sub.php b/application/classes/lnapp/block/sub.php new file mode 100644 index 00000000..0f0f781e --- /dev/null +++ b/application/classes/lnapp/block/sub.php @@ -0,0 +1,95 @@ + '; + protected static $_required_keys = array('body','position'); + + /** + * Add a block to be rendered + * + * @param array Block attributes + */ + public static function add($block,$prepend=FALSE) { + parent::add($block); + + // Detect any style sheets. + if (! empty($block['style']) && is_array($block['style'])) + foreach ($block['style'] as $data=>$media) + Style::add(array( + 'type'=>'file', + 'data'=>$data, + 'media'=>$media, + )); + } + + /** + * Return an instance of this class + * + * @return Block + */ + public static function factory() { + return new Block_Sub; + } + + /** + * Render this block + * + * @see HTMLRender::render() + */ + protected function render() { + $output = ''; + $o = array(); + + $i = 0; + $x = $y = 0; + Sort::MAsort(static::$_data,'order,position,title,subtitle'); + foreach (static::$_data as $value) { + $i = (! isset($value['order'])) ? $i+1 : $value['order']; + + // Work out our dimentions + if ($value['position'] > $y) + $y = $value['position']; + if ($i > $x) + $x = $i; + + // @todo Alert if a sub block has already been defined. + $o[$i][$value['position']] = ''; + + if (! empty($value['title'])) + $o[$i][$value['position']] .= sprintf('',$value['title']); + + if (! empty($value['subtitle'])) + $o[$i][$value['position']] .= sprintf('',$value['subtitle']); + + $o[$i][$value['position']] .= sprintf('',$value['body']); + + if (! empty($value['footer'])) + $o[$i][$value['position']] .= sprintf('',$value['footer']); + + $o[$i][$value['position']] .= '
%s
%s
%s
'; + } + + // Render our output. + $output .= ''; + foreach ($o as $k => $v) + $output .= sprintf('',round(100/$y,0),implode('
%s
',$v)); + $output .= '
'; + + return $output; + } +} +?> diff --git a/application/classes/lnapp/config.php b/application/classes/lnapp/config.php index 33369cf1..774ebc1c 100644 --- a/application/classes/lnapp/config.php +++ b/application/classes/lnapp/config.php @@ -84,6 +84,20 @@ abstract class lnApp_Config extends Kohana_Config { return date(Kohana::config('config.date_format'),$date); } + /** + * Show a date using a site configured format + */ + public static function time($date) { + return date(Kohana::config('config.time_format'),$date); + } + + /** + * Show a date using a site configured format + */ + public static function datetime($date) { + return date(Kohana::config('config.date_format').' '.Kohana::config('config.time_format'),$date); + } + /** * See if our emails for the template should be sent to configured admin(s) * diff --git a/application/classes/lnapp/htmlrender.php b/application/classes/lnapp/htmlrender.php index b1404011..325c2038 100644 --- a/application/classes/lnapp/htmlrender.php +++ b/application/classes/lnapp/htmlrender.php @@ -77,9 +77,7 @@ abstract class lnApp_HTMLRender { // Display the exception message catch (Exception $e) { - Kohana::exception_handler($e); - - return ''; + Kohana_Exception::handler($e); } } diff --git a/application/classes/lnapp/table.php b/application/classes/lnapp/table.php new file mode 100644 index 00000000..e8acb547 --- /dev/null +++ b/application/classes/lnapp/table.php @@ -0,0 +1,63 @@ +'; + $output .= ''.implode('',array_keys($cols)).''; + foreach ($data as $do) { + if ($i++ < $rows) { + $output .= ''; + + foreach (array_values($cols) as $col) { + if (is_array($do) AND isset($do[$col])) + $x = $do[$col]; + // If the col is a method, we need to eval it + elseif (preg_match('/\(/',$col)) + eval("\$x = \$do->$col;"); + else + $x = $do->{$col}; + + $output .= sprintf('%s',$x); + } + + $output .= ''; + + } else { + if (is_array($do) AND isset($do[$col])) + $x = $do[$col]; + // If the col is a method, we need to eval it + elseif (preg_match('/\(/',$col)) + eval("\$x = \$do->$col;"); + else + $x = $do->{$col}; + + $other += $x; + } + } + + if ($other) + $output .= sprintf('Other(%s) %s',count($cols)-1,$i-$rows,$other); + + $output .= ''; + + return $output; + } +} +?> diff --git a/application/classes/table.php b/application/classes/table.php new file mode 100644 index 00000000..8c98abde --- /dev/null +++ b/application/classes/table.php @@ -0,0 +1,4 @@ + diff --git a/application/config/config.php b/application/config/config.php index 31c102fd..b1594727 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -13,6 +13,7 @@ return array( 'cache_type' => 'file', 'currency_format' => '2', 'date_format' => 'd-M-Y', + 'time_format' => 'H:i:s', 'email_admin_only'=> array( 'adsl_traffic_notice'=>array('deon@c5t61p.leenooks.vpn'=>'Deon George'), ), diff --git a/application/media/css/default.css b/application/media/css/default.css index 2a4dc0b0..277f02b8 100644 --- a/application/media/css/default.css +++ b/application/media/css/default.css @@ -197,6 +197,21 @@ table.page tr.pagemain td.pagebody table.content table.block { width: 100%; } +table.page tr.pagemain td.pagebody table.content table.block td { + vertical-align: top; +} + +table.page tr.pagemain td.pagebody table.content table.subblockhead { + width: 100%; +} + +table.page tr.pagemain td.pagebody table.content table.subblock { + width: 100%; + border: 1px solid #AAAACC; + margin-right: auto; + width: 100%; +} + table.page tr.pagemain td.pagebody table.content tr.title { text-align: left; margin: 0px; diff --git a/application/views/template.php b/application/views/template.php index 6f727648..e69de29b 100644 --- a/application/views/template.php +++ b/application/views/template.php @@ -1 +0,0 @@ - diff --git a/modules/account/classes/model/account.php b/modules/account/classes/model/account.php index 548c19ff..ca068cdf 100644 --- a/modules/account/classes/model/account.php +++ b/modules/account/classes/model/account.php @@ -18,6 +18,18 @@ class Model_Account extends Model_Auth_UserDefault { 'service' => array('far_key'=>'id'), ); + protected $_display_filters = array( + 'date_orig'=>array( + array('Config::date',array(':value')), + ), + 'date_last'=>array( + array('Config::date',array(':value')), + ), + 'status'=>array( + array('StaticList_YesNo::display',array(':value')), + ), + ); + /** * Return an account name */ @@ -32,10 +44,6 @@ class Model_Account extends Model_Auth_UserDefault { return sprintf('%02s-%04s',Config::siteid(),$this->id); } - public function date_last() { - return Config::date($this->date_last); - } - public function title($name) { return StaticList_Title::form($name,$this->title); } diff --git a/modules/account/classes/model/auth/userdefault.php b/modules/account/classes/model/auth/userdefault.php index a7a9476f..490d579e 100644 --- a/modules/account/classes/model/auth/userdefault.php +++ b/modules/account/classes/model/auth/userdefault.php @@ -78,3 +78,4 @@ class Model_Auth_UserDefault extends Model_Auth_User { ->as_array(); } } +?> diff --git a/modules/account/views/account/edit.php b/modules/account/views/account/edit.php index b731d4af..11012102 100644 --- a/modules/account/views/account/edit.php +++ b/modules/account/views/account/edit.php @@ -3,7 +3,7 @@ - + diff --git a/modules/account_group/classes/model/group.php b/modules/account_group/classes/model/group.php index 3aee3bb9..a8b683f9 100644 --- a/modules/account_group/classes/model/group.php +++ b/modules/account_group/classes/model/group.php @@ -9,8 +9,6 @@ * @license http://dev.leenooks.net/license.html */ class Model_Group extends Model_Auth_RoleDefault { - protected $_object_formated = array(); - // Relationships protected $_has_many = array( 'account'=>array('through'=>'account_group'), @@ -20,10 +18,6 @@ class Model_Group extends Model_Auth_RoleDefault { 'name'=>'ASC', ); - protected $_formats = array( - 'status'=>array('StaticList_YesNo::display'=>array()), - ); - // Validation rules protected $_rules = array( 'name' => array( @@ -35,5 +29,11 @@ class Model_Group extends Model_Auth_RoleDefault { 'max_length' => array(255), ), ); + + protected $_display_filters = array( + 'status'=>array( + array('StaticList_YesNo::display',array(':value')), + ), + ); } ?> diff --git a/modules/adsl/classes/model/adsl/supplier.php b/modules/adsl/classes/model/adsl/supplier.php index 82b85af1..1570ff24 100644 --- a/modules/adsl/classes/model/adsl/supplier.php +++ b/modules/adsl/classes/model/adsl/supplier.php @@ -38,10 +38,12 @@ class Model_ADSL_Supplier extends ORMOSB { return $services; } + /** LIST FUNCTIONS **/ + /** * Return a list of active suppliers */ - public function active() { + public function list_active() { return $this->where('status','=',1)->find_all(); } } diff --git a/modules/currency/classes/currency.php b/modules/currency/classes/currency.php index 987ec112..b3a65ad5 100644 --- a/modules/currency/classes/currency.php +++ b/modules/currency/classes/currency.php @@ -15,3 +15,4 @@ class Currency { return Num::format($amount,2,TRUE); } } +?> diff --git a/modules/email/classes/model/email/log.php b/modules/email/classes/model/email/log.php new file mode 100644 index 00000000..a7bd4027 --- /dev/null +++ b/modules/email/classes/model/email/log.php @@ -0,0 +1,20 @@ +array( + array('Config::datetime',array(':value')), + ), + ); +} +?> diff --git a/modules/emailtemplate/classes/emailtemplate.php b/modules/emailtemplate/classes/emailtemplate.php index db9ac621..3c40d529 100644 --- a/modules/emailtemplate/classes/emailtemplate.php +++ b/modules/emailtemplate/classes/emailtemplate.php @@ -39,12 +39,18 @@ class EmailTemplate { public function __set($key,$value) { switch ($key) { + case 'to': + if (! is_array($value) OR ! array_intersect(array('email','account'),array_keys($value))) + throw new Kohana_Exception('Values for to should be an array of either "mail" or "account", however :value was given',array(':value'=>serialize($value))); + + $this->email_data[$key] = $value; + break; + case 'variables': // Our variables should be an array if (! is_array($value)) throw new Kohana_Exception('Values for variables should be an array, however :value was given',array(':value'=>$value)); - case 'to': $this->email_data[$key] = $value; break; @@ -53,12 +59,44 @@ class EmailTemplate { } } + public function __get($key) { + switch ($key) { + case 'to': + if (empty($this->email_data[$key])) + return array(); + + elseif (isset($this->email_data[$key]['email'])) + return $this->email_data[$key]['email']; + + elseif (isset($this->email_data[$key]['account'])) { + $list = array(); + + foreach ($this->email_data[$key]['account'] as $id) { + $ao = ORM::factory('account',$id); + if ($ao->loaded()) + $list[$ao->email] = $ao->name(); + } + + return $list; + } + + break; + + case 'variables': + return $this->email_data[$key]; + + default: + throw new Kohana_Exception('Unknown variable :key (:value)',array(':key'=>$key,':value'=>is_string($value) ? $value : serialize($value))); + } + } + public static function instance($template) { return new EmailTemplate($template); } public function variables() { $return = array(); + foreach ($this->components as $v) foreach ($this->template_mail->variables($v) as $x=>$y) if (! in_array($y,$return)) @@ -93,14 +131,46 @@ class EmailTemplate { } } + // @todo This should go to the admin defined in email_setup - if ($admin OR ($mail = Config::testmail($this->template->name))) - $sm->setTo($mail); - else - $sm->setTo($this->email_data['to']); + if ($admin OR ($admin = Config::testmail($this->template->name))) { + $sm->setTo($admin); + $sa = array(1); + + } else { + $sm->setTo($this->to); + $sa = $this->to_accounts(); + } // @todo - Setup queue mode - $e->send($sm); + $result = $e->send($sm); + + if ($result) { + // Store our email log. + $data = gzcompress(serialize($this->email_data['variables'])); + $elo = ORM::factory('email_log'); + + foreach ($sa as $id) { + $elo->clear(); + + $elo->account_id = $id; + $elo->email_template_id = $this->template_mail->id; + $elo->data = $data; + $elo->save(); + } + } + + return $result; + } + + private function to_accounts() { + // @todo Set the default account in a configuration file. + $default = array(1); + + if (! isset($this->email_data['to']) OR ! is_array($this->email_data['to']) OR ! array_intersect(array('email','account'),array_keys($this->email_data['to']))) + return $default; + + return isset($this->email_data['to']['account']) ? $this->email_data['to']['account'] : $default; } } ?> diff --git a/modules/emailtemplate/classes/model/emailtemplate.php b/modules/emailtemplate/classes/model/emailtemplate.php index 894e2941..a8f742ed 100644 --- a/modules/emailtemplate/classes/model/emailtemplate.php +++ b/modules/emailtemplate/classes/model/emailtemplate.php @@ -13,19 +13,21 @@ class Model_EmailTemplate extends ORMOSB { protected $_table_name = 'email_template'; protected $_has_many = array( - 'emailtemplate_translate'=>array('foreign_key'=>'email_template_id'), + 'emailtemplate_translate'=>array('foreign_key'=>'email_template_id','far_key'=>'id'), ); // This module doesnt keep track of column updates automatically protected $_created_column = FALSE; protected $_updated_column = FALSE; - protected $_formats = array( - 'active'=>array('StaticList_YesNo::display'=>array()), - ); - protected $_sorting = array( 'name'=>'ASC', ); + + protected $_display_filters = array( + 'status'=>array( + array('StaticList_YesNo::display',array(':value')), + ), + ); } ?> diff --git a/modules/export/classes/model/export.php b/modules/export/classes/model/export.php index 724d9368..d01e8a96 100644 --- a/modules/export/classes/model/export.php +++ b/modules/export/classes/model/export.php @@ -12,3 +12,4 @@ */ class Model_Export extends ORMOSB { } +?> diff --git a/modules/export/classes/osbexport.php b/modules/export/classes/osbexport.php index 11d042be..8da23593 100644 --- a/modules/export/classes/osbexport.php +++ b/modules/export/classes/osbexport.php @@ -33,3 +33,4 @@ abstract class OSBExport { return array_values($this->_data); } } +?> diff --git a/modules/export/classes/quicken.php b/modules/export/classes/quicken.php index cc918c83..5a8e80b7 100644 --- a/modules/export/classes/quicken.php +++ b/modules/export/classes/quicken.php @@ -64,3 +64,4 @@ class Quicken extends OSBExport { return $export; } } +?> diff --git a/modules/export/classes/quicken/invoice.php b/modules/export/classes/quicken/invoice.php index cae2bd00..82675e35 100644 --- a/modules/export/classes/quicken/invoice.php +++ b/modules/export/classes/quicken/invoice.php @@ -24,3 +24,4 @@ class Quicken_Invoice extends Quicken { array_push($this->_payments,$item); } } +?> diff --git a/modules/export/classes/quicken/invoiceitem.php b/modules/export/classes/quicken/invoiceitem.php index c89b54b3..7fe00481 100644 --- a/modules/export/classes/quicken/invoiceitem.php +++ b/modules/export/classes/quicken/invoiceitem.php @@ -12,3 +12,4 @@ */ class Quicken_InvoiceItem extends Quicken { } +?> diff --git a/modules/export/classes/quicken/payment.php b/modules/export/classes/quicken/payment.php index 41f4ba69..255a9ec4 100644 --- a/modules/export/classes/quicken/payment.php +++ b/modules/export/classes/quicken/payment.php @@ -15,3 +15,4 @@ class Quicken_Payment extends Quicken { 'TRNSTYPE'=>'PAYMENT' ); } +?> diff --git a/modules/host_server/classes/controller/hostserver.php b/modules/host_server/classes/controller/hostserver.php index 635d4c55..bb84adf0 100644 --- a/modules/host_server/classes/controller/hostserver.php +++ b/modules/host_server/classes/controller/hostserver.php @@ -102,3 +102,4 @@ class Controller_HostServer extends Controller { print_r(array('s'=>(string)$result,'r'=>(string)$result)); } } +?> diff --git a/modules/invoice/classes/controller/task/invoice.php b/modules/invoice/classes/controller/task/invoice.php new file mode 100644 index 00000000..97342a7e --- /dev/null +++ b/modules/invoice/classes/controller/task/invoice.php @@ -0,0 +1,48 @@ +$mode)); + + $total = $numinv = 0; + $duelist = View::factory('invoice/task/'.$tm.'_header'); + foreach ($io->$tm() as $t) { + $duelist .= View::factory('invoice/task/'.$tm.'_body') + ->set('io',$t); + + $numinv++; + $total += $t->due(); + } + $duelist .= View::factory('invoice/task/'.$tm.'_footer'); + + // Send our email + $et = EmailTemplate::instance('task_invoice_overdue'); + + // @todo Update this to be dynamic + $et->to = array('account'=>array(1,68)); + $et->variables = array( + 'TABLE'=>$duelist, + 'NUM_INV'=>$numinv, + 'TOTAL'=>$total, + ); + $et->send(); + + $output = sprintf('List (%s) sent to: %s',$mode,implode(',',array_keys($et->to))); + $this->response->body($output); + } +} +?> diff --git a/modules/invoice/classes/model/invoice.php b/modules/invoice/classes/model/invoice.php index 297d199e..4bdedaca 100644 --- a/modules/invoice/classes/model/invoice.php +++ b/modules/invoice/classes/model/invoice.php @@ -324,5 +324,37 @@ class Model_Invoice extends ORMOSB { $this->_changed[$field] = $field; } + + /** LIST FUNCTIONS **/ + + /** + * Identify all the invoices that are due + */ + private function _list_due($time=NULL,$op='<=') { + if (is_null($time)) + $time = time(); + + // @todo This rounding should be a system configuration + return $this + ->where('round(total_amt-ifnull(credit_amt,0),2)','>','=billed_amt') + ->and_where('due_date',$op,$time) + ->and_where('status','=',1) + ->order_by('due_date,account_id,id') + ->find_all(); + } + + /** + * Return a list of invoices that are over their due date. + */ + public function list_overdue($time=NULL) { + return $this->_list_due($time,'<='); + } + + /** + * Return a list of invoices that are due, excluding overdue. + */ + public function list_due($time=NULL) { + return $this->_list_due($time,'>'); + } } ?> diff --git a/modules/invoice/invoice.inc.php b/modules/invoice/invoice.inc.php index 693fd575..960d9663 100644 --- a/modules/invoice/invoice.inc.php +++ b/modules/invoice/invoice.inc.php @@ -2465,17 +2465,17 @@ AND ( $this->setRecordAttr('account_id',$so->getRecordAttr('account_id')); $this->setRecordAttr('account_billing_id',$so->getRecordAttr('account_billing_id')); $this->setRecordAttr('billed_currency_id',$ao->getRecordAttr('currency_id')); - $this->setRecordAttr('actual_billed_currency_id',DEFAULT_CURRENCY); +// $this->setRecordAttr('actual_billed_currency_id',DEFAULT_CURRENCY); $this->setRecordAttr('reseller_id',$ao->getRecordAttr('reseller_id')); $this->setRecordAttr('checkout_plugin_id',$ao->getRecordAttr('checkout_plugin_id')); - $this->setRecordAttr('checkout_plugin_data',$ao->getRecordAttr('checkout_plugin_data')); - $this->setRecordAttr('grace_period',$ao->getRecordAttr('invoice_grace')); +// $this->setRecordAttr('checkout_plugin_data',$ao->getRecordAttr('checkout_plugin_data')); +// $this->setRecordAttr('grace_period',$ao->getRecordAttr('invoice_grace')); # @todo this may unintentially allocate all service revenue to an affiliate, which should be configurable (not just the service that the account signed up for initially) - $this->setRecordAttr('affiliate_id',$ao->getRecordAttr('affiliate_id')); +// $this->setRecordAttr('affiliate_id',$ao->getRecordAttr('affiliate_id')); # @todo the parent invoice should bring this campaign id. - $this->setRecordAttr('campaign_id',null); +// $this->setRecordAttr('campaign_id',null); } $this->setRecordAttr('due_date',$so->getRecordAttr('date_next_invoice')); @@ -2519,7 +2519,7 @@ AND ( $last_invoice = $x; } - array_push($invoice['recur_schedules'],$so->getRecordAttr('recur_schedule')); +// array_push($invoice['recur_schedules'],$so->getRecordAttr('recur_schedule')); # Update the last & next invoice date for this service $rs = $db->Execute(sqlUpdate($db,'service', @@ -2616,17 +2616,17 @@ AND ( else $grace_period = GRACE_PERIOD; - $this->setRecordAttr('notice_next_date',time()); +// $this->setRecordAttr('notice_next_date',time()); $this->setRecordAttr('billing_status',0); $this->setRecordAttr('print_status',0); $this->setRecordAttr('process_status',0); $this->setRecordAttr('status',1); // $this->setRecordAttr('suspend_billing',0); $this->setRecordAttr('billed_amt',0); - $this->setRecordAttr('actual_billed_amt',0); - $this->setRecordAttr('notice_count',0); - $this->setRecordAttr('type',1); - $this->setRecordAttr('notice_max',MAX_BILLING_NOTICE); +// $this->setRecordAttr('actual_billed_amt',0); +// $this->setRecordAttr('notice_count',0); +// $this->setRecordAttr('type',1); +// $this->setRecordAttr('notice_max',MAX_BILLING_NOTICE); $rs = $this->sql_SaveRecord(true); if (! $rs) { @@ -2761,10 +2761,10 @@ AND ( 'total_amt' => $total, 'billed_amt' => 0, 'billed_currency_id'=> DEFAULT_CURRENCY, - 'actual_billed_amt' => 0, - 'actual_billed_currency_id' => @$invoice['actual_billed_currency_id'], +// 'actual_billed_amt' => 0, +// 'actual_billed_currency_id' => @$invoice['actual_billed_currency_id'], 'notice_count' => 0, - 'notice_next_date' => time(), +// 'notice_next_date' => time(), 'notice_max' => MAX_BILLING_NOTICE, 'grace_period' => 0, 'due_date' => $due_date @@ -3402,7 +3402,7 @@ AND ( $sInvoicesBal = array(); $db = &DB(); $rs = $db->Execute(sqlSelect('invoice','date_orig,account_id,id,total_amt,billed_amt,IFNULL(credit_amt,0) as credit_amt,ROUND(total_amt-billed_amt-IFNULL(credit_amt,0),2) as balance', - array('where'=>'(refund_status=0 OR refund_status IS NULL) AND status=1 AND total_amt-billed_amt-IFNULL(credit_amt,0)!=0','orderby'=>'account_id,date_orig,id'))); + array('where'=>'status=1 AND total_amt-billed_amt-IFNULL(credit_amt,0)!=0','orderby'=>'account_id,date_orig,id'))); if ($rs && $rs->RecordCount()) { while (! $rs->EOF) { $invoice = array(); diff --git a/modules/invoice/invoice_construct.xml b/modules/invoice/invoice_construct.xml index 39a0cad7..c09af823 100644 --- a/modules/invoice/invoice_construct.xml +++ b/modules/invoice/invoice_construct.xml @@ -19,19 +19,13 @@ date_orig date_last - parent_id billing_status process_status - suspend_billing - refund_status account_id - affiliate_id - campaign_id reseller_id total_amt due_date checkout_plugin_id - tax_id net_term_id @@ -66,16 +60,6 @@ ActiveL - - - - - L - L @@ -85,17 +69,6 @@ Invoice Status L - - - Refund Status - L - - - L @@ -115,16 +88,6 @@ C(32) - - - I4 - - - C(32) @@ -138,13 +101,6 @@ C(255) array - - Total Taxes @@ -155,24 +111,11 @@ Total Credits F - - Total Discounts F - - Amount @@ -195,34 +138,12 @@ I4 - - - I4 - - - - I4 - - - - I8 - date-time - - - - I4 - Date Due I8 date-time - - X @@ -231,33 +152,20 @@ L - - - I8 - - - - I4 - - - - id,type,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,status - id,date_last,type,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,due_date,status + id,date_last,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,due_date,net_term_id id - id,date_orig,date_last,type,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_amt,discount_amt,total_amt,billed_amt,credit_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,type,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,checkout_plugin_data,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals - id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,affiliate_id,campaign_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,actual_billed_amt,actual_billed_currency_id,notice_count,notice_max,notice_next_date,grace_period,due_date,net_term_date_last,net_term_id,net_term_intervals + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,credit_amt,billed_currency_id,due_date,net_term_id + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,due_date,net_term_id + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,due_date,net_term_id + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,due_date,net_term_id + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,due_date,net_term_id + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,due_date,net_term_id + id,date_orig,date_last,process_status,billing_status,print_status,account_id,account_billing_id,reseller_id,checkout_plugin_id,tax_amt,discount_amt,total_amt,billed_amt,billed_currency_id,due_date,net_term_id diff --git a/modules/invoice/views/invoice/task/list_overdue_body.php b/modules/invoice/views/invoice/task/list_overdue_body.php new file mode 100644 index 00000000..4a4d5084 --- /dev/null +++ b/modules/invoice/views/invoice/task/list_overdue_body.php @@ -0,0 +1,6 @@ + + + + + + diff --git a/modules/invoice/views/invoice/task/list_overdue_footer.php b/modules/invoice/views/invoice/task/list_overdue_footer.php new file mode 100644 index 00000000..000ca4b0 --- /dev/null +++ b/modules/invoice/views/invoice/task/list_overdue_footer.php @@ -0,0 +1 @@ +
Last Updateddate_last(); ?>display('date_last'); ?>
User Name
account->name(); ?>display('due_date'); ?>id(); ?>due(TRUE); ?>
diff --git a/modules/invoice/views/invoice/task/list_overdue_header.php b/modules/invoice/views/invoice/task/list_overdue_header.php new file mode 100644 index 00000000..b0e1d550 --- /dev/null +++ b/modules/invoice/views/invoice/task/list_overdue_header.php @@ -0,0 +1,7 @@ + + + + + + + diff --git a/modules/invoice_item/invoice_item_construct.xml b/modules/invoice_item/invoice_item_construct.xml index e83504b3..ac662575 100644 --- a/modules/invoice_item/invoice_item_construct.xml +++ b/modules/invoice_item/invoice_item_construct.xml @@ -14,10 +14,8 @@ 25 - parent_id invoice_id,site_id product_id - account_id service_id,site_id service_id,invoice_id sku @@ -39,16 +37,6 @@ I8 - - I8 @@ -131,10 +119,10 @@ account_id,invoice_id,product_id,product_name,service_id,charge_id,quantity,item_type,product_attr,product_attr_cart,price_type,price_base,price_setup,total_amt,discount_amt,tax_amt,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,date_start,date_stop - date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id - id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id - id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id - id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type,invoice_item_parent_id + date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type + id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type + id,site_id,date_orig,invoice_id,product_id,sku,quantity,item_type,product_attr,product_attr_cart,price_base,price_setup,recurring_schedule,domain_name,domain_tld,domain_term,domain_type + id,site_id,date_orig,invoice_id,product_id,quantity,item_type,price_base,price_setup 0 diff --git a/modules/module/classes/model/module/method.php b/modules/module/classes/model/module/method.php index 70eed89d..40771e91 100644 --- a/modules/module/classes/model/module/method.php +++ b/modules/module/classes/model/module/method.php @@ -26,8 +26,10 @@ class Model_Module_Method extends ORMOSB { 'name'=>'ASC', ); - protected $_formats = array( - 'menu_display'=>array('StaticList_YesNo::display'=>array()), + protected $_display_filters = array( + 'menu_display'=>array( + array('StaticList_YesNo::display',array(':value')), + ), ); // This module doesnt keep track of column updates automatically diff --git a/modules/payment/classes/model/payment.php b/modules/payment/classes/model/payment.php index 310ab2f0..3ca51507 100644 --- a/modules/payment/classes/model/payment.php +++ b/modules/payment/classes/model/payment.php @@ -72,4 +72,21 @@ class Model_Payment extends ORMOSB { public function invoicelist() { return join(',',$this->invoices()); } + + /** LIST FUNCTIONS **/ + + public function list_unapplied() { + $pi = array(); + + // @todo database suffix needs to be dynamically calculated + foreach (DB::Query(Database::SELECT, + sprintf('SELECT A.id AS id,A.total_amt as total_amt FROM ab_%s A,ab_%s B WHERE A.site_id=B.site_id AND A.id=B.payment_id GROUP BY B.payment_id HAVING ROUND(SUM(B.alloc_amt),2)!=A.total_amt ORDER BY account_id,payment_id','payment','payment_item')) + ->execute() as $values) { + + array_push($pi,$values['id']); + } + + return $this->where('id','IN',$pi)->order_by('account_id')->find_all(); + } } +?> diff --git a/modules/payment/classes/model/payment/item.php b/modules/payment/classes/model/payment/item.php index 79a52364..7c653037 100644 --- a/modules/payment/classes/model/payment/item.php +++ b/modules/payment/classes/model/payment/item.php @@ -13,3 +13,4 @@ class Model_Payment_Item extends ORMOSB { protected $_belongs_to = array('payment'=>array(),'invoice'=>array()); } +?> diff --git a/modules/product/classes/model/product.php b/modules/product/classes/model/product.php index d97fb147..940b1f28 100644 --- a/modules/product/classes/model/product.php +++ b/modules/product/classes/model/product.php @@ -21,8 +21,10 @@ class Model_Product extends ORMOSB { 'sku'=>'asc', ); - protected $_display_format = array( - 'price_type'=>array('StaticList_PriceType::display'=>array()), + protected $_display_filters = array( + 'price_type'=>array( + array('StaticList_PriceType::display',array(':value')), + ), ); /** @@ -43,7 +45,7 @@ class Model_Product extends ORMOSB { /** * Return the object of the product plugin */ - private function plugin() { + public function plugin() { if (! $this->prod_plugin_file) return NULL; diff --git a/modules/service/classes/controller/task/service.php b/modules/service/classes/controller/task/service.php index 67826832..4cbf63f9 100644 --- a/modules/service/classes/controller/task/service.php +++ b/modules/service/classes/controller/task/service.php @@ -10,11 +10,11 @@ * @copyright (c) 2010 Open Source Billing * @license http://dev.osbill.net/license.html */ -class Controller_Task_Service extends Controller_Template { +class Controller_Task_Service extends Controller_Task { private function _traffic_suppliers($active=FALSE) { $suppliers = ORM::factory('adsl_supplier'); - return $active ? $suppliers->active() : $suppliers->find_all(); + return $active ? $suppliers->list_active() : $suppliers->find_all(); } /** diff --git a/modules/service/classes/model/service/adsl.php b/modules/service/classes/model/service/adsl.php index 11b38de8..e4c113ae 100644 --- a/modules/service/classes/model/service/adsl.php +++ b/modules/service/classes/model/service/adsl.php @@ -338,7 +338,7 @@ class Model_Service_ADSL extends Model_Service { } protected function _service_view() { - return View::factory($this->viewpath(strtolower($this->service->prod_plugin_name))) + return View::factory('service/user/adsl/view') ->set('so',$this); } diff --git a/modules/static_page/classes/controller/staticpage/category.php b/modules/static_page/classes/controller/staticpage/category.php index 75a24fc0..c57f46de 100644 --- a/modules/static_page/classes/controller/staticpage/category.php +++ b/modules/static_page/classes/controller/staticpage/category.php @@ -61,3 +61,4 @@ class Controller_StaticPage_Category extends Controller_TemplateDefault { ->find_all(); } } +?> diff --git a/modules/static_page/classes/model/staticpage.php b/modules/static_page/classes/model/staticpage.php index 611daba6..6d14ecb7 100644 --- a/modules/static_page/classes/model/staticpage.php +++ b/modules/static_page/classes/model/staticpage.php @@ -25,3 +25,4 @@ class Model_StaticPage extends ORMOSB { 'staticpage_category'=>array('foreign_key'=>'static_page_category_id'), ); } +?> diff --git a/modules/static_page/classes/model/staticpage/category.php b/modules/static_page/classes/model/staticpage/category.php index 43c965f3..7ce2169f 100644 --- a/modules/static_page/classes/model/staticpage/category.php +++ b/modules/static_page/classes/model/staticpage/category.php @@ -17,3 +17,4 @@ class Model_StaticPage_Category extends ORMOSB { 'name'=>'asc', ); } +?> diff --git a/modules/static_page/classes/model/staticpage/translate.php b/modules/static_page/classes/model/staticpage/translate.php index 18cf92f3..7a64f264 100644 --- a/modules/static_page/classes/model/staticpage/translate.php +++ b/modules/static_page/classes/model/staticpage/translate.php @@ -17,3 +17,4 @@ class Model_StaticPage_Translate extends ORMOSB { 'staticpage'=>array('foreign_key'=>'id'), ); } +?> diff --git a/modules/task/classes/controller/task/task.php b/modules/task/classes/controller/task/task.php new file mode 100644 index 00000000..dc6da59c --- /dev/null +++ b/modules/task/classes/controller/task/task.php @@ -0,0 +1,59 @@ +request->param('id'); + + if (! method_exists($to,$tm)) + throw new Kohana_Exception('Unknown Task List command :command',array(':command'=>$mode)); + + $output .= sprintf('%2s %30s %21s %21s %40s', + 'ID','Command','Last Run','Next Run','Description'); + $output .= "\n"; + + foreach ($to->$tm() as $t) { + $output .= sprintf('%2s %30s %21s %21s %40s', + $t['task']->id, + $t['task']->command, + $t['task']->display('date_run'), + Config::datetime($t['next']), + $t['task']->display('description') + ); + + $output .= "\n"; + }; + + $this->response->body($output); + } + + public function action_run() { + if ($id = $this->request->param('id')) { + $to = ORM::factory('task',$id); + $to->run(); + + } else { + $tlo = ORM::factory('task'); + $t = time(); + + foreach ($tlo->list_active() as $to) + if ($to['next'] < $t) + $to['task']->run(); + } + } +} +?> diff --git a/modules/task/classes/model/task.php b/modules/task/classes/model/task.php new file mode 100644 index 00000000..45d02bbe --- /dev/null +++ b/modules/task/classes/model/task.php @@ -0,0 +1,107 @@ +array( + array('Config::datetime',array(':value')), + ), + ); + + public function run() { + $r = rand(0,9999); + $tlo = ORM::factory('task_log'); + $tlo->task_id = $this->id; + + if (! $this->loaded()) + $tlo->message = sprintf('Unknown Task ID %s',$this->id); + + elseif (! $this->status) + $tlo->message = sprintf('Task %s is not active',$this->id); + + elseif ($this->running) + $tlo->message = sprintf('Task %s is already running',$this->id); + + elseif (! preg_match('/\//',$this->command)) + $tlo->message = sprintf('Task %s uses the old configuration, ignoring :command',$this->id,$this->command); + + else { + try { + // Get a lock + $this->running = 1; + $this->running_host = $r; + $this->save(); + + // Check we are the winning host to run this task + $this->reload(); + if ($this->running_host != $r) + return; + + switch ($this->type) { + case 0: + $r = Request::factory($this->command)->execute(); + break; + + default: + throw new Kohana_Exception('Unknown task type :type',array(':type'=>$this->type)); + } + + // Clear our lock and update the last run time + $this->date_run = time(); + $this->running = 0; + $this->running_host = NULL; + $this->save(); + + $tlo->result = 0; + $tlo->message = $r->body(); + } + catch (Exception $e) { + $tlo->result = $e->getCode(); + $tlo->message = $e->getMessage(); + } + } + + if ($this->log) + $tlo->save(); + } + + /** LIST FUNCTIONS **/ + + private function _list_active() { + return $this->where('status','=',1)->find_all(); + } + + public function list_active() { + $return = array(); + + foreach ($this->_list_active() as $to) { + $ct = sprintf('%s %s %s %s %s',$to->int_min,$to->int_hour,$to->int_month_day,$to->int_month,$to->int_week_day); + + $c = new Cron($ct,$to->command); + $return[$to->id]['task'] = $to; + $return[$to->id]['next'] = $c->next($to->date_run); + } + + return $return; + } + + public function list_next() { + $return = array(); + + foreach ($this->list_active() as $v) + if ((! $return OR $v['next']<$return['next']) AND ! $v['task']->running) + $return = $v; + + return array($return['task']->id=>$return); + } +} +?> diff --git a/modules/task/classes/model/task/log.php b/modules/task/classes/model/task/log.php new file mode 100644 index 00000000..6463024f --- /dev/null +++ b/modules/task/classes/model/task/log.php @@ -0,0 +1,20 @@ +array( + array('Config::datetime',array(':value')), + ), + ); +} +?> diff --git a/modules/task/task.inc.php b/modules/task/task.inc.php index ff69742e..b7201467 100644 --- a/modules/task/task.inc.php +++ b/modules/task/task.inc.php @@ -57,8 +57,8 @@ class task extends OSB_module { printf("%s: Selecting Job [%s] (%s)\n",__METHOD__,$result['command'],$this->id); $task = array(); - $task['start'] = (int)$result['date_start']; - $task['end'] = (int)$result['date_expire']; + $task['start'] = 0; + $task['end'] = 0; $task['lastrun'] = (int)$result['date_run']; $task['cron'] = sprintf('%s %s %s %s %s', $result['int_min'],
AccountDue DateInv IDAmount Due