Updated charge, Invoice improvements and other minor fixes
This commit is contained in:
parent
2322a802de
commit
ab3735914b
@ -11,27 +11,11 @@
|
||||
*/
|
||||
class Controller_Reseller_Account extends Controller_Account {
|
||||
protected $secure_actions = array(
|
||||
'ajaxlist'=>TRUE,
|
||||
'list'=>TRUE,
|
||||
'listlog'=>TRUE,
|
||||
'view'=>TRUE,
|
||||
);
|
||||
|
||||
/**
|
||||
* Used by AJAX calls to find accounts
|
||||
* @note list_autocomplete() will limit to authorised accounts
|
||||
*/
|
||||
public function action_ajaxlist() {
|
||||
$result = array();
|
||||
|
||||
if (isset($_REQUEST['term']) AND trim($_REQUEST['term']))
|
||||
$result += ORM::factory('Account')->list_autocomplete($_REQUEST['term']);
|
||||
|
||||
$this->auto_render = FALSE;
|
||||
$this->response->headers('Content-Type','application/json');
|
||||
$this->response->body(json_encode(array_values($result)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of accounts
|
||||
*/
|
||||
@ -138,7 +122,7 @@ class Controller_Reseller_Account extends Controller_Account {
|
||||
->title(sprintf('Next Invoice Items for Account: %s',$ao->accnum()))
|
||||
->title_icon('icon-info-sign')
|
||||
->span(6)
|
||||
->body($i->render('html','body'));
|
||||
->body($i->render('html','body',array('noid'=>TRUE)));
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -41,7 +41,7 @@ class Controller_TemplateDefault extends lnApp_Controller_TemplateDefault {
|
||||
|
||||
// @todo To rework
|
||||
public function after() {
|
||||
$dc = 'u/welcome/index';
|
||||
$dc = URL::link('user','welcome/index');
|
||||
$m = sprintf('%s/%s',Request::current()->directory(),Request::current()->controller());
|
||||
|
||||
BreadCrumb::URL(Request::current()->directory(),sprintf('%s/%s',Request::current()->directory(),$dc),FALSE);
|
||||
|
@ -21,12 +21,12 @@ class Controller_User_Search extends Controller_Search {
|
||||
$result = array();
|
||||
|
||||
if (isset($_REQUEST['term']) AND trim($_REQUEST['term'])) {
|
||||
$result = Arr::merge($result,ORM::factory('Account')->list_autocomplete($_REQUEST['term'],'url','id',array('ACC %s: %s'=>array('id','name(TRUE)')),array(),array('urlprefix'=>'r/account/view/')));
|
||||
$result = Arr::merge($result,ORM::factory('Service')->list_autocomplete($_REQUEST['term'],'url','id',array('SVC %s: %s'=>array('id','service_name()')),array(),array('urlprefix'=>'u/service/view/')));
|
||||
$result = Arr::merge($result,ORM::factory('Invoice')->list_autocomplete($_REQUEST['term'],'url','id',array('INV %s: %s'=>array('id','account->name(TRUE)')),array(),array('urlprefix'=>'u/invoice/view/')));
|
||||
$result = Arr::merge($result,ORM::factory('Account')->list_autocomplete($_REQUEST['term'],'url','id',array('ACC %s: %s'=>array('id','name(TRUE)')),array(),array('urlprefix'=>URL::link('reseller','account/view/'))));
|
||||
$result = Arr::merge($result,ORM::factory('Service')->list_autocomplete($_REQUEST['term'],'url','id',array('SVC %s: %s'=>array('id','service_name()')),array(),array('urlprefix'=>URL::link('user','service/view/'))));
|
||||
$result = Arr::merge($result,ORM::factory('Invoice')->list_autocomplete($_REQUEST['term'],'url','id',array('INV %s: %s'=>array('id','account->name(TRUE)')),array(),array('urlprefix'=>URL::link('user','invoice/view/'))));
|
||||
|
||||
foreach (array('Service_Plugin_Adsl','Service_Plugin_Domain','Service_Plugin_Host') as $o)
|
||||
$result = Arr::merge($result,ORM::factory($o)->list_autocomplete($_REQUEST['term'],'url','service_id',array('SVC %s: %s'=>array('service_id','service_name()')),array(),array('urlprefix'=>'u/service/view/')));
|
||||
$result = Arr::merge($result,ORM::factory($o)->list_autocomplete($_REQUEST['term'],'url','service_id',array('SVC %s: %s'=>array('service_id','service_name()')),array(),array('urlprefix'=>URL::link('user','service/view/'))));
|
||||
}
|
||||
|
||||
$this->response->headers('Content-Type','application/json');
|
||||
|
@ -10,11 +10,17 @@
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
abstract class Minion_Task extends Kohana_Minion_Task {
|
||||
protected $_options = array(
|
||||
protected $_sysoptions = array(
|
||||
'site'=>NULL,
|
||||
'id'=>NULL,
|
||||
'force'=>FALSE,
|
||||
'verbose'=>FALSE,
|
||||
);
|
||||
|
||||
/**
|
||||
* Override our __construct so that we can specify options in each class file
|
||||
*/
|
||||
protected function __construct() {
|
||||
// Populate $_accepted_options based on keys from $_options
|
||||
$this->_accepted_options = array_keys(Arr::merge($this->_sysoptions,$this->_options));
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -14,6 +14,10 @@ class Model_Country extends ORM_OSB {
|
||||
'currency'=>array('far_key'=>'id'),
|
||||
);
|
||||
|
||||
protected $_sorting = array(
|
||||
'name'=>'ASC',
|
||||
);
|
||||
|
||||
protected $_form = array('id'=>'id','value'=>'name');
|
||||
|
||||
public static function icon() {
|
||||
|
@ -10,6 +10,10 @@
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Model_Currency extends ORM_OSB {
|
||||
protected $_sorting = array(
|
||||
'name'=>'ASC',
|
||||
);
|
||||
|
||||
protected $_form = array('id'=>'id','value'=>'name');
|
||||
}
|
||||
?>
|
||||
|
@ -10,6 +10,10 @@
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Model_Language extends ORM_OSB {
|
||||
protected $_sorting = array(
|
||||
'name'=>'ASC',
|
||||
);
|
||||
|
||||
protected $_form = array('id'=>'id','value'=>'name');
|
||||
}
|
||||
?>
|
||||
|
@ -27,6 +27,11 @@ abstract class ORM_OSB extends ORM {
|
||||
// Our attribute values that need to be stored as serialized
|
||||
protected $_serialize_column = array();
|
||||
|
||||
// If we need to load any sub items on loading this model
|
||||
protected $_sub_items = array();
|
||||
protected $_sub_items_load = array();
|
||||
protected $_sub_items_sorted = FALSE;
|
||||
|
||||
// Rules to assist with site ID and getting next record ID for inserts.
|
||||
public function rules() {
|
||||
return array(
|
||||
@ -101,6 +106,25 @@ abstract class ORM_OSB extends ORM {
|
||||
return parent::__get($column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept our object load, so that we can load our subitems
|
||||
*/
|
||||
protected function _load_values(array $values) {
|
||||
parent::_load_values($values);
|
||||
|
||||
$sort = FALSE;
|
||||
if ($this->_loaded AND $this->_sub_items_load AND count($this->_sub_items_load) == 1)
|
||||
foreach ($this->_sub_items_load as $item => $sort)
|
||||
$this->_sub_items = $this->$item->find_all()->as_array();
|
||||
|
||||
if ($sort) {
|
||||
Sort::MAsort($this->_sub_items,$sort);
|
||||
$this->_sub_items_sorted = TRUE;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a column is marked to be nullified if it is empty, this is where it is done.
|
||||
*/
|
||||
@ -266,7 +290,7 @@ abstract class ORM_OSB extends ORM {
|
||||
|
||||
if ($this->_form AND array_intersect(array('id','value'),$this->_form))
|
||||
foreach ($this->find_all() as $o)
|
||||
$result[$o->{$this->_form['id']}] = $o->{$this->_form['value']};
|
||||
$result[$o->{$this->_form['id']}] = $o->resolve($this->_form['value']);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
@ -12,8 +12,15 @@
|
||||
class StaticList_ItemType extends StaticList {
|
||||
protected function _table() {
|
||||
return array(
|
||||
0=>'MAIN', // Line Charge Topic on Invoice, eg: Service Name
|
||||
5=>'EXCESS', // Excess Service Item, of item 0
|
||||
0=>_('Product/Service Charge'), // Line Charge Topic on Invoice, eg: Service Name
|
||||
1=> _('Hardware'),
|
||||
2=> _('Service Relocation Fee'),
|
||||
3=> _('Service Change Fee'),
|
||||
4=> _('Service Connection Fee'),
|
||||
5=>_('Excess Usage'), // Excess Service Item, of item 0
|
||||
125=>_('Payment Fee'), // Payment processing fee
|
||||
126=> _('Rounding'),
|
||||
127=> _('Late Payment Fee'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
* OSB Configuration - Authentication
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Authentication
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* OSB Caching
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage System
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* OSB Configuration - System Default Configurable Items.
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage System
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* OSB Configuration - Database Driver
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Database
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* OSB Configuration - Debug Settings
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Debug
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* OSB Configuration - PWGen Configuration
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage PWGen
|
||||
* @category PWGen
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
187
application/tests/classes/PeriodTest.php
Normal file
187
application/tests/classes/PeriodTest.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* Test that PeriodTest is doing as expected
|
||||
*
|
||||
* @group osb
|
||||
* @group osb.helpers
|
||||
*/
|
||||
class PeriodTest extends UnitTest_TestCase {
|
||||
private $DATE = '2012-07-20'; // Fri (5)
|
||||
private $TIME;
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$this->TIME = strtotime($this->DATE);
|
||||
$this->w = date('w',$this->TIME);
|
||||
}
|
||||
|
||||
// Weekly
|
||||
public function test_weekly() {
|
||||
# +7 week
|
||||
foreach (array(0,2,6) as $x) {
|
||||
$p = Period::details(0,NULL,$this->TIME+86400*$x,TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',$this->TIME+86400*(7+$x-1)),$p['end']);
|
||||
}
|
||||
|
||||
# +7 week, SUN
|
||||
foreach (array(0,2,6) as $x) {
|
||||
$p = Period::details(0,0,$this->TIME+86400*$x,TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',$this->TIME+86400*(7-($this->w+$x)%7+$x-1)),$p['end']); // Sat
|
||||
}
|
||||
|
||||
# +7 week, TUE
|
||||
foreach (array(0,2,6) as $x) {
|
||||
$p = Period::details(0,2,$this->TIME+86400*$x,TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',$this->TIME+86400*(7-($this->w+$x)%7+$x-1+2)),$p['end']); // Sat
|
||||
}
|
||||
}
|
||||
|
||||
public function test_monthly() {
|
||||
# +1 month
|
||||
$p = Period::details(1,NULL,strtotime('2012-07-20'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-08-19')),$p['end']);
|
||||
|
||||
$p = Period::details(1,NULL,strtotime('2012-07-01'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-07-31')),$p['end']);
|
||||
|
||||
$p = Period::details(1,NULL,strtotime('2012-07-31'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-08-30')),$p['end']);
|
||||
|
||||
# +1 month, 1st of the month
|
||||
$p = Period::details(1,1,strtotime('2012-07-20'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-07-31')),$p['end']);
|
||||
|
||||
$p = Period::details(1,1,strtotime('2012-07-01'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-07-31')),$p['end']);
|
||||
|
||||
$p = Period::details(1,1,strtotime('2012-07-31'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-07-31')),$p['end']);
|
||||
|
||||
# +1 month, 15th of the month
|
||||
$p = Period::details(1,15,strtotime('2012-07-20'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-08-14')),$p['end']);
|
||||
|
||||
$p = Period::details(1,15,strtotime('2012-02-20'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-03-14')),$p['end']);
|
||||
|
||||
$p = Period::details(1,15,strtotime('2012-02-14'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-02-14')),$p['end']);
|
||||
|
||||
$p = Period::details(1,15,strtotime('2012-02-15'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-03-14')),$p['end']);
|
||||
|
||||
# +1 month, 1st of the month, strict doesnt have any affect
|
||||
$p = Period::details(1,1,strtotime('2012-07-20'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-07-31')),$p['end']);
|
||||
|
||||
$p = Period::details(1,1,strtotime('2012-07-01'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-07-31')),$p['end']);
|
||||
|
||||
$p = Period::details(1,1,strtotime('2012-07-31'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-07-31')),$p['end']);
|
||||
}
|
||||
|
||||
public function test_quarterly() {
|
||||
# +3 months
|
||||
$p = Period::details(2,NULL,strtotime('2012-02-15'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-05-14')),$p['end']);
|
||||
|
||||
$p = Period::details(2,NULL,strtotime('2012-11-15'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-02-14')),$p['end']);
|
||||
|
||||
$p = Period::details(2,NULL,strtotime('2012-08-20'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-11-19')),$p['end']);
|
||||
|
||||
# +3 months, 1st of the month
|
||||
$p = Period::details(2,1,strtotime('2012-08-20'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-10-31')),$p['end']);
|
||||
|
||||
$p = Period::details(2,1,strtotime('2012-11-15'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-01-31')),$p['end']);
|
||||
|
||||
# +3 months, 1st of the month, strict JAN-MAR,APR-JUN,JUL-SEP,OCT-DEC
|
||||
$p = Period::details(2,1,strtotime('2012-11-15'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-12-31')),$p['end']);
|
||||
|
||||
$p = Period::details(2,1,strtotime('2013-01-01'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-03-31')),$p['end']);
|
||||
}
|
||||
|
||||
public function test_halfyearly() {
|
||||
# +6 months
|
||||
$p = Period::details(3,NULL,strtotime('2012-02-15'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-08-14')),$p['end']);
|
||||
|
||||
$p = Period::details(3,NULL,strtotime('2011-09-15'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-03-14')),$p['end']);
|
||||
|
||||
# +6 months, 1st of the month
|
||||
$p = Period::details(3,1,strtotime('2012-02-15'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-07-31')),$p['end']);
|
||||
|
||||
$p = Period::details(3,1,strtotime('2011-09-15'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-02-29')),$p['end']);
|
||||
|
||||
# +6 months, 1st of the month, strict JAN-JUN,JUL-DEC
|
||||
$p = Period::details(3,1,strtotime('2012-02-15'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-06-30')),$p['end']);
|
||||
|
||||
$p = Period::details(3,1,strtotime('2012-01-01'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-06-30')),$p['end']);
|
||||
}
|
||||
|
||||
public function test_yearly() {
|
||||
# +1 year
|
||||
$p = Period::details(4,NULL,strtotime('2012-02-29'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-02-28')),$p['end']);
|
||||
|
||||
# +1 year, 1st of the month
|
||||
$p = Period::details(4,1,strtotime('2012-02-29'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-01-31')),$p['end']);
|
||||
|
||||
$p = Period::details(4,1,strtotime('2012-02-01'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-01-31')),$p['end']);
|
||||
|
||||
# +1 year, 1st of the month, strict JAN-DEC
|
||||
$p = Period::details(4,1,strtotime('2012-02-29'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-12-31')),$p['end']);
|
||||
|
||||
$p = Period::details(4,1,strtotime('2012-12-31'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2012-12-31')),$p['end']);
|
||||
|
||||
$p = Period::details(4,1,strtotime('2013-02-28'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-12-31')),$p['end']);
|
||||
|
||||
$p = Period::details(4,1,strtotime('2013-12-31'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-12-31')),$p['end']);
|
||||
}
|
||||
|
||||
public function test_twoyear() {
|
||||
# +2 year
|
||||
$p = Period::details(5,NULL,strtotime('2012-02-29'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2014-02-28')),$p['end']);
|
||||
|
||||
# +2 year, 1st of the month
|
||||
$p = Period::details(5,1,strtotime('2012-02-29'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2014-01-31')),$p['end']);
|
||||
|
||||
$p = Period::details(5,1,strtotime('2012-02-01'),TRUE,FALSE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2014-01-31')),$p['end']);
|
||||
|
||||
# +2 year, 1st of the month, strict JAN/YEAR%2
|
||||
$p = Period::details(5,1,strtotime('2012-02-29'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-12-31')),$p['end']);
|
||||
|
||||
$p = Period::details(5,1,strtotime('2012-01-31'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-12-31')),$p['end']);
|
||||
|
||||
$p = Period::details(5,1,strtotime('2013-01-31'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2014-12-31')),$p['end']);
|
||||
|
||||
$p = Period::details(5,1,strtotime('2012-12-31'),TRUE,TRUE);
|
||||
$this->assertEquals(date('d-M-Y',strtotime('2013-12-31')),$p['end']);
|
||||
}
|
||||
}
|
||||
?>
|
@ -9,11 +9,9 @@
|
||||
|
||||
<?php echo Form::input('email',$o->display('email'),array('label'=>'Email','class'=>'input-xxlarge','placeholder'=>'Email Address','type'=>'email','required')); ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="span1">
|
||||
<?php echo Form::select('title',StaticList_Title::table(),$o->display('title'),array('class'=>'input-small','label'=>'Title','required')); ?>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="span2">
|
||||
<?php echo Form::input('first_name',$o->display('first_name'),array('label'=>'','class'=>'input-medium','placeholder'=>'First Name','required')); ?>
|
||||
</div>
|
||||
@ -21,7 +19,6 @@
|
||||
<div class="span3">
|
||||
<?php echo Form::input('last_name',$o->display('last_name'),array('label'=>'','class'=>'input-large','placeholder'=>'Last Name','required')); ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php echo Form::input('company',$o->display('company'),array('label'=>'Company','class'=>'input-xxlarge','placeholder'=>'Company Name')); ?>
|
||||
|
@ -18,7 +18,7 @@ class Task_Adsl_Trafficget extends Minion_Task {
|
||||
|
||||
protected function _execute(array $params) {
|
||||
foreach ($this->_traffic_suppliers(TRUE) as $aso) {
|
||||
if (Minion_CLI::options('verbose'))
|
||||
if ($params['verbose'])
|
||||
echo $aso->name."\n";
|
||||
|
||||
Service_Traffic_Adsl::instance($aso->name)->update_traffic();
|
||||
|
@ -1,133 +0,0 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class provides charge capabilities.
|
||||
*
|
||||
* @package Charge
|
||||
* @category Controllers/Admin
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Controller_Admin_Charge extends Controller_TemplateDefault_Admin {
|
||||
protected $secure_actions = array(
|
||||
'add'=>TRUE,
|
||||
'list'=>TRUE,
|
||||
'auditinvoiceitems'=>TRUE,
|
||||
);
|
||||
|
||||
/**
|
||||
* Show a list of invoices
|
||||
*/
|
||||
public function action_list() {
|
||||
Block::add(array(
|
||||
'title'=>_('Customer Charges'),
|
||||
'body'=>Table::display(
|
||||
ORM::factory('Charge')->where('sweep_type','>=',0)->order_by('date_orig DESC')->find_all(),
|
||||
25,
|
||||
array(
|
||||
'id'=>array('label'=>'ID','url'=>URL::link('user','charge/view/')),
|
||||
'date_orig'=>array('label'=>'Date'),
|
||||
'sweep_type'=>array('label'=>'Sweep'),
|
||||
'status'=>array('label'=>'Status'),
|
||||
'quantity'=>array('label'=>'Quantity','class'=>'right'),
|
||||
'amount'=>array('label'=>'Total','class'=>'right'),
|
||||
'description'=>array('label'=>'Description'),
|
||||
'service_id'=>array('label'=>'Service'),
|
||||
'account->accnum()'=>array('label'=>'Cust ID'),
|
||||
'account->name()'=>array('label'=>'Customer'),
|
||||
'attributes'=>array('label'=>'Attributes'),
|
||||
),
|
||||
array(
|
||||
'page'=>TRUE,
|
||||
'type'=>'select',
|
||||
'form'=>URL::link('user','charge/view'),
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
public function action_add() {
|
||||
$output = '';
|
||||
|
||||
$co = ORM::factory('Charge');
|
||||
|
||||
if ($_POST) {
|
||||
// Trim down our attributes
|
||||
if (is_array($_POST['attributes']))
|
||||
foreach ($_POST['attributes'] as $k=>$v)
|
||||
if (! trim($v))
|
||||
unset($_POST['attributes'][$k]);
|
||||
|
||||
if ($co->values($_POST)->check()) {
|
||||
$co->status=0;
|
||||
|
||||
// Entry updated
|
||||
if (! $co->save())
|
||||
throw new Kohana_Exception('Unable to save charge');
|
||||
}
|
||||
}
|
||||
|
||||
$output .= Form::open();
|
||||
$output .= View::factory($this->viewpath());
|
||||
$output .= Form::submit('submit','submit');
|
||||
$output .= Form::close();
|
||||
|
||||
Style::add(array(
|
||||
'type'=>'stdin',
|
||||
'data'=>'.ui-autocomplete-loading { background: white url("'.URL::site('media/img/ui-anim_basic_16x16.gif').'") right center no-repeat; }'
|
||||
));
|
||||
|
||||
Style::add(array(
|
||||
'type'=>'file',
|
||||
'data'=>'media/js/jquery.ui/css/smoothness/jquery-ui-1.8.16.custom.css',
|
||||
));
|
||||
|
||||
Script::add(array(
|
||||
'type'=>'file',
|
||||
'data'=>'media/js/jquery-ui-1.8.16.custom.min.js',
|
||||
));
|
||||
|
||||
Script::add(array('type'=>'stdin','data'=>'
|
||||
$(document).ready(function() {
|
||||
$("input[name=account_id]").autocomplete({
|
||||
source: "'.URL::link('admin','account/ajaxlist').'",
|
||||
minLength: 2,
|
||||
change: function(event,ui) {
|
||||
// Send the request and update sub category dropdown
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
data: "aid="+$(this).val(),
|
||||
dataType: "json",
|
||||
cache: false,
|
||||
url: "'.URL::link('admin','service/ajaxlist',TRUE).'",
|
||||
timeout: 2000,
|
||||
error: function() {
|
||||
alert("Failed to submit");
|
||||
},
|
||||
success: function(data) {
|
||||
// Clear all options from sub category select
|
||||
$("select[name=service_id] option").remove();
|
||||
|
||||
// Prepopulate a blank
|
||||
var row = "<option value=\"\"> </option>";
|
||||
$(row).appendTo("select[name=service_id]");
|
||||
|
||||
// Fill sub category select
|
||||
$.each(data, function(i, j){
|
||||
var row = "<option value=\"" + j.value + "\">" + j.label + "</option>";
|
||||
$(row).appendTo("select[name=service_id]");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});'
|
||||
));
|
||||
|
||||
Block::add(array(
|
||||
'title'=>_('Add Customer Charges'),
|
||||
'body'=>$output,
|
||||
));
|
||||
}
|
||||
}
|
||||
?>
|
14
modules/charge/classes/Controller/Charge.php
Normal file
14
modules/charge/classes/Controller/Charge.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class provides item charging management
|
||||
*
|
||||
* @package Charge
|
||||
* @category Controllers
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Controller_Charge extends Controller_TemplateDefault {
|
||||
}
|
||||
?>
|
171
modules/charge/classes/Controller/Reseller/Charge.php
Normal file
171
modules/charge/classes/Controller/Reseller/Charge.php
Normal file
@ -0,0 +1,171 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class provides charge capabilities.
|
||||
*
|
||||
* @package Charge
|
||||
* @category Controllers/Reseller
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Controller_Reseller_Charge extends Controller_Charge {
|
||||
protected $secure_actions = array(
|
||||
'add'=>TRUE,
|
||||
'ajaxlist'=>TRUE,
|
||||
'ajaxlistservice'=>TRUE,
|
||||
'edit'=>TRUE,
|
||||
'list'=>TRUE,
|
||||
);
|
||||
|
||||
public function action_add() {
|
||||
Block::factory()
|
||||
->type('form-horizontal')
|
||||
->title('Add/View Charge')
|
||||
->title_icon('icon-wrench')
|
||||
->body($this->add_edit());
|
||||
}
|
||||
|
||||
public function action_ajaxlist() {
|
||||
$result = array();
|
||||
|
||||
if (isset($_REQUEST['term']) AND trim($_REQUEST['term'])) {
|
||||
$result = Arr::merge($result,ORM::factory('Account')->list_autocomplete($_REQUEST['term'],'id','id',array('ACC %s: %s'=>array('id','name(TRUE)'))));
|
||||
$result = Arr::merge($result,ORM::factory('Service')->list_autocomplete($_REQUEST['term'],'account_id','id',array('ACC %s: %s (%s)'=>array('account_id','account->name()','name()'))));
|
||||
|
||||
foreach (array('Service_Plugin_Adsl','Service_Plugin_Domain','Service_Plugin_Host') as $o)
|
||||
$result = Arr::merge($result,ORM::factory($o)->list_autocomplete($_REQUEST['term'],'account_id','service->account_id',array('ACC %s: %s (%s)'=>array('service->account_id','service->account->name()','name()'))));
|
||||
}
|
||||
|
||||
$this->response->headers('Content-Type','application/json');
|
||||
$this->response->body(json_encode(array_values($result)));
|
||||
}
|
||||
|
||||
public function action_ajaxlistservice() {
|
||||
$result = array();
|
||||
|
||||
if (isset($_REQUEST['key']) AND trim($_REQUEST['key']))
|
||||
$result = Arr::merge($result,ORM::factory('Service')->list_autocomplete('','id','id',array('SVC %s: %s'=>array('id','service_name()')),array(array('account_id','=',$_REQUEST['key']))));
|
||||
|
||||
$this->response->headers('Content-Type','application/json');
|
||||
$this->response->body(json_encode(array_values($result)));
|
||||
}
|
||||
|
||||
private function add_edit($id=NULL,$output='') {
|
||||
$co = ORM::factory('Charge',$id);
|
||||
|
||||
if ($_POST) {
|
||||
// Entry updated
|
||||
if ($co->values($_POST)->check() AND $co->save())
|
||||
SystemMessage::factory()
|
||||
->title('Record updated')
|
||||
->type('success')
|
||||
->body(_('Your Charge record has been recorded/updated.'));
|
||||
}
|
||||
|
||||
Script::factory()
|
||||
->type('file')
|
||||
->data('media/theme/bootstrap/vendor/datepicker/js/bootstrap-datepicker.js');
|
||||
|
||||
Style::factory()
|
||||
->type('file')
|
||||
->data('media/theme/bootstrap/vendor/datepicker/css/datepicker.css');
|
||||
|
||||
Script::factory()
|
||||
->type('stdin')
|
||||
->data('
|
||||
$(document).ready(function() {
|
||||
var nowTemp = new Date();
|
||||
var now = new Date(nowTemp.getFullYear(), nowTemp.getMonth(), nowTemp.getDate(), 0, 0, 0, 0);
|
||||
|
||||
$("#date_charge_label").datepicker({
|
||||
autoclose : true,
|
||||
endDate : now,
|
||||
format : "dd-mm-yyyy",
|
||||
todayBtn : true,
|
||||
}).on("hide",function(ev) {
|
||||
$("input[name=date_charge]").val(ev.date.valueOf()/1000);
|
||||
});
|
||||
|
||||
$("input[name=account_id_label]").typeahead({
|
||||
minLength: 2,
|
||||
source: function (query,process) {
|
||||
search("'.URL::link('reseller','charge/ajaxlist').'",query,process);
|
||||
},
|
||||
|
||||
matcher: function () { return true; },
|
||||
|
||||
updater: function (item) {
|
||||
$("input[name=account_id]").val(users[item]);
|
||||
|
||||
// Send the request and update sub category dropdown
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
data: "key="+users[item],
|
||||
dataType: "json",
|
||||
cache: false,
|
||||
url: "'.URL::link('reseller','charge/ajaxlistservice',TRUE).'",
|
||||
timeout: 2000,
|
||||
error: function(x) {
|
||||
alert("Failed to submit");
|
||||
},
|
||||
success: function(data) {
|
||||
$.each(data, function(i, j){
|
||||
var row = "<option value=\"" + j.value + "\">" + j.label + "</option>";
|
||||
$(row).appendTo("select[name=service_id]");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return item;
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
');
|
||||
|
||||
return View::factory('charge/reseller/add_edit')
|
||||
->set('o',$co);
|
||||
}
|
||||
|
||||
public function action_edit() {
|
||||
list($id,$output) = Table::page(__METHOD__);
|
||||
|
||||
Block::factory()
|
||||
->type('form-horizontal')
|
||||
->title(sprintf('%s: %s',_('View Charges'),$id))
|
||||
->title_icon('icon-wrench')
|
||||
->body($this->add_edit($id,$output));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of invoices
|
||||
*/
|
||||
public function action_list() {
|
||||
Block::factory()
|
||||
->title('Customer Charges')
|
||||
->title_icon('icon-th-list')
|
||||
->body(Table::factory()
|
||||
->page_items(50)
|
||||
->data(ORM::factory('Charge')->where('account_id','IN',$this->ao->RTM->customers($this->ao->RTM))->order_by('id DESC')->find_all())
|
||||
->columns(array(
|
||||
'id'=>'ID',
|
||||
'date_orig'=>'Processed',
|
||||
'date_charge'=>'Date',
|
||||
'sweep_type'=>'Sweep',
|
||||
'status'=>'Status',
|
||||
'quantity'=>'Quantity',
|
||||
'amount'=>'Amount',
|
||||
'description'=>'Description',
|
||||
'service_id'=>'Service',
|
||||
'account->accnum()'=>'Cust ID',
|
||||
'account->name()'=>'Customer',
|
||||
))
|
||||
->prepend(array(
|
||||
'id'=>array('url'=>URL::link('reseller','charge/edit/')),
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
?>
|
@ -10,21 +10,25 @@
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Model_Charge extends ORM_OSB {
|
||||
// Charge doesnt use the update column
|
||||
protected $_updated_column = FALSE;
|
||||
protected $_belongs_to = array(
|
||||
'account'=>array(),
|
||||
);
|
||||
|
||||
protected $_nullifempty = array(
|
||||
'attributes',
|
||||
);
|
||||
|
||||
protected $_serialize_column = array(
|
||||
'attributes',
|
||||
);
|
||||
|
||||
protected $_belongs_to = array(
|
||||
'account'=>array(),
|
||||
);
|
||||
|
||||
protected $_display_filters = array(
|
||||
'date_orig'=>array(
|
||||
array('Config::date',array(':value')),
|
||||
),
|
||||
'date_charge'=>array(
|
||||
array('Config::date',array(':value')),
|
||||
),
|
||||
'amount'=>array(
|
||||
array('Currency::display',array(':value')),
|
||||
),
|
||||
|
@ -1,37 +0,0 @@
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td>Account</td>
|
||||
<td><?php echo Form::input('account_id',''); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Service</td>
|
||||
<td><?php echo Form::select('service_id',array('NONE')); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sweep</td>
|
||||
<td><?php echo StaticList_SweepType::form('sweep_type',6); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Quantity</td>
|
||||
<td><?php echo Form::input('quantity',NULL); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Amount</td>
|
||||
<td><?php echo Form::input('amount',NULL); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Taxable</td>
|
||||
<td><?php echo StaticList_YesNo::form('taxable',true); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Description</td>
|
||||
<td><?php echo Form::input('description',NULL); ?></td>
|
||||
</tr>
|
||||
<!-- @todo This to be dynamic -->
|
||||
<?php for($x=0;$x<10;$x++) { ?>
|
||||
<tr>
|
||||
<td>Attributes</td>
|
||||
<td><?php echo Form::input('attributes['.$x.']',NULL); ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</table>
|
31
modules/charge/views/charge/reseller/add_edit.php
Normal file
31
modules/charge/views/charge/reseller/add_edit.php
Normal file
@ -0,0 +1,31 @@
|
||||
<div class="row">
|
||||
<div class="span9 offset1">
|
||||
|
||||
<fieldset>
|
||||
<legend>Charge Details</legend>
|
||||
|
||||
<div class="input-append date" id="date_charge_label">
|
||||
<?php echo Form::input('date_charge_label',$o->display('date_charge'),array('class'=>'span2','label'=>'Date of Charge','add-on'=>'<i class="icon-calendar"></i>','disabled')); ?>
|
||||
</div>
|
||||
|
||||
<?php echo Form::hidden('date_charge',$o->date_charge); ?>
|
||||
<?php echo Form::input('account_id_label',$o->account->name(),array('class'=>'span5','label'=>'Account','placeholder'=>'Account','data-provide'=>'typeahead','required')); ?>
|
||||
<?php echo Form::hidden('account_id',$o->account_id); ?>
|
||||
<?php echo Form::select('service_id',$o->account_id ? $o->account->service->list_select() : array(),$o->service_id,array('class'=>'span5','label'=>'Service')); ?>
|
||||
<?php echo StaticList_SweepType::form('sweep_type',is_null($o->sweep_type) ? 6 : $o->sweep_type,FALSE,array('label'=>'Sweep')); ?>
|
||||
<?php echo StaticList_ItemType::form('type',is_null($o->type) ? 6 : $o->type,FALSE,array('label'=>'Item Type')); ?>
|
||||
|
||||
<?php echo Form::input('quantity',$o->quantity,array('class'=>'span1','label'=>'Quantity','placeholder'=>'Quantity')); ?>
|
||||
<?php echo Form::input('amount',$o->amount,array('class'=>'span1','label'=>'Amount','placeholder'=>'Total',)); ?>
|
||||
<?php echo StaticList_YesNo::form('taxable',is_null($o->taxable) ? TRUE : $o->taxable,FALSE,array('label'=>'Taxable','class'=>'span1')); ?>
|
||||
<?php echo Form::input('description',$o->description,array('class'=>'span5','label'=>'Description','placeholder'=>'Any notes about this charge?')); ?>
|
||||
|
||||
<!-- @todo Use JS to dynamically add more lines as required -->
|
||||
<?php for ($i=0;$i<10;$i++) :
|
||||
echo Form::input("attributes[$i]",isset($o->attributes[$i]) ? $o->attributes[$i] : "",array('class'=>'span5','label'=>'Attributes'));
|
||||
endfor ?>
|
||||
</fieldset>
|
||||
|
||||
<?php echo Form::button('submit','Submit',array('class'=>'btn btn-primary')); ?>
|
||||
</div> <!-- /span -->
|
||||
</div> <!-- /row -->
|
@ -10,7 +10,7 @@
|
||||
<dd><?php echo $o->display('domain_expire'); ?></dd>
|
||||
|
||||
<dt>Domain Auth Password</dt>
|
||||
<dd><?php echo $o->display('registrar_auth_password'); ?></dd>
|
||||
<dd><?php echo ! $o->service->expiring() ? $o->display('registrar_auth_password') : 'EXPIRED'; ?></dd>
|
||||
|
||||
<?php if ($x=$o->manage_button()) : ?>
|
||||
<dt>Registrar</dt>
|
||||
|
@ -12,155 +12,6 @@
|
||||
class Controller_Task_Invoice extends Controller_Task {
|
||||
public $auto_render = FALSE;
|
||||
|
||||
/**
|
||||
* Email a customers a reminder of their upcoming invoices that are due.
|
||||
*/
|
||||
public function action_remind_due() {
|
||||
$action = array();
|
||||
$key = 'remind_due';
|
||||
$days = ORM::factory('Invoice')->config('REMIND_DUE');
|
||||
|
||||
foreach (ORM::factory('Invoice')->list_due(time()+86400*$days) as $io) {
|
||||
// @todo Use another option to supress reminders
|
||||
// If we have already sent a reminder, we'll skip to the next one.
|
||||
if (($io->remind($key) AND (is_null($x=$this->request->param('id')) OR $x != 'again')) OR ($io->account->invoice_delivery != 1))
|
||||
continue;
|
||||
|
||||
// Send our email
|
||||
$et = Email_Template::instance('task_invoice_'.$key);
|
||||
|
||||
$et->to = array('account'=>array($io->account_id));
|
||||
$et->variables = array(
|
||||
'DUE'=>$io->due(TRUE),
|
||||
'DUE_DATE'=>$io->display('due_date'),
|
||||
'FIRST_NAME'=>$io->account->first_name,
|
||||
'INV_NUM'=>$io->refnum(),
|
||||
'INV_URL'=>URL::site(URL::link('user','invoice/view/'.$io->id),'http'),
|
||||
'SITE_NAME'=>Company::instance()->name(),
|
||||
);
|
||||
|
||||
// @todo Record email log id if possible.
|
||||
if ($et->send()) {
|
||||
$io->set_remind($key,time());
|
||||
array_push($action,(string)$io);
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->body(_('Due Reminders Sent: ').join('|',$action));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate our services invoices, based on the service next invoice date
|
||||
*
|
||||
* @param int ID Service ID to generate invoice for (optional) - multiple services colon separated
|
||||
*/
|
||||
public function action_services() {
|
||||
// Used to only process X invoices in a row.
|
||||
$max = ($x=Kohana::$config->load('debug')->invoice) ? $x : ORM::factory('Invoice')->config('GEN_INV_MAX');
|
||||
// Our service next billing dates that need to be updated if this is successful.
|
||||
$snd = array();
|
||||
// Our charges that need to be updated if this is successful.
|
||||
$chgs = array();
|
||||
// If we are invoicing a specific service
|
||||
$sid = is_null($this->request->param('id')) ? NULL : explode(':',$this->request->param('id'));
|
||||
// Sort our service by account_id, then we can generate 1 invoice.
|
||||
$svs = ORM::factory('Service')->list_invoicesoon()->as_array();
|
||||
Sort::MAsort($svs,'account_id,date_next_invoice');
|
||||
|
||||
$aid = $due = $io = NULL;
|
||||
$max_count = 0;
|
||||
foreach ($svs as $so) {
|
||||
// If we are generating an invoice for a service, skip to that service.
|
||||
if (! is_null($sid) AND ! in_array($so->id,$sid))
|
||||
continue;
|
||||
|
||||
// Close off invoice, and start a new one.
|
||||
if (is_null($io) OR (! is_null($aid) AND $aid != $so->account_id) OR (! is_null($due) AND $due != $io->min_due($so->date_next_invoice))) {
|
||||
// Close this invoice.
|
||||
if (is_object($io)) {
|
||||
// Save our invoice.
|
||||
if (! $io->save())
|
||||
throw new Kohana_Exception('Failed to save invoice :invoice for service :service',array(':invoice'=>$io->id,':service'=>$so->id));
|
||||
}
|
||||
|
||||
// If we have issued the max number of invoices this round, finish.
|
||||
if ($max AND (++$max_count > $max))
|
||||
break;
|
||||
|
||||
// Start a new invoice.
|
||||
$io = ORM::factory('Invoice');
|
||||
$io->due_date = $due = $io->min_due($so->date_next_invoice);
|
||||
$io->account_id = $aid = $so->account_id;
|
||||
$io->status = TRUE;
|
||||
}
|
||||
|
||||
$pdata = Period::details($so->recur_schedule,$so->product->price_recurr_weekday,$so->date_next_invoice,TRUE);
|
||||
|
||||
$iio = $io->add_item();
|
||||
$iio->service_id = $so->id;
|
||||
$iio->product_id = $so->product_id;
|
||||
$iio->quantity = $pdata['prorata'];
|
||||
$iio->item_type = 0; // Service Billing
|
||||
$iio->discount_amt = NULL; // @todo
|
||||
$iio->price_base = $so->price();
|
||||
$iio->recurring_schedule = $so->recur_schedule;
|
||||
$iio->date_start = $pdata['start_time'];
|
||||
$iio->date_stop = $pdata['end_time'];
|
||||
|
||||
// Our service next billing date, if this invoice generation is successful.
|
||||
$snd[$so->id] = $pdata['end_time']+86400;
|
||||
|
||||
// Check if there are any charges
|
||||
$c = ORM::factory('Charge')
|
||||
->where('service_id','=',$so->id)
|
||||
->where('status','=',0)
|
||||
->where('sweep_type','=',6); // @todo This needs to be dynamic, not "6"
|
||||
|
||||
foreach ($c->find_all() as $co) {
|
||||
$iio = $io->add_item();
|
||||
$iio->service_id = $co->service_id;
|
||||
$iio->product_id = $co->product_id;
|
||||
$iio->charge_id = $co->id;
|
||||
$iio->quantity = $co->quantity;
|
||||
$iio->item_type = 5; // @todo This probably should not be hard coded as "5".
|
||||
$iio->discount_amt = NULL; // @todo
|
||||
$iio->price_base = $co->amount;
|
||||
$iio->date_start = $co->date_orig;
|
||||
$iio->date_stop = $co->date_orig; // @todo
|
||||
|
||||
// @todo Temp
|
||||
// We'll mark any charges as temporarily processed, although they should be set to status=1 later.
|
||||
$co->status=2;
|
||||
$co->save();
|
||||
array_push($chgs,$co->id);
|
||||
}
|
||||
}
|
||||
|
||||
// Save our invoice.
|
||||
if ($io AND ! $io->saved() AND ! $io->save()) {
|
||||
print_r($io->items());
|
||||
throw new Kohana_Exception('Failed to save invoice :invoice for service :service',array(':invoice'=>$io->id,':service'=>$so->id));
|
||||
}
|
||||
|
||||
// Update our service next billing dates.
|
||||
// @todo Catch any update errors
|
||||
foreach ($snd as $sid=>$date) {
|
||||
$so = ORM::factory('Service',$sid);
|
||||
$so->date_next_invoice = $date;
|
||||
$so->save();
|
||||
}
|
||||
|
||||
// Update any processed charges as such
|
||||
// @todo Catch any update errors
|
||||
foreach ($chgs as $cid) {
|
||||
$co = ORM::factory('Charge',$cid);
|
||||
$co->status=1;
|
||||
$co->save();
|
||||
}
|
||||
|
||||
$this->response->body(_('Services Invoiced: ').join('|',array_keys($snd)));
|
||||
}
|
||||
|
||||
public function action_send() {
|
||||
// Used to only process X invoices in a row.
|
||||
$max = ORM::factory('Invoice')->config('EMAIL_INV_MAX');
|
||||
|
@ -67,7 +67,7 @@ class Controller_User_Invoice extends Controller_Invoice {
|
||||
->set('o',$io);
|
||||
|
||||
if ($io->due() AND ! $io->cart_exists())
|
||||
$output .= View::factory('/invoice/user/view/pay')
|
||||
$output .= View::factory('invoice/user/view/pay')
|
||||
->set('mid',$io->mid())
|
||||
->set('o',$io);
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This interface ensures that all invoice processing objects have the right methods
|
||||
*
|
||||
* @package Invoice
|
||||
* @category Interface
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
interface Invoicable {
|
||||
// Render the line item for an invoice
|
||||
public function invoice_line();
|
||||
}
|
||||
?>
|
@ -13,8 +13,26 @@ class Invoice {
|
||||
// This invoice Object
|
||||
private $io;
|
||||
|
||||
private $_methods = array(
|
||||
'min_due',
|
||||
'save',
|
||||
'saved',
|
||||
);
|
||||
|
||||
// Enable passing calls to ORM::Invoice()
|
||||
public function __call($method,array $args) {
|
||||
if (in_array($method,$this->_methods))
|
||||
return call_user_func_array(array($this->io,$method),$args);
|
||||
else
|
||||
throw HTTP_Exception::factory(501,'Unknown/unauthorised method :method',array(':method'=>$method));
|
||||
}
|
||||
|
||||
public function __construct(Model_Invoice $io=NULL) {
|
||||
$this->io = is_null($io) ? ORM::factory('Invoice') : $io;
|
||||
|
||||
// Set our invoice as valid
|
||||
if (is_null($io))
|
||||
$this->io->status = 1;
|
||||
}
|
||||
|
||||
public static function instance(Model_Invoice $io=NULL) {
|
||||
@ -27,6 +45,19 @@ class Invoice {
|
||||
* @param $so Model_Servie
|
||||
*/
|
||||
public function add_service(Model_Service $so) {
|
||||
if ($this->io->loaded())
|
||||
throw HTTP_Exception::factory(501,'Cannot use add service :service to an existing invoice :invoice ',array(':service'=>$so->id,':invoice'=>$this->io->id));
|
||||
|
||||
if (! $this->io->account_id)
|
||||
$this->io->account_id = $so->account_id;
|
||||
|
||||
else if ($this->io->account_id != $so->account_id)
|
||||
throw HTTP_Exception::factory(501,'Cannot add service :service to invoice - it is for a different account',array(':service'=>$so->id));
|
||||
|
||||
// Set the invoice due date
|
||||
if (! $this->io->due_date OR $this->io->due_date > $this->io->min_due($so->date_next_invoice))
|
||||
$this->io->due_date = $this->io->min_due($so->date_next_invoice);
|
||||
|
||||
$pdata = Period::details($so->recur_schedule,$so->product->price_recurr_day,$so->invoiced_to()+86400,FALSE,$so->product->price_recurr_strict);
|
||||
|
||||
$iio = ORM::factory('Invoice_Item');
|
||||
@ -39,13 +70,14 @@ class Invoice {
|
||||
$iio->date_stop = $pdata['end_time'];
|
||||
|
||||
// Service Billing
|
||||
$iio->item_type = StaticList_ItemType::index('MAIN');
|
||||
$iio->item_type = 0;
|
||||
|
||||
$this->io->add_item($iio);
|
||||
|
||||
// Check if there are any charges
|
||||
$c = ORM::factory('Charge')
|
||||
->where('service_id','=',$so->id)
|
||||
->where('void','is',NULL)
|
||||
->where('processed','is',NULL);
|
||||
|
||||
foreach ($c->find_all() as $co) {
|
||||
@ -57,9 +89,7 @@ class Invoice {
|
||||
$iio->price_base = $co->amount;
|
||||
$iio->date_start = $co->date_orig;
|
||||
$iio->date_stop = $co->date_orig;
|
||||
|
||||
// @todo This should be $co->item_type;
|
||||
$iio->item_type = StaticList_ItemType::index('EXCESS');
|
||||
$iio->item_type = $co->type;
|
||||
|
||||
$this->io->add_item($iio);
|
||||
}
|
||||
@ -67,12 +97,13 @@ class Invoice {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render($type,$section) {
|
||||
public function render($type,$section,$args=array()) {
|
||||
switch ($type) {
|
||||
case 'html':
|
||||
switch ($section) {
|
||||
case 'body':
|
||||
return View::factory('invoice/user/view/body')
|
||||
->set('show_id',(isset($args['noid']) AND $args['noid']) ? FALSE : TRUE)
|
||||
->set('o',$this->io);
|
||||
break;
|
||||
|
||||
|
@ -38,8 +38,9 @@ class Model_Invoice extends ORM_OSB implements Cartable {
|
||||
);
|
||||
|
||||
// Items belonging to an invoice
|
||||
private $invoice_items = array();
|
||||
private $invoice_items_unsorted = TRUE;
|
||||
protected $_sub_items_load = array(
|
||||
'invoice_item'=>'service_id,item_type',
|
||||
);
|
||||
|
||||
/** INTERFACE REQUIREMENTS **/
|
||||
public function cart_item() {
|
||||
@ -53,32 +54,21 @@ class Model_Invoice extends ORM_OSB implements Cartable {
|
||||
return count(Cart::instance()->get($this->mid(),$this->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept our object load, so that we can load our subitems
|
||||
*/
|
||||
protected function _load_values(array $values) {
|
||||
parent::_load_values($values);
|
||||
|
||||
if ($this->_loaded)
|
||||
$this->invoice_items = $this->invoice_item->find_all()->as_array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to an invoice
|
||||
*/
|
||||
public function add_item(Model_Invoice_Item $iio=NULL) {
|
||||
// @todo This is the old calling of this function, which should be removed
|
||||
if (is_null($iio)) {
|
||||
$c = count($this->invoice_items);
|
||||
$c = count($this->_sub_items);
|
||||
|
||||
$this->invoice_items[$c] = ORM::factory('Invoice_Item');
|
||||
$this->_sub_items[$c] = ORM::factory('Invoice_Item');
|
||||
|
||||
return $this->invoice_items[$c];
|
||||
return $this->_sub_items[$c];
|
||||
}
|
||||
|
||||
array_push($this->invoice_items,$iio);
|
||||
array_push($this->_sub_items,$iio);
|
||||
$this->_sub_items_sorted = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +76,7 @@ class Model_Invoice extends ORM_OSB implements Cartable {
|
||||
*
|
||||
* @param $period Return an Array of items for that period
|
||||
*/
|
||||
public function items_periods($period=NULL) {
|
||||
public function items_periods($period=FALSE) {
|
||||
$result = array();
|
||||
|
||||
foreach ($this->items() as $ito) {
|
||||
@ -94,11 +84,56 @@ class Model_Invoice extends ORM_OSB implements Cartable {
|
||||
if ($ito->item_type != 0)
|
||||
continue;
|
||||
|
||||
if (is_null($period) AND ! in_array($ito->recurring_schedule,$result))
|
||||
if ($period === FALSE AND ! in_array($ito->recurring_schedule,$result))
|
||||
array_push($result,$ito->recurring_schedule);
|
||||
elseif ($ito->recurring_schedule == $period)
|
||||
|
||||
elseif ($ito->recurring_schedule == $period) {
|
||||
// If we have this service already, we'll skip
|
||||
if (! Object::in_array('service_id',$ito->service_id,$result))
|
||||
array_push($result,$ito);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the item titles that are on an invoice
|
||||
*
|
||||
* @param $title Return an Array of items for that title
|
||||
*/
|
||||
public function items_titles($title=NULL,$period=NULL) {
|
||||
$result = array();
|
||||
|
||||
foreach ($this->items() as $ito) {
|
||||
if ($ito->service_id) {
|
||||
if (is_null($title) AND ! in_array($ito->title(),$result) AND (is_null($period) OR ($period == $ito->recurring_schedule)))
|
||||
array_push($result,$ito->title());
|
||||
elseif (($ito->title() == $title AND (is_null($period) OR ($period == $ito->recurring_schedule))) OR is_null($ito->recurring_schedule))
|
||||
array_push($result,$ito);
|
||||
|
||||
} else {
|
||||
throw HTTP_Exception::factory(501,'Not handled non-services');
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the service items on an invoice relating to an invoice_item
|
||||
* IE: item_type == 0
|
||||
*/
|
||||
public function service_items(Model_Invoice_Item $o) {
|
||||
$result = array();
|
||||
|
||||
// At the moment, we only return items pertaining to a service
|
||||
if (! $o->service_id)
|
||||
return $result;
|
||||
|
||||
foreach ($this->items() as $iio)
|
||||
if ($iio->item_type == 0 AND $iio->service_id == $o->service_id)
|
||||
array_push($result,$iio);
|
||||
|
||||
return $result;
|
||||
}
|
||||
@ -195,7 +230,7 @@ class Model_Invoice extends ORM_OSB implements Cartable {
|
||||
public function items($type='ALL') {
|
||||
$result = array();
|
||||
|
||||
foreach ($this->invoice_items as $ito) {
|
||||
foreach ($this->_sub_items as $ito) {
|
||||
$return = FALSE;
|
||||
|
||||
switch ($type) {
|
||||
@ -429,8 +464,10 @@ class Model_Invoice extends ORM_OSB implements Cartable {
|
||||
// Our items will be clobbered once we save the object, so we need to save it here.
|
||||
$items = $this->items();
|
||||
|
||||
// If this is a new invoice, we'll need to do more work
|
||||
$new = ! $this->loaded();
|
||||
|
||||
// Save the invoice
|
||||
if ($this->changed())
|
||||
parent::save($validation);
|
||||
|
||||
// Need to save the associated items and their taxes
|
||||
@ -453,6 +490,27 @@ class Model_Invoice extends ORM_OSB implements Cartable {
|
||||
throw new Kohana_Exception('Problem saving invoice_item for invoice :invoice - Failed save()',array(':invoice'=>$this->id));
|
||||
}
|
||||
|
||||
// If this is a new invoice, we'll need to update some other items
|
||||
if ($new) {
|
||||
// Update next invoice date
|
||||
if ($iio->item_type == 0) {
|
||||
$iio->service->date_next_invoice = $iio->date_stop+86400;
|
||||
|
||||
// @todo Mark invoice as cancelled and write a memo, then...
|
||||
if (! $iio->service->save())
|
||||
throw new Kohana_Exception('Problem saving service :service for invoice_item :invoice_item - Failed save()',array(':invoice_item'=>$iio->id,':service'=>$iio->service_id));
|
||||
}
|
||||
|
||||
// Update charge iteme
|
||||
if ($iio->charge_id) {
|
||||
$iio->charge->processed = 1;
|
||||
|
||||
// @todo Mark invoice as cancelled and write a memo, then...
|
||||
if (! $iio->charge->save())
|
||||
throw new Kohana_Exception('Problem saving charge :charge for invoice_item :invoice_item - Failed save()',array(':invoice_item'=>$iio->id,':charge'=>$iio->charge_id));
|
||||
}
|
||||
}
|
||||
|
||||
// @todo Need to save discount information
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
* Column Definitions:
|
||||
* + item_type: 0=MAIN Service Item,2=?,3=?,4=Connection/Setup,5=Excess Service Item,6=Change Service,126=Payment Fee,127=Late Fee
|
||||
*/
|
||||
class Model_Invoice_Item extends ORM_OSB implements Invoicable {
|
||||
class Model_Invoice_Item extends ORM_OSB {
|
||||
// Relationships
|
||||
protected $_belongs_to = array(
|
||||
'product'=>array(),
|
||||
@ -38,11 +38,21 @@ class Model_Invoice_Item extends ORM_OSB implements Invoicable {
|
||||
),
|
||||
);
|
||||
|
||||
// Items belonging to an invoice
|
||||
private $subitems = array();
|
||||
private $subitems_loaded = FALSE;
|
||||
// Items belonging to an invoice item
|
||||
protected $_sub_items_load = array(
|
||||
'invoice_item_tax'=>FALSE,
|
||||
);
|
||||
|
||||
/**
|
||||
* The title for invoice items
|
||||
*/
|
||||
public function title() {
|
||||
if ($this->product_id AND $this->service_id)
|
||||
return $this->product_id ? sprintf('%s: %s',$this->product->title(),$this->service->name()) : $this->service->name;
|
||||
else
|
||||
return 'Unknown Item';
|
||||
}
|
||||
|
||||
/** INTERFACE REQUIREMENTS **/
|
||||
public function invoice_line() {
|
||||
if ($this->charge_id)
|
||||
return $this->charge->description.' '.$this->period();
|
||||
@ -52,23 +62,6 @@ class Model_Invoice_Item extends ORM_OSB implements Invoicable {
|
||||
throw HTTP_Exception::factory(501,'Unable to render invoice item :id',array(':id'=>$this->id));
|
||||
}
|
||||
|
||||
public function __construct($id = NULL) {
|
||||
// Load our model.
|
||||
parent::__construct($id);
|
||||
|
||||
return $this->load_sub_items();
|
||||
}
|
||||
|
||||
private function load_sub_items() {
|
||||
// Load our sub items
|
||||
if (! $this->subitems_loaded AND $this->loaded()) {
|
||||
$this->subitems['tax'] = $this->invoice_item_tax->find_all()->as_array();
|
||||
$this->subitems_loaded = TRUE;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Display a transaction number
|
||||
public function trannum() {
|
||||
return sprintf('%03s-%06s',$this->item_type,$this->id);
|
||||
@ -125,7 +118,7 @@ class Model_Invoice_Item extends ORM_OSB implements Invoicable {
|
||||
}
|
||||
|
||||
public function total($format=FALSE) {
|
||||
$result = Currency::round($this->subtotal()+$this->tax()-$this->discount());
|
||||
$result = $this->void ? 0 : Currency::round($this->subtotal()+$this->tax()-$this->discount());
|
||||
|
||||
return $format ? Currency::display($result) : $result;
|
||||
}
|
||||
@ -205,9 +198,9 @@ class Model_Invoice_Item extends ORM_OSB implements Invoicable {
|
||||
if ($this->saved()) {
|
||||
$iito = ORM::factory('Invoice_Item_Tax');
|
||||
|
||||
if ($this->subitems_loaded) {
|
||||
if ($this->_sub_items) {
|
||||
foreach (array('tax') as $i)
|
||||
foreach ($this->subitems[$i] as $io)
|
||||
foreach ($this->_sub_items[$i] as $io)
|
||||
if ($io->changed())
|
||||
$io->save();
|
||||
|
||||
|
64
modules/invoice/classes/Task/Invoice/Service.php
Normal file
64
modules/invoice/classes/Task/Invoice/Service.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* Generate customer invoices for services
|
||||
*
|
||||
* @package Invoice
|
||||
* @category Tasks
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Task_Invoice_Service extends Minion_Task {
|
||||
protected $_options = array(
|
||||
'days'=>1, // Days in advance to generate for
|
||||
'id'=>NULL, // Service invoice to generate for
|
||||
);
|
||||
|
||||
protected function _execute(array $params) {
|
||||
// Used to only process X invoices in a row.
|
||||
$max = ($x=Kohana::$config->load('debug')->invoice) ? $x : ORM::factory('Invoice')->config('GEN_INV_MAX');
|
||||
// Sort our service by account_id, then we can generate 1 invoice.
|
||||
$svs = ORM::factory('Service')->list_invoicesoon($params['days'])->as_array();
|
||||
Sort::MAsort($svs,'account_id');
|
||||
|
||||
$sids = $params['id'] ? explode(':',$params['id']) : array();
|
||||
|
||||
$aid = $io = NULL;
|
||||
$max_count = 0;
|
||||
$action = array();
|
||||
|
||||
foreach ($svs as $so) {
|
||||
// If we are generating an invoice for a service, skip to that service.
|
||||
if ($sids AND ! in_array($so->id,$sids))
|
||||
continue;
|
||||
|
||||
// Close off invoice, and start a new one, if this is for a different account.
|
||||
if (is_null($io) OR (! is_null($aid) AND $aid != $so->account_id)) {
|
||||
// Close and save this invoice.
|
||||
if (is_object($io) AND ! $io->save())
|
||||
throw new Kohana_Exception('Failed to save invoice :invoice for service :service',array(':invoice'=>$io->id,':service'=>$so->id));
|
||||
|
||||
// If we have issued the max number of invoices this round, finish.
|
||||
if ($max AND (++$max_count > $max))
|
||||
break;
|
||||
|
||||
// Start a new invoice.
|
||||
$io = Invoice::instance();
|
||||
$aid = $so->account_id;
|
||||
}
|
||||
|
||||
$io->add_service($so);
|
||||
|
||||
// Record what we have updated.
|
||||
array_push($action,$so->id);
|
||||
}
|
||||
|
||||
// Save our invoice.
|
||||
if ($io AND ! $io->saved() AND ! $io->save())
|
||||
throw new Kohana_Exception('Failed to save invoice :invoice for service :service',array(':invoice'=>$io->id,':service'=>$so->id));
|
||||
|
||||
return _('Services Invoiced: ').join('|',$action);
|
||||
}
|
||||
}
|
||||
?>
|
@ -4,7 +4,6 @@
|
||||
* OSB Configuration - Invoice Driver
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Invoice
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -29,7 +29,7 @@
|
||||
<dd><?php echo $o->display('due_date'); ?></dd>
|
||||
<dt>Current Charges</dt>
|
||||
<dd><?php echo $o->total_charges(TRUE); ?></dd>
|
||||
<dt>Payments Recieved</dt>
|
||||
<dt>Payments Received</dt>
|
||||
<dd><?php echo $o->payments_total(TRUE); ?></dd>
|
||||
<dt>Credits Applied</dt>
|
||||
<dd><?php echo $o->total_credits(TRUE); ?></dd>
|
||||
@ -45,55 +45,7 @@
|
||||
<div class="span11">
|
||||
<h4>Charge Details</h4>
|
||||
|
||||
<table class="table table-striped table-condensed table-hover" id="list-table" border="0">
|
||||
<tbody>
|
||||
<?php foreach ($o->items_periods() as $rs) : ?>
|
||||
<tr><th colspan="5"><?php echo StaticList_RecurSchedule::get($rs); ?></th></tr>
|
||||
|
||||
<?php foreach ($o->items_periods($rs) as $iio) : ?>
|
||||
<?php if ($iio->service_id) : ?>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<!-- @todo product->title() should be changed to show the service_name() for the invoice product item -->
|
||||
<th colspan="2"><?php echo HTML::anchor(URL::link('user','service/view/'.$iio->service_id),$iio->service->id()).' '.$iio->product->title(); ?></th>
|
||||
<th> </th>
|
||||
<th><div class="text-right"><?php echo $o->service_items_total($iio,TRUE); ?></div></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td><?php printf('%s (%s)',$iio->invoice_line(),$iio->display('id')); ?></td>
|
||||
<td><div class="text-right"><?php echo $iio->subtotal(TRUE); ?></div></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
|
||||
<?php if ($x=$o->service_items_extra($iio)) : ?>
|
||||
<?php foreach ($x as $eiio) : ?>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td><?php printf('%s (%s)',$eiio->invoice_line(),$eiio->display('id')); ?></td>
|
||||
<td><div class="text-right"><?php echo $eiio->subtotal(TRUE); ?></div></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td><?php echo 'Taxes'; ?></td>
|
||||
<td><div class="text-right"><?php echo $o->service_items_tax($iio,TRUE); ?></div></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
|
||||
<?php else : ?>
|
||||
<?php endif ?>
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php echo Invoice::instance($o)->render('html','body'); ?>
|
||||
|
||||
</div> <!-- /span -->
|
||||
</div>
|
||||
|
@ -7,22 +7,28 @@
|
||||
<?php if ($iio->service_id) : ?>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th colspan="2"><?php echo $iio->service->service_name(); ?></th>
|
||||
<th colspan="2"><?php echo ($show_id ? HTML::anchor(URL::link('user','service/view/'.$iio->service_id),$iio->service->id()).' ' : '').$iio->service->service_name(); ?></th>
|
||||
<th> </th>
|
||||
<th><div class="text-right"><?php echo $o->service_items_total($iio,TRUE); ?></div></th>
|
||||
</tr>
|
||||
|
||||
<?php if ($x=$o->service_items($iio)) : ?>
|
||||
<?php foreach ($x as $eiio) : ?>
|
||||
<tr>
|
||||
<td colspan="2"> </td>
|
||||
<td><?php echo $iio->invoice_line(); ?></td>
|
||||
<td><div class="text-right"><?php echo $iio->total(TRUE); ?></div></td>
|
||||
<td colspan="1"> </td>
|
||||
<td colspan="1"> </td>
|
||||
<td><?php echo $eiio->invoice_line().($show_id ? " (<small>$eiio->id</small>)" : ''); ?></td>
|
||||
<td><div class="text-right"><?php echo $eiio->total(TRUE); ?></div></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if ($x=$o->service_items_extra($iio)) : ?>
|
||||
<?php foreach ($x as $eiio) : ?>
|
||||
<tr>
|
||||
<td colspan="2"> </td>
|
||||
<td><?php echo $eiio->invoice_line(); ?></td>
|
||||
<td><?php echo $eiio->invoice_line().($show_id ? " (<small>$eiio->id</small>)" : ''); ?></td>
|
||||
<td><div class="text-right"><?php echo $eiio->total(TRUE); ?></div></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit d3627ace8fc427abe493044f387a802dfc7f09d1
|
||||
Subproject commit 9e191ab0be69f296ae3cd2f079aafa80210f6928
|
@ -4,7 +4,6 @@
|
||||
* OAuth Configuration - System Default Configurable Items.
|
||||
*
|
||||
* @package OAuth
|
||||
* @subpackage Facebook
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -131,7 +131,7 @@ $(document).ready(function() {
|
||||
$("input[name=account_id_label]").typeahead({
|
||||
minLength: 2,
|
||||
source: function (query,process) {
|
||||
search("a/payment/ajaxlist",query,process);
|
||||
search("'.URL::link('admin','payment/ajaxlist').'",query,process);
|
||||
},
|
||||
|
||||
matcher: function () { return true; },
|
||||
|
@ -39,34 +39,23 @@ class Model_Payment extends ORM_OSB {
|
||||
),
|
||||
);
|
||||
|
||||
// Items belonging to an invoice
|
||||
private $payment_items = array();
|
||||
private $payment_items_unsorted = TRUE;
|
||||
|
||||
/**
|
||||
* Intercept our object load, so that we can load our subitems
|
||||
*/
|
||||
protected function _load_values(array $values) {
|
||||
parent::_load_values($values);
|
||||
|
||||
if ($this->_loaded)
|
||||
$this->payment_items = $this->payment_item->find_all()->as_array();
|
||||
|
||||
return $this;
|
||||
}
|
||||
// Items belonging to a payment
|
||||
protected $_sub_items_load = array(
|
||||
'payment_item'=>FALSE,
|
||||
);
|
||||
|
||||
/**
|
||||
* Add an item to an payment
|
||||
*/
|
||||
public function add_item(Model_Payment_Item $p=NULL) {
|
||||
$this->payment_items_unsorted = TRUE;
|
||||
$this->_sub_items_sorted = FALSE;
|
||||
|
||||
// Make sure this payment item for an invoice is not already in the list
|
||||
foreach ($this->payment_items as $pio)
|
||||
foreach ($this->_sub_items as $pio)
|
||||
if ($pio->invoice_id == $p->invoice_id)
|
||||
return $pio;
|
||||
|
||||
array_push($this->payment_items,$p);
|
||||
array_push($this->_sub_items,$p);
|
||||
|
||||
return $p;
|
||||
}
|
||||
@ -101,7 +90,7 @@ class Model_Payment extends ORM_OSB {
|
||||
public function invoices() {
|
||||
$result = array();
|
||||
|
||||
foreach ($this->payment_items as $pio)
|
||||
foreach ($this->_sub_items as $pio)
|
||||
array_push($result,$pio->invoice);
|
||||
|
||||
return $result;
|
||||
@ -117,14 +106,14 @@ class Model_Payment extends ORM_OSB {
|
||||
* @see payment_items
|
||||
*/
|
||||
public function items($type='ALL') {
|
||||
if ($this->payment_items_unsorted) {
|
||||
Sort::MAsort($this->payment_items,'invoice_id');
|
||||
$this->payment_items_unsorted = FALSE;
|
||||
if (! $this->_sub_items_sorted) {
|
||||
Sort::MAsort($this->_sub_items,'invoice_id');
|
||||
$this->_sub_items_sorted = TRUE;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
|
||||
foreach ($this->payment_items as $pio) {
|
||||
foreach ($this->_sub_items as $pio) {
|
||||
$return = FALSE;
|
||||
|
||||
switch ($type) {
|
||||
|
@ -11,7 +11,6 @@
|
||||
*/
|
||||
class Controller_Admin_Service extends Controller_Service {
|
||||
protected $secure_actions = array(
|
||||
'ajaxlist'=>TRUE,
|
||||
'ajaxjson_traffic'=>TRUE,
|
||||
'adslstat'=>TRUE,
|
||||
'listadslbilling'=>TRUE,
|
||||
@ -25,22 +24,6 @@ class Controller_Admin_Service extends Controller_Service {
|
||||
'view'=>TRUE,
|
||||
);
|
||||
|
||||
public function action_ajaxlist() {
|
||||
$result = array();
|
||||
|
||||
$result += ORM::factory('Service')->list_autocomplete(
|
||||
isset($_REQUEST['term']) ? $_REQUEST['term'] : '',
|
||||
'id',
|
||||
'id',
|
||||
array('SVC %s: %s'=>array('id','service_name(TRUE)')),
|
||||
isset($_REQUEST['aid']) ? array(array('account_id','=',$_REQUEST['aid'])) : array()
|
||||
);
|
||||
|
||||
$this->auto_render = FALSE;
|
||||
$this->response->headers('Content-Type','application/json');
|
||||
$this->response->body(json_encode(array_values($result)));
|
||||
}
|
||||
|
||||
public function action_ajaxjson_traffic() {
|
||||
$result = array();
|
||||
$svs = ORM::factory('Service')->list_bylistgroup('ADSL');
|
||||
@ -54,7 +37,6 @@ class Controller_Admin_Service extends Controller_Service {
|
||||
|
||||
$google->sdata(array('yr'=>'services'),array('services'=>$data['svs']));
|
||||
|
||||
$this->auto_render = FALSE;
|
||||
$this->response->headers('Content-Type','application/json');
|
||||
$this->response->body($google->json());
|
||||
}
|
||||
@ -538,7 +520,7 @@ class Controller_Admin_Service extends Controller_Service {
|
||||
if (is_null($bt))
|
||||
$bt = $iio->date_start;
|
||||
|
||||
$pdata = Period::details($iio->recurring_schedule,$a ? NULL : $iio->product->price_recurr_weekday,$bt,TRUE);
|
||||
$pdata = Period::details($iio->recurring_schedule,$a ? NULL : $iio->product->price_recurr_weekday,$bt,TRUE,TRUE);
|
||||
|
||||
switch ($iio->recurring_schedule) {
|
||||
case 1:
|
||||
|
@ -46,6 +46,8 @@ class Model_Service extends ORM_OSB {
|
||||
),
|
||||
);
|
||||
|
||||
protected $_form = array('id'=>'id','value'=>'service_name()');
|
||||
|
||||
/**
|
||||
* Get the additional charges associated with this service
|
||||
*/
|
||||
@ -67,7 +69,7 @@ class Model_Service extends ORM_OSB {
|
||||
->or_where('processed','=',FALSE)
|
||||
->where_close();
|
||||
|
||||
return $x->find_all();
|
||||
return $x->and_where('void','IS',NULL)->find_all();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,9 +134,24 @@ class Model_Service extends ORM_OSB {
|
||||
* Show the date we are invoiced to
|
||||
*/
|
||||
public function invoiced_to($format=FALSE) {
|
||||
$x = $this->invoice_item->order_by('date_stop','DESC')->limit(1)->find();
|
||||
$iio = $this->last_invoice_item()
|
||||
->limit(1);
|
||||
|
||||
return $format ? $x->display('date_stop') : $x->date_stop;
|
||||
$iio->find();
|
||||
|
||||
$x = (! $iio->loaded() AND $this->date_next_invoice) ? $this->date_next_invoice-86400 : $iio->date_stop;
|
||||
|
||||
return $format ? Config::date($x) : $x;
|
||||
}
|
||||
|
||||
private function last_invoice_item() {
|
||||
return ORM::factory('Invoice_Item')->join('invoice')
|
||||
->on('invoice.id','=','invoice_item.invoice_id')
|
||||
->on('invoice.status','=',1)
|
||||
->on('invoice_item.service_id','=',$this)
|
||||
->on('invoice_item.item_type','=',0)
|
||||
->on('invoice_item.void','is','null')
|
||||
->order_by('date_stop','DESC');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,7 +167,7 @@ class Model_Service extends ORM_OSB {
|
||||
public function paid_to($format=FALSE) {
|
||||
$x = NULL;
|
||||
|
||||
foreach ($this->invoice_item->order_by('date_stop','DESC')->order_by('date_orig','DESC')->find_all() as $iio)
|
||||
foreach ($this->last_invoice_item()->order_by('date_orig','DESC')->find_all() as $iio)
|
||||
if ($iio->invoice->due() == 0) {
|
||||
$x = $iio;
|
||||
break;
|
||||
@ -203,7 +220,7 @@ class Model_Service extends ORM_OSB {
|
||||
$x = $this->product->keyget('price_group',$this->recur_schedule);
|
||||
|
||||
// @todo This index shouldnt be hard coded.
|
||||
$p = $this->price ? $this->price : $x[$this->price_group]['price_base'];
|
||||
$p = ! is_null($this->price) ? $this->price : $x[$this->price_group]['price_base'];
|
||||
|
||||
if ($tax)
|
||||
$p = Tax::add($p);
|
||||
@ -250,7 +267,7 @@ class Model_Service extends ORM_OSB {
|
||||
*/
|
||||
public function list_autocomplete($term,$index,$value,array $label,array $limit=array(),array $options=NULL) {
|
||||
// We only show service numbers.
|
||||
if (! is_numeric($term))
|
||||
if (! is_numeric($term) AND (! $limit))
|
||||
return array();
|
||||
|
||||
$ao = Auth::instance()->get_user();
|
||||
|
@ -47,7 +47,7 @@ abstract class Model_Service_Plugin extends ORM_OSB {
|
||||
abstract public function password_value();
|
||||
|
||||
public function manage_button() {
|
||||
if (! $this->service->status)
|
||||
if (! $this->service->status OR $this->service->expiring())
|
||||
return FALSE;
|
||||
|
||||
static $k = '';
|
||||
|
@ -90,6 +90,6 @@
|
||||
|
||||
<fieldset class="span5">
|
||||
<legend>Next Invoice Charges</legend>
|
||||
<?php echo Invoice::instance()->add_service($o)->render('html','body'); ?>
|
||||
<?php echo Invoice::instance()->add_service($o)->render('html','body',array('noid'=>TRUE)); ?>
|
||||
</fieldset>
|
||||
</div> <!-- /row -->
|
||||
|
@ -10,6 +10,10 @@
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Task_SSL_Renew extends Minion_Task {
|
||||
protected $_options = array(
|
||||
'id'=>NULL,
|
||||
);
|
||||
|
||||
/**
|
||||
* Renew a certificate
|
||||
*/
|
||||
|
@ -4,7 +4,6 @@
|
||||
* OSB Configuration - SSL Config Items
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage System
|
||||
* @category Configuration
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* SSL Certificate validation messages.
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage SSL
|
||||
* @category Validation
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* This class provides static pages
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Page
|
||||
* @category Controllers
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Deon George
|
||||
|
@ -4,7 +4,6 @@
|
||||
* This class provides static menu categories
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Page
|
||||
* @category Controllers
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Deon George
|
||||
|
@ -4,7 +4,6 @@
|
||||
* This class provides static pages.
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Static Page
|
||||
* @category Models
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* This class provides static page categories
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Static Page
|
||||
* @category Models
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -4,7 +4,6 @@
|
||||
* This class provides Static Page Translation
|
||||
*
|
||||
* @package OSB
|
||||
* @subpackage Static Page
|
||||
* @category Models
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
|
@ -10,6 +10,11 @@
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Task_Task_Run extends Minion_Task {
|
||||
protected $_options = array(
|
||||
'id'=>NULL,
|
||||
'force'=>FALSE,
|
||||
);
|
||||
|
||||
protected function _execute(array $params) {
|
||||
if ($params['id']) {
|
||||
$to = ORM::factory('Task',$params['id']);
|
||||
|
Reference in New Issue
Block a user