diff --git a/application/classes/Controller/Reseller/Account.php b/application/classes/Controller/Reseller/Account.php index d38fcb0e..e504a3e8 100644 --- a/application/classes/Controller/Reseller/Account.php +++ b/application/classes/Controller/Reseller/Account.php @@ -128,6 +128,17 @@ class Controller_Reseller_Account extends Controller_Account { 'id'=>array('url'=>URL::link('user','service/view/')), )) ); + + $i = Invoice::instance(); + foreach ($ao->service->list_active() as $io) + if (! $io->suspend_billing) + $i->add_service($io); + + Block::factory() + ->title(sprintf('Next Invoice Items for Account: %s',$ao->accnum())) + ->title_icon('icon-info-sign') + ->span(6) + ->body($i->render('html','body')); } } ?> diff --git a/application/classes/Model/Auth/UserDefault.php b/application/classes/Model/Auth/UserDefault.php index 7414250e..490b513e 100644 --- a/application/classes/Model/Auth/UserDefault.php +++ b/application/classes/Model/Auth/UserDefault.php @@ -15,7 +15,7 @@ class Model_Auth_UserDefault extends Model_Auth_User { 'username' => array( array('not_empty'), array('min_length', array(':value', 4)), - array('max_length', array(':value', 32)), + array('max_length', array(':value', 256)), ), 'email' => array( array('not_empty'), diff --git a/application/classes/StaticList/ItemType.php b/application/classes/StaticList/ItemType.php new file mode 100644 index 00000000..7643f1d3 --- /dev/null +++ b/application/classes/StaticList/ItemType.php @@ -0,0 +1,28 @@ +'MAIN', // Line Charge Topic on Invoice, eg: Service Name + 5=>'EXCESS', // Excess Service Item, of item 0 + ); + } + + public static function get($value) { + return static::factory()->_get($value); + } + + public static function index($key) { + return array_search($key,static::factory()->table()); + } +} +?> diff --git a/modules/invoice/classes/Controller/Task/Invoice.php b/modules/invoice/classes/Controller/Task/Invoice.php index 1930adf8..e238ed56 100644 --- a/modules/invoice/classes/Controller/Task/Invoice.php +++ b/modules/invoice/classes/Controller/Task/Invoice.php @@ -201,7 +201,6 @@ class Controller_Task_Invoice extends Controller_Task { $iio->quantity = $pdata['prorata']; $iio->item_type = 0; // Service Billing $iio->discount_amt = NULL; // @todo - $iio->price_type = $so->product->price_type; $iio->price_base = $so->price(); $iio->recurring_schedule = $so->recur_schedule; $iio->date_start = $pdata['start_time']; diff --git a/modules/invoice/classes/Controller/User/Invoice.php b/modules/invoice/classes/Controller/User/Invoice.php index 63175267..902a85c5 100644 --- a/modules/invoice/classes/Controller/User/Invoice.php +++ b/modules/invoice/classes/Controller/User/Invoice.php @@ -64,7 +64,6 @@ class Controller_User_Invoice extends Controller_Invoice { throw HTTP_Exception::factory(403,'Service either doesnt exist, or you are not authorised to see it'); $output .= View::factory('invoice/user/view') - ->set('mediapath',Route::get('default/media')) ->set('o',$io); if ($io->due() AND ! $io->cart_exists()) diff --git a/modules/invoice/classes/Invoicable.php b/modules/invoice/classes/Invoicable.php new file mode 100644 index 00000000..4e8f32bd --- /dev/null +++ b/modules/invoice/classes/Invoicable.php @@ -0,0 +1,16 @@ + diff --git a/modules/invoice/classes/Invoice.php b/modules/invoice/classes/Invoice.php index 124df9e5..4cfe7448 100644 --- a/modules/invoice/classes/Invoice.php +++ b/modules/invoice/classes/Invoice.php @@ -13,80 +13,78 @@ class Invoice { // This invoice Object private $io; - public function __construct($io) { - $this->io = $io; + public function __construct(Model_Invoice $io=NULL) { + $this->io = is_null($io) ? ORM::factory('Invoice') : $io; } - public static function instance($io) { + public static function instance(Model_Invoice $io=NULL) { return new Invoice($io); } /** - * Return a list of invoices for an service + * Add a Service to an Invoice * - * @param $id int Service ID - * @param $paid boolean Optionally only list the ones that are not paid. - * @return array + * @param $so Model_Servie */ - // @todo Function Not Used - public static function servicelist($id,$paid=TRUE) { - // @todo need to add the db prefix - $invoices = DB::Query(Database::SELECT,' -SELECT i.id AS iid,i.due_date AS due FROM ab_invoice i,ab_invoice_item ii WHERE ii.invoice_id=i.id AND service_id=:id GROUP BY i.id - ') - ->param(':id',$id) - ->execute(); + public function add_service(Model_Service $so) { + $pdata = Period::details($so->recur_schedule,$so->product->price_recurr_day,$so->invoiced_to()+86400,FALSE,$so->product->price_recurr_strict); - $service_invoices = array(); - foreach ($invoices as $item) { - if ($bal = Invoice::balance($item['iid']) OR $paid) { - $service_invoices[$item['iid']]['id'] = $item['iid']; - $service_invoices[$item['iid']]['total'] = $bal; - $service_invoices[$item['iid']]['due'] = $item['due']; - } + $iio = ORM::factory('Invoice_Item'); + $iio->service_id = $so->id; + $iio->product_id = $so->product_id; + $iio->quantity = $pdata['prorata']; + $iio->price_base = $so->price(); + $iio->recurring_schedule = $so->recur_schedule; + $iio->date_start = $pdata['start_time']; + $iio->date_stop = $pdata['end_time']; + + // Service Billing + $iio->item_type = StaticList_ItemType::index('MAIN'); + + $this->io->add_item($iio); + + // Check if there are any charges + $c = ORM::factory('Charge') + ->where('service_id','=',$so->id) + ->where('processed','is',NULL); + + foreach ($c->find_all() as $co) { + $iio = ORM::factory('Invoice_Item'); + $iio->service_id = $co->service_id; + $iio->product_id = $co->product_id; + $iio->charge_id = $co->id; + $iio->quantity = $co->quantity; + $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'); + + $this->io->add_item($iio); } - return $service_invoices; + return $this; } - /** - * Return the total of amount outstanding for a service - * - * @param $id int Service ID - * @param $paid boolean Optionally only list the ones that are not paid. - * @return real Total amount outstanding - * @see Invoice::listservice() - */ - // @todo Function Not Used - public static function servicetotal($id,$paid=TRUE) { - $total = 0; + public function render($type,$section) { + switch ($type) { + case 'html': + switch ($section) { + case 'body': + return View::factory('invoice/user/view/body') + ->set('o',$this->io); + break; - foreach (Invoice::servicelist($id,$paid) as $item) - $total += $item['total']; + default: + throw HTTP_Exception::factory(501,'Unknown section type :section',array(':section'=>$section)); + } - return $total; - } + break; - /** - * Return the earliest due date of an outstanding invoice - * - * @param $id int Service ID - * @return datetime - */ - // @todo Function Not Used - public static function servicedue($id) { - $due = 0; - - foreach (Invoice::servicelist($id,FALSE) as $item) - if ($due < $item['due']) - $due = $item['due']; - - return $due; - } - - // @todo Function Not Used - public static function balance($id) { - return ORM::factory('Invoice',$id)->due(); + default: + throw HTTP_Exception::factory(501,'Unknown render type :type',array(':type'=>$type)); + } } /** diff --git a/modules/invoice/classes/Model/Invoice.php b/modules/invoice/classes/Model/Invoice.php index 66b0134c..3ac5f0be 100644 --- a/modules/invoice/classes/Model/Invoice.php +++ b/modules/invoice/classes/Model/Invoice.php @@ -75,15 +75,95 @@ class Model_Invoice extends ORM_OSB implements Cartable { /** * Add an item to an invoice */ - public function add_item() { + public function add_item(Model_Invoice_Item $iio=NULL) { + // Just to check if an invoice is called from the DB, that it should have items with it. if ($this->loaded() and ! $this->invoice_items) - throw new Kohana_Exception('Need to load invoice_items?'); + throw HTTP_Exception::factory(501,'Need dto load invoice_items?'); - $c = count($this->invoice_items); + // @todo This is the old calling of this function, which should be removed + if (is_null($iio)) { + $c = count($this->invoice_items); - $this->invoice_items[$c] = ORM::factory('Invoice_Item'); + $this->invoice_items[$c] = ORM::factory('Invoice_Item'); - return $this->invoice_items[$c]; + return $this->invoice_items[$c]; + } + + array_push($this->invoice_items,$iio); + } + + /** + * Return the recurring schedules that are on an invoice + * + * @param $period Return an Array of items for that period + */ + public function items_periods($period=NULL) { + $result = array(); + + foreach ($this->items() as $ito) { + // We are only interested in item_type=0 + if ($ito->item_type != 0) + continue; + + if (is_null($period) AND ! in_array($ito->recurring_schedule,$result)) + array_push($result,$ito->recurring_schedule); + elseif ($ito->recurring_schedule == $period) + array_push($result,$ito); + } + + return $result; + } + + /** + * Return the extra items on an invoice relating to an invoice_item + * IE: item_type != 0 + */ + public function service_items_extra(Model_Invoice_Item $o) { + $result = array(); + + // At the moment, we only return extra 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; + } + + /** + * Return the total of all items relating to a service + */ + public function service_items_tax(Model_Invoice_Item $o,$format=FALSE) { + $result = 0; + + // At the moment, we only return extra items pertaining to a service + if (! $o->service_id) + return $result; + + foreach ($this->items() as $iio) + if ($iio->service_id == $o->service_id) + $result += $iio->tax(); + + return $format ? Currency::display($result) : $result; + } + + /** + * Return the total of all items relating to a service + */ + public function service_items_total(Model_Invoice_Item $o,$format=FALSE) { + $result = 0; + + // At the moment, we only return extra items pertaining to a service + if (! $o->service_id) + return $result; + + foreach ($this->items() as $iio) + if ($iio->service_id == $o->service_id) + $result += $iio->total(); + + return $format ? Currency::display($result) : $result; } /** diff --git a/modules/invoice/classes/Model/Invoice/Item.php b/modules/invoice/classes/Model/Invoice/Item.php index 2b85f970..3b3ff6e4 100644 --- a/modules/invoice/classes/Model/Invoice/Item.php +++ b/modules/invoice/classes/Model/Invoice/Item.php @@ -9,7 +9,7 @@ * @copyright (c) 2009-2013 Open Source Billing * @license http://dev.osbill.net/license.html */ -class Model_Invoice_Item extends ORM_OSB { +class Model_Invoice_Item extends ORM_OSB implements Invoicable { // Relationships protected $_belongs_to = array( 'product'=>array(), @@ -39,6 +39,16 @@ class Model_Invoice_Item extends ORM_OSB { private $subitems = array(); private $subitems_loaded = FALSE; + /** INTERFACE REQUIREMENTS **/ + public function invoice_line() { + if ($this->charge_id) + return $this->charge->description.' '.$this->period(); + elseif ($this->service_id) + return 'Service '.$this->period(); + else + 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); @@ -71,7 +81,7 @@ class Model_Invoice_Item extends ORM_OSB { } // Sum up the tax that applies to this invoice item - public function tax() { + public function tax($format=FALSE) { $result = 0; foreach ($this->invoice_item_tax->find_all() as $iit) @@ -81,7 +91,9 @@ class Model_Invoice_Item extends ORM_OSB { if (! $result) $result += round($this->price_base*$this->quantity*.1,2); - return Currency::round($result); + $result = Currency::round($result); + + return $format ? Currency::display($result) : $result; } public function tax_items() { @@ -98,8 +110,10 @@ class Model_Invoice_Item extends ORM_OSB { } // This total of this item before discounts and taxes - public function subtotal() { - return Currency::round($this->price_base*$this->quantity); + public function subtotal($format=FALSE) { + $result = Currency::round($this->price_base*$this->quantity); + + return $format ? Currency::display($result) : $result; } // The total of all discounts @@ -107,8 +121,10 @@ class Model_Invoice_Item extends ORM_OSB { return Currency::round($this->discount_amt); } - public function total() { - return Currency::round($this->subtotal()+$this->tax()-$this->discount()); + public function total($format=FALSE) { + $result = Currency::round($this->subtotal()+$this->tax()-$this->discount()); + + return $format ? Currency::display($result) : $result; } /** diff --git a/modules/invoice/views/invoice/user/view.php b/modules/invoice/views/invoice/user/view.php index 6b36df10..e3b6a437 100644 --- a/modules/invoice/views/invoice/user/view.php +++ b/modules/invoice/views/invoice/user/view.php @@ -20,7 +20,7 @@
+ | service_id),$iio->service->id()).' '.$iio->service->service_name(); ?> | ++ | service_items_total($iio,TRUE); ?> |
+ |||
---|---|---|---|---|---|---|
+ | + | invoice_line(),$iio->display('id')); ?> | +subtotal(TRUE); ?> |
+ + |
service_id),$ito->service->id()); ?> | -product->title(),$ito->service->name()); ?> (product_id; ?>) | -items_service_total($ito->service_id)) : ' ');?> | -||||
- | trannum();?> | -name();?> | -detail();?> | -period();?> | -subtotal());?> | -|
- | - | (items_service_discount($ito->service_id));?>) | -||||
- | - | items_service_tax($ito->service_id));?> | -||||
+ | + | invoice_line(),$eiio->display('id')); ?> | +subtotal(TRUE); ?> |
+ + |
- | trannum();?> | -name();?> | -detail();?> | -period();?> | -subtotal());?> | -
- | - | items_service_tax($ito->service_id));?> | -
+ | service->service_name(); ?> | ++ | service_items_total($iio,TRUE); ?> |
+ |
---|---|---|---|---|
+ | invoice_line(); ?> | +total(TRUE); ?> |
+ + | |
+ | invoice_line(); ?> | +total(TRUE); ?> |
+ + |