Minor fixes to statement, services and internal things
Many misc updates
This commit is contained in:
@@ -9,6 +9,10 @@
|
||||
* @author Deon George
|
||||
* @copyright (c) 2010 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*
|
||||
* Column Definitions:
|
||||
* + price_type: 0=One Time, 1=Recurring, 2=Trial, 3=Extra Item
|
||||
* + 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 Controller_Admin_Invoice extends Controller_TemplateDefault_Admin {
|
||||
protected $secure_actions = array(
|
||||
|
@@ -20,15 +20,15 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
public function action_list() {
|
||||
$mode = $this->request->param('id');
|
||||
|
||||
$io = ORM::factory('invoice');
|
||||
$i = ORM::factory('invoice');
|
||||
$tm = 'list_'.$mode;
|
||||
|
||||
if (! method_exists($io,$tm))
|
||||
if (! method_exists($i,$tm))
|
||||
throw new Kohana_Exception('Unknown Task List command :command',array(':command'=>$mode));
|
||||
|
||||
$total = $numinv = 0;
|
||||
$duelist = View::factory('invoice/task/'.$tm.'_head');
|
||||
foreach ($io->$tm() as $t) {
|
||||
foreach ($i->$tm() as $t) {
|
||||
$duelist .= View::factory('invoice/task/'.$tm.'_body')
|
||||
->set('io',$t);
|
||||
|
||||
@@ -60,10 +60,9 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
$action = array();
|
||||
// @todo This should go in a config somewhere
|
||||
$days = 5;
|
||||
$i = ORM::factory('invoice');
|
||||
$key = 'remind_due';
|
||||
|
||||
foreach ($i->list_due(time()+86400*$days) as $io) {
|
||||
foreach (ORM::factory('invoice')->list_due(time()+86400*$days) as $io) {
|
||||
// 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'))
|
||||
continue;
|
||||
@@ -96,7 +95,6 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
*/
|
||||
public function action_remind_overdue() {
|
||||
$action = array();
|
||||
$i = ORM::factory('invoice');
|
||||
$notice = $this->request->param('id');
|
||||
$x = NULL;
|
||||
|
||||
@@ -126,7 +124,7 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
|
||||
$key = 'remind_overdue_'.$notice;
|
||||
|
||||
foreach ($i->list_overdue_billing(time()-86400*$days,FALSE) as $io) {
|
||||
foreach (ORM::factory('invoice')->list_overdue_billing(time()-86400*$days,FALSE) as $io) {
|
||||
// If we have already sent a reminder, we'll skip to the next one.
|
||||
if ($io->remind($key) AND (is_null($x) OR $x != 'again'))
|
||||
continue;
|
||||
@@ -162,29 +160,38 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
*
|
||||
* @param int ID Service ID to generate invoice for (optional)
|
||||
*/
|
||||
public function action_serviceinvoices() {
|
||||
public function action_services() {
|
||||
// Used to only process X invoices in a row.
|
||||
// @todo This should be a configuration item.
|
||||
$max = 10;
|
||||
$action = array();
|
||||
$snd = array(); // Our service next billing dates that need to be updated if this is successful.
|
||||
$sid = $this->request->param('id');
|
||||
$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();
|
||||
Sort::MAsort($svs,'account_id,date_next_invoice');
|
||||
|
||||
$aid = $due = $io = NULL;
|
||||
$max_count = 0;
|
||||
foreach ($svs as $so) {
|
||||
if (! is_null($sid) AND $sid != $so->id)
|
||||
// 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))) {
|
||||
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_null($io)) {
|
||||
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_count > $max)
|
||||
break;
|
||||
|
||||
// Start a new invoice.
|
||||
$io = ORM::factory('invoice');
|
||||
$io->due_date = $due = $io->min_due($so->date_next_invoice);
|
||||
@@ -199,12 +206,12 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
|
||||
$iio->service_id = $so->id;
|
||||
$iio->product_id = $so->product_id;
|
||||
$iio->quantity = 1;
|
||||
$iio->quantity = $pdata['prorata'];
|
||||
$iio->item_type = 0;
|
||||
$iio->discount_amt = null; // @todo
|
||||
$iio->price_type = $so->price_type; // @todo Do we need this?
|
||||
$iio->price_type = $so->product->price_type; // @todo Do we need this?
|
||||
// @todo Might be a better way to do this
|
||||
$iio->price_base = isset($ppa[$so->recur_schedule]['price_base']) ? $ppa[$so->recur_schedule]['price_base'] : 0;
|
||||
$iio->price_base = $so->price ? $so->price : (isset($ppa[$so->recur_schedule]['price_base']) ? $ppa[$so->recur_schedule]['price_base'] : 0);
|
||||
$iio->recurring_schedule = $so->recur_schedule;
|
||||
$iio->date_start = $pdata['start_time']; // @todo
|
||||
$iio->date_stop = $pdata['end_time']; // @todo
|
||||
@@ -212,12 +219,38 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
// 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
|
||||
$co->status=2;
|
||||
$co->save();
|
||||
}
|
||||
|
||||
array_push($action,(string)$so->id);
|
||||
}
|
||||
|
||||
// Save our invoice.
|
||||
if (! $io->save())
|
||||
if (! $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.
|
||||
foreach ($snd as $sid=>$date) {
|
||||
@@ -229,7 +262,10 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
$this->response->body(_('Services Invoiced: ').join('|',$action));
|
||||
}
|
||||
|
||||
public function action_invoice_send() {
|
||||
public function action_send() {
|
||||
// Used to only process X invoices in a row.
|
||||
// @todo This should be a configuration item.
|
||||
$max = 2;
|
||||
$action = array();
|
||||
$iid = $this->request->param('id');
|
||||
$x = NULL;
|
||||
@@ -237,16 +273,21 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
if (preg_match('/:/',$iid))
|
||||
list($iid,$x) = explode(':',$iid);
|
||||
|
||||
// @todo The parameter for email should be a system CONSTANT?
|
||||
$i = $iid ? ORM::factory('invoice')->where('id','=',$iid) : ORM::factory('invoice')->tosend(1);
|
||||
// Get our list of invoices to send
|
||||
$i = $iid ? ORM::factory('invoice')->where('id','=',$iid) : ORM::factory('invoice')->list_tosend();
|
||||
|
||||
$key = 'send';
|
||||
|
||||
$max_count = 0;
|
||||
foreach ($i->find_all() as $io) {
|
||||
// If we have already sent a reminder, we'll skip to the next one.
|
||||
if ($io->remind($key) AND (is_null($x) OR $x != 'again'))
|
||||
continue;
|
||||
|
||||
// If we have issued the max number of invoices this round, finish.
|
||||
if (++$max_count > $max)
|
||||
break;
|
||||
|
||||
// Send our email
|
||||
$et = Email_Template::instance('task_invoice_'.$key);
|
||||
$token = ORM::factory('module_method_token')
|
||||
@@ -271,6 +312,7 @@ class Controller_Task_Invoice extends Controller_Task {
|
||||
|
||||
// @todo Record email log id if possible.
|
||||
if ($et->send()) {
|
||||
$io->print_status = 1;
|
||||
$io->set_remind($key,time());
|
||||
array_push($action,(string)$io);
|
||||
}
|
||||
|
@@ -60,7 +60,7 @@ class Controller_User_Invoice extends Controller_TemplateDefault_User {
|
||||
|
||||
$io = ORM::factory('invoice',$id);
|
||||
|
||||
if (! $io->loaded() OR ! Auth::instance()->authorised($io->account_id,$io->affiliate_id)) {
|
||||
if (! $io->loaded() OR (! Auth::instance()->authorised($io->account_id,$io->affiliate_id) AND ! in_array($this->ao->affiliate->id,$io->service_affiliates()))) {
|
||||
$this->template->content = 'Unauthorised or doesnt exist?';
|
||||
return FALSE;
|
||||
}
|
||||
|
@@ -322,7 +322,7 @@ class Invoice_TCPDF_Default extends Invoice_TCPDF {
|
||||
$this->SetXY($x-1,$y-1);
|
||||
$this->Cell(0,5*(
|
||||
1+1+1+3+($this->io->discount_amt ? 1 : 0)+($this->io->billed_amt ? 1 : 0)+($this->io->credit_amt ? 1 : 0)+$box
|
||||
)+1,'',1,0,'',1);
|
||||
)+1+4,'',1,0,'',1);
|
||||
|
||||
$this->SetFont('helvetica','B',11);
|
||||
$this->SetXY($x,$y);
|
||||
@@ -335,7 +335,7 @@ class Invoice_TCPDF_Default extends Invoice_TCPDF {
|
||||
foreach ($items as $name => $line) {
|
||||
if ($i < $this->itemsSummaryMax) {
|
||||
$this->SetX($x);
|
||||
$this->Cell(0,0,$line['quantity']);
|
||||
$this->Cell(0,0,sprintf('%3.2f',$line['quantity']));
|
||||
$this->SetX($x+8);
|
||||
$this->Cell(0,0,$name);
|
||||
$this->SetX($x+135);
|
||||
@@ -362,7 +362,7 @@ class Invoice_TCPDF_Default extends Invoice_TCPDF {
|
||||
if (round($this->io->subtotal(),Kohana::config('config.currency_format')) != $subtotal) {
|
||||
$this->SetFont('helvetica','',9);
|
||||
$this->SetX($x);
|
||||
$this->Cell(0,0,'Rounding');
|
||||
$this->Cell(0,0,'Other');
|
||||
$this->SetX($x+135);
|
||||
$this->Cell(0,0,Currency::display($this->io->subtotal()-$subtotal),0,0,'R');
|
||||
|
||||
@@ -404,7 +404,7 @@ class Invoice_TCPDF_Default extends Invoice_TCPDF {
|
||||
$this->SetY($y);
|
||||
|
||||
$this->SetX($x+8);
|
||||
$this->Cell(0,0,'Total Charges');
|
||||
$this->Cell(0,0,'Total Charges This Invoice');
|
||||
$this->SetX($x+135);
|
||||
$this->Cell(0,0,Currency::display($this->io->total()),0,0,'R');
|
||||
|
||||
@@ -496,7 +496,7 @@ class Invoice_TCPDF_Default extends Invoice_TCPDF {
|
||||
}
|
||||
|
||||
$this->SetX($x+130);
|
||||
$this->Cell(0,0,Currency::display($ito->total_amt),0,0,'R');
|
||||
$this->Cell(0,0,Currency::display($ito->total()),0,0,'R');
|
||||
|
||||
if ($this->show_service_range && $ito->period()) {
|
||||
$this->SetFont('helvetica','I',7);
|
||||
|
@@ -148,7 +148,7 @@ class Model_Invoice extends ORMOSB {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of services on an invoice
|
||||
* Get a list of invoice_items for a service_id on an invoice
|
||||
*
|
||||
* We use this to list details by service on an invoice.
|
||||
*/
|
||||
@@ -158,15 +158,15 @@ class Model_Invoice extends ORMOSB {
|
||||
$items = $this->items();
|
||||
|
||||
foreach ($items as $ito)
|
||||
if ($ito->service_id AND empty($result[$ito->service_id]))
|
||||
$result[$ito->service_id] = $ito->service;
|
||||
if ($ito->service_id AND empty($result[$ito->service_id]))
|
||||
$result[$ito->service_id] = $ito;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all invoice items for a service optionally by recurring schedule
|
||||
*/
|
||||
*/
|
||||
public function items_service($sid,$rs=NULL) {
|
||||
$result = array();
|
||||
$items = $this->items();
|
||||
@@ -211,11 +211,11 @@ class Model_Invoice extends ORMOSB {
|
||||
$result = array();
|
||||
|
||||
foreach ($this->items() as $ito) {
|
||||
// We conly summaries item_type=0
|
||||
// We only summarise item_type=0
|
||||
if (! $ito->item_type == 0)
|
||||
continue;
|
||||
|
||||
$t = $ito->product_id;
|
||||
$t = $ito->product->name();
|
||||
|
||||
if (! isset($result[$t])) {
|
||||
$result[$t]['quantity'] = 0;
|
||||
@@ -303,14 +303,17 @@ class Model_Invoice extends ORMOSB {
|
||||
}
|
||||
|
||||
public function min_due($date) {
|
||||
// @todo This should be configurable;
|
||||
return ($date < time()) ? time() : $date;
|
||||
return ($date < time()) ? time()+Kohana::config('config.invoice.min_due_days')*86400 : $date;
|
||||
}
|
||||
|
||||
public function save(Validation $validation = NULL) {
|
||||
// Our items will be clobbered once we save the object, so we need to save it here.
|
||||
$items = $this->items();
|
||||
|
||||
// @todo This is added here so we can do payments
|
||||
$this->total_amt = $this->total();
|
||||
$this->billed_amt = 0;
|
||||
|
||||
// Save the invoice
|
||||
parent::save($validation);
|
||||
|
||||
@@ -331,12 +334,14 @@ class Model_Invoice extends ORMOSB {
|
||||
throw new Kohana_Exception('Problem saving invoice_item for invoice :invoice - Failed save()',array(':invoice'=>$invoice->id));
|
||||
}
|
||||
|
||||
// @todo Need to save tax information
|
||||
// @todo Need to save discount information
|
||||
}
|
||||
|
||||
|
||||
} else
|
||||
throw new Kohana_Exception('Couldnt save invoice for some reason?');
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,13 +392,29 @@ class Model_Invoice extends ORMOSB {
|
||||
return $this->saved();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of affiliates associated with this invoice (via the service)
|
||||
*/
|
||||
public function service_affiliates() {
|
||||
$return = array();
|
||||
|
||||
foreach ($this->items() as $io)
|
||||
array_push($return,$io->service->affiliate_id);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/** LIST FUNCTIONS **/
|
||||
|
||||
private function _list_active() {
|
||||
return ORM::factory('invoice')->where('status','=',1);
|
||||
}
|
||||
|
||||
private function _list_due() {
|
||||
static $result = array();
|
||||
|
||||
if (! $result)
|
||||
foreach (ORM::factory('invoice')->where('status','=',1)->find_all() as $io)
|
||||
foreach ($this->_list_active()->find_all() as $io)
|
||||
if ($io->due())
|
||||
array_push($result,$io);
|
||||
|
||||
@@ -445,12 +466,20 @@ class Model_Invoice extends ORMOSB {
|
||||
if ($io->due_date > time())
|
||||
if (is_null($time))
|
||||
array_push($result,$io);
|
||||
elseif ($this->due_date <= $time)
|
||||
elseif ($io->due_date <= $time)
|
||||
array_push($result,$io);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of invoices that need to be sent.
|
||||
* @todo This should be optimised a little to return only invoices to send, instead of looking for them.
|
||||
*/
|
||||
public function list_tosend() {
|
||||
return ORM::factory('invoice')->where('status','=',1)->where_open()->where('print_status','is',NULL)->or_where('print_status','!=',1)->where_close();
|
||||
}
|
||||
|
||||
public function html() {
|
||||
// @todo This should be in a config file.
|
||||
$css = '<style type="text/css">';
|
||||
|
@@ -19,11 +19,17 @@ class Model_Invoice_Item extends ORMOSB {
|
||||
'invoice'=>array(),
|
||||
'service'=>array()
|
||||
);
|
||||
protected $_has_one = array(
|
||||
'charge'=>array('far_key'=>'charge_id','foreign_key'=>'id')
|
||||
);
|
||||
protected $_has_many = array(
|
||||
'invoice_item_tax'=>array('far_key'=>'id')
|
||||
);
|
||||
|
||||
protected $_display_filters = array(
|
||||
'date_orig'=>array(
|
||||
array('Config::date',array(':value')),
|
||||
),
|
||||
'date_start'=>array(
|
||||
array('Config::date',array(':value')),
|
||||
),
|
||||
@@ -83,8 +89,11 @@ class Model_Invoice_Item extends ORMOSB {
|
||||
return ($this->item_type == 0 OR $this->quantity == 1) ? HTML::nbsp('') : sprintf('%s@%3.2f',$this->quantity,$this->price_base);
|
||||
}
|
||||
|
||||
// @todo This might not be required.
|
||||
public function invoice_detail_items() {
|
||||
// @todo To fix up this function - needs to be better formed.
|
||||
if ($this->item_type == 5)
|
||||
return $this->charge->details('invoice_detail_items');
|
||||
|
||||
if ($this->item_type != 0)
|
||||
return;
|
||||
|
||||
@@ -96,6 +105,7 @@ class Model_Invoice_Item extends ORMOSB {
|
||||
parent::save($validation);
|
||||
|
||||
// Need to save the taxes and discounts associated with the invoice_item
|
||||
// @todo This needs to only check if the records have previously been saved, and update them.
|
||||
if ($this->saved()) {
|
||||
$iito = ORM::factory('invoice_item_tax');
|
||||
|
||||
|
Reference in New Issue
Block a user