Revamping invoice rendering

This commit is contained in:
Deon George
2016-08-03 16:25:26 +10:00
parent 7adcd1d983
commit a560c5f4fa
6 changed files with 288 additions and 99 deletions

View File

@@ -43,7 +43,7 @@ class Model_Invoice extends ORM_OSB implements Cartable {
// Items belonging to an invoice
protected $_sub_items_load = array(
'invoice_item'=>array('service_id','item_type','date_start','date_stop'),
'invoice_item'=>array('service_id','product_id','item_type','date_start','date_stop'),
);
protected $_compress_column = array(
@@ -67,12 +67,6 @@ class Model_Invoice extends ORM_OSB implements Cartable {
return new Cart_Item(1,sprintf('Invoice: %s',$this->refnum()),$this->due());
}
public function add_sub_item(Model_Invoice_Item $iio,$taxed=FALSE) {
$iio->add_sub_item($this->account->country,$taxed);
$this->subitem_add($iio);
}
/**
* Return if this invoice is already in the cart
*/
@@ -80,7 +74,16 @@ class Model_Invoice extends ORM_OSB implements Cartable {
return count(Cart::instance()->get($this->mid(),$this->id));
}
// Our local methods
/** LOCAL METHODS **/
/**
* Add items to the invoice while building it
*/
public function add_sub_item(Model_Invoice_Item $iio,$taxed=FALSE) {
$iio->add_sub_item($this->account->country,$taxed);
$this->subitem_add($iio);
}
/**
* Return a list of valid checkout options for this invoice
@@ -136,6 +139,66 @@ class Model_Invoice extends ORM_OSB implements Cartable {
return array_keys($this->_render['SCHED']);
}
/**
* Return an array of items to render, in appropriate order
*/
public function items_render() {
$result = $track = array();
// If the invoice hasnt been saved, then we'll need to assign some fake IDs to the items
$c = 0;
if (! $this->_loaded)
foreach ($this->_sub_items as $iio)
$iio->id = 'FAKE:'.$c++;
// First work through our recurring schedule items
$result['s'] = array();
foreach ($this->recur_schedules() as $rs)
foreach ($this->recur_schedule_services($rs) as $sid)
foreach ($this->service_products($sid) as $pid) {
// Get all the services with this recur schedule first, then get service charges with rs=NULL
foreach ($this->_sub_items as $iio) {
// If this is not the recur schedule or service we are working with, skip it
if ($iio->service_id != $sid OR $iio->product_id != $pid OR $iio->recurring_schedule != $rs OR in_array($iio->id,$track))
continue;
// Ensure we dont process this item again
array_push($track,$iio->id);
if (! $iio->void)
array_push($result['s'],$iio);
}
// Get all the items for this service with a NULL rs
foreach ($this->_sub_items as $iio) {
// If this is not the recur schedule or service we are working with, skip it
if ($iio->service_id != $sid OR $iio->product_id != $pid OR ! is_null($iio->recurring_schedule) OR in_array($iio->id,$track))
continue;
// Ensure we dont process this item again
array_push($track,$iio->id);
if (! $iio->void)
array_push($result['s'],$iio);
}
}
// Next get the items we havent already got
$result['other'] = array();
foreach ($this->_sub_items as $iio)
if (! in_array($iio->id,$track))
array_push($result['other'],$iio);
// Debug
#foreach ($result['s'] as $iio)
# echo Debug::vars(array('s'=>$iio->object()));
#foreach ($result['other'] as $iio)
# echo Debug::vars(array('o'=>$iio->object()));
return $result;
}
/**
* Return a summary of all itemss on an invoice
*/
@@ -230,6 +293,38 @@ class Model_Invoice extends ORM_OSB implements Cartable {
}
}
/**
* For a particular recurring schedule, get al lthe services
*/
private function recur_schedule_services($rs) {
$result = array();
if (! $rs)
return $result;
foreach ($this->_sub_items as $o)
if ($o->service_id AND $o->recurring_schedule == $rs AND ! in_array($o->service_id,$result))
array_push($result,$o->service_id);
return $result;
}
/**
* Get the recurring schedules on an invoice
* Exclude any NULL recurring schedules
*/
private function recur_schedules() {
$result = array();
foreach ($this->_sub_items as $o)
if (! is_null($o->recurring_schedule) AND ! in_array($o->recurring_schedule,$result))
array_push($result,$o->recurring_schedule);
sort($result);
return $result;
}
/**
* Check the reminder value
*/
@@ -389,6 +484,29 @@ class Model_Invoice extends ORM_OSB implements Cartable {
return $format ? Currency::display($result) : $result;
}
/**
* For a particular service, get all the products
*/
private function service_products($sid) {
$result = array();
foreach ($this->_sub_items as $o)
if ($o->product_id AND $o->service_id == $sid AND ! in_array($o->product_id,$result))
array_push($result,$o->product_id);
return $result;
}
public function service_products_total($sid,$pid,$format=FALSE) {
$result = 0;
foreach ($this->_sub_items as $o)
if ($o->service_id == $sid AND $o->product_id == $pid)
$result += $o->total();
return $format ? Currency::display($result) : $result;
}
public function set_remind($key,$value,$add=FALSE) {
$x = $this->reminders;

View File

@@ -13,8 +13,11 @@ class Model_Invoice_Item extends ORM_OSB {
// Relationships
protected $_belongs_to = array(
'invoice'=>array(),
'service'=>array()
'module'=>array(),
'product'=>array(),
'service'=>array(),
);
protected $_has_many = array(
'tax'=>array('model'=>'Invoice_Item_Tax','far_key'=>'id')
);
@@ -29,6 +32,9 @@ class Model_Invoice_Item extends ORM_OSB {
'date_stop'=>array(
array('Site::Date',array(':value')),
),
'recurring_schedule'=>array(
array('StaticList_RecurSchedule::get',array(':value')),
),
);
// Items belonging to an invoice item
@@ -38,40 +44,81 @@ class Model_Invoice_Item extends ORM_OSB {
/**
* Invoice Item Types
*
* @see isValid()
*/
private $_item_type = array(
0=>'Product/Service Charge', // Line Charge Topic on Invoice, eg: Service Name, must have corresponding SERVICE_ID
1=>'Hardware',
2=>'Service Relocation Fee', // Must have corresponding SERVICE_ID
3=>'Service Change Fee', // Must have corresponding SERVICE_ID
4=>'Service Connection Fee', // Must have corresponding SERVICE_ID
5=>'Excess Usage', // Excess Service Item, of item 0, must have corresponding SERVICE_ID
6=>'Service Cancellation Fee', // Must have corresponding SERVICE_ID
7=>'Extra Product/Service Charge', // Service Billing in advance, Must have corresponding SERVICE_ID
8=>'Product Addition', // Additional Product Customisation, Must have corresponding SERVICE_ID
9=>'Module Charge', // Must have corresponding SERVICE_ID
120=>'Credit/Debit Transfer', // SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL : INVOICE_ID is NOT NULL
124=>'Late Payment Fee', // SERVICE_ID is NULL, MODULE_ID = CHECKOUT MODULE,
125=>'Payment Fee', // SERVICE_ID is NULL, MODULE_ID = CHECKOUT MODULE, MODULE_REF = CHECKOUT NAME
126=>'Other', // MODEL_ID should be a module
127=>'Rounding', // SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL
0=>'Product/Service', // * Line Charge Topic on Invoice.
1=>'Hardware', // *
2=>'Service Relocation Fee', // * Must have corresponding SERVICE_ID
3=>'Service Change Fee', // * Must have corresponding SERVICE_ID
4=>'Service Connection Fee', // * Must have corresponding SERVICE_ID
5=>'Excess Usage', // * Excess Service Item, of item 0, must have corresponding SERVICE_ID
6=>'Service Cancellation Fee', // * Must have corresponding SERVICE_ID
7=>'Extra Product/Service Charge', // * Service Billing in advance, Must have corresponding SERVICE_ID
8=>'Product Addition', // * Additional Product Customisation, Must have corresponding SERVICE_ID
120=>'Credit/Debit Transfer', // * SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL : INVOICE_ID is NOT NULL
124=>'Late Payment Fee', // * SERVICE_ID is NULL, MODULE_ID = CHECKOUT MODULE,
125=>'Payment Fee', // * SERVICE_ID is NULL, MODULE_ID = CHECKOUT MODULE, MODULE_REF = CHECKOUT NAME
126=>'Other', // * MODEL_ID should be a module
127=>'Rounding', // * SERVICE_ID is NULL, MODULE_ID is NULL, MODULE_REF is NULL
);
/** REQUIRED ABSTRACT METHODS **/
public function name($variable=NULL) {
if (! $this->isValid())
return sprintf('Record Error [%s-%s]',$this->item_type,$this->id);
switch ($this->item_type) {
case 0:
case 3:
case 4:
case 5:
return sprintf('%s: %s',$this->product->name($variable),$this->service->namesub($variable));
default:
return sprintf('Unknown [%s]',$this->id);
return sprintf('Unknown [%s-%s]',$this->item_type,$this->id);
}
}
public function titleline() {
return in_array($this->item_type,[0,120,124,125,126,127]);
public function namesub($variable=NULL) {
if (! $this->isValid())
return sprintf('Record Error [%s-%s]',$this->item_type,$this->id);
switch ($this->item_type) {
case 0:
return sprintf('%s: %s',StaticList_ItemType::get($this->item_type),$this->period());
case 3:
case 4:
case 5:
return $this->_module()->namesub($variable);
default:
return sprintf('Unknown [%s-%s]',$this->item_type,$this->id);
}
}
/**
* Display the Invoice Item Reference Number
*/
public function refnum($short=FALSE) {
return $short ? '' : sprintf('%03s-',$this->item_type).sprintf('%06s',$this->id);
}
/** LOCAL METHODS **/
/**
* Module assocated with the invoice item
*/
public function _module() {
if (! $this->module_id OR ! $this->module_ref)
return NULL;
return $this->module->instance($this->module_ref);
}
/**
* Return the list of available item types
*/
public function _types() {
return $this->_item_type;
}
@@ -110,6 +157,33 @@ class Model_Invoice_Item extends ORM_OSB {
return Currency::round($this->discount_amt);
}
/**
* Validate that this record is correct
*/
private function isValid() {
switch ($this->item_type) {
case 0:
// @todo Validate if module_id = charge and module_ref corresponds with the line item
if (! $this->service_id OR ! $this->product_id OR ($this->module_id AND $this->module_id != 30 AND ! is_null($this>module_id)) OR $this->product_name OR is_null($this->recurring_schedule))
return FALSE;
break;
// These items come from the charge module, so we should have a charge module_id and ref
case 3:
case 4:
if (! $this->service_id OR ! $this->product_id OR ! $this->module_id OR ! $this->module_ref OR $this->product_name OR ! is_null($this->recurring_schedule))
return FALSE;
break;
// These items come from the charge module, so we should have a charge module_id and ref
case 5:
if (! $this->service_id OR ! $this->product_id OR ! $this->module_id OR ! $this->module_ref OR $this->product_name OR ! is_null($this->recurring_schedule))
return FALSE;
break;
}
// If we get here, assume it is valid
return TRUE;
}
/**
* The line that will be printed on an invoice
*
@@ -159,15 +233,10 @@ class Model_Invoice_Item extends ORM_OSB {
/**
* Return an instance of the Model of this charge
*/
public function module() {
$x = ORM::factory('Module',$this->module_id);
if (! $x->loaded())
throw new Kohana_Exception('Module :module doesnt exist?',array(':module'=>$this->module_id));
return ORM::factory('Module',$this->module_id)->instance($this->module_ref);
return $this->_module();
}
// Display the period that a transaction applies
public function period() {
return ($this->date_start == $this->date_stop) ? Site::Date($this->date_start) : sprintf('%s -> %s',Site::Date($this->date_start),Site::Date($this->date_stop));
@@ -206,7 +275,7 @@ class Model_Invoice_Item extends ORM_OSB {
// This total of this item before discounts and taxes
public function subtotal($format=FALSE) {
$result = $this->price_base*$this->quantity;
$result = Currency::round($this->price_base*$this->quantity);
return $format ? Currency::display($result) : $result;
}