2013-10-10 02:44:53 +00:00
< ? php defined ( 'SYSPATH' ) or die ( 'No direct access allowed.' );
/**
* This class supports OSB payments .
*
* @ package Payment
* @ category Models
* @ author Deon George
* @ copyright ( c ) 2009 - 2013 Open Source Billing
* @ license http :// dev . osbill . net / license . html
*/
class Model_Payment extends ORM_OSB {
// Relationships
protected $_has_many = array (
'payment_item' => array ( 'far_key' => 'id' ),
'invoice' => array ( 'through' => 'payment_item' ),
);
protected $_belongs_to = array (
'account' => array (),
'checkout' => array ( 'foreign_key' => 'checkout_plugin_id' ),
);
protected $_sorting = array (
'date_payment' => 'DESC'
);
protected $_display_filters = array (
2013-05-14 13:53:04 +00:00
'date_orig' => array (
array ( 'Config::date' , array ( ':value' )),
),
2013-10-10 02:44:53 +00:00
'date_payment' => array (
array ( 'Config::date' , array ( ':value' )),
),
'total_amt' => array (
array ( 'Currency::display' , array ( ':value' )),
),
);
// Items belonging to an invoice
private $payment_items = array ();
public function __construct ( $id = NULL ) {
// Load our model.
parent :: __construct ( $id );
// Load our sub items
if ( $this -> loaded ())
$this -> payment_items = $this -> payment_item -> find_all () -> as_array ();
}
/**
* Add an item to this payment
*
* @ param $inv number , to allocate payment to an invoice
*/
public function add_item ( $invnum ) {
// Find our id, if it exists
foreach ( $this -> payment_items as $pio )
if ( $pio -> invoice_id == $invnum )
return $pio ;
// New Item
$c = count ( $this -> payment_items );
$this -> payment_items [ $c ] = ORM :: factory ( 'Payment_Item' );
$this -> payment_items [ $c ] -> invoice_id = $invnum ;
return $this -> payment_items [ $c ];
}
/**
* Calculate the remaining balance available for this payment
*/
public function balance ( $format = FALSE ) {
$result = $this -> total ();
foreach ( $this -> items ( 'ALLOC' ) as $pio )
$result -= $pio -> alloc_amt ;
return $format ? Currency :: display ( $result ) : $result ;
}
/**
* Find all items that are exportable .
*
* @ param int $start List payments that were modified this many days ago
*/
public function export ( $start ) {
return ORM :: factory ( 'Payment' )
-> where ( 'date_payment' , '>=' , time () - $start * 86400 )
-> find_all ();
}
/**
* Return a list of invoices that this payment is applied to
*/
public function invoices () {
$result = array ();
foreach ( $this -> payment_items as $pio )
array_push ( $result , $pio -> invoice );
return $result ;
}
public function invoicelist () {
return join ( ',' , $this -> invoices ());
}
/**
* Return a list of payment items for this payment .
* @ param type [ ALLOC | CREDIT | ALL ]
* @ see payment_items
*/
public function items ( $type = 'ALL' ) {
$result = array ();
foreach ( $this -> payment_items as $pio ) {
$return = FALSE ;
switch ( $type ) {
case 'ALLOC' :
if ( $pio -> alloc_amt > 0 )
$return = TRUE ;
break ;
case 'CREDIT' :
if ( $pio -> alloc_amt < 0 )
$return = TRUE ;
break ;
case 'ALL' :
default :
$return = TRUE ;
break ;
}
if ( $return )
array_push ( $result , $pio );
}
return $result ;
}
/**
* Show the total amount of a payment .
*/
public function total ( $format = FALSE ) {
$result = $this -> total_amt ;
foreach ( $this -> items ( 'CREDIT' ) as $pio )
$result += $pio -> alloc_amt ;
return $format ? Currency :: display ( $result ) : Currency :: round ( $result );
}
/** LIST FUNCTIONS **/
public function list_unapplied () {
return array ();
$pi = array ();
// @todo database suffix needs to be dynamically calculated
foreach ( DB :: Query ( Database :: SELECT ,
sprintf ( 'SELECT A.id AS id,A.total_amt as total_amt FROM ab_%s A LEFT JOIN ab_%s B ON (A.site_id=B.site_id AND A.id=B.payment_id) WHERE (A.refund_status=0 OR A.refund_status IS NULL) GROUP BY A.id HAVING ROUND(SUM(IFNULL(B.alloc_amt,0)),2)!=A.total_amt ORDER BY account_id,payment_id' , 'payment' , 'payment_item' ))
-> execute () as $values ) {
array_push ( $pi , $values [ 'id' ]);
}
return $this -> where ( 'id' , 'IN' , $pi ) -> order_by ( 'account_id' ) -> find_all ();
}
public function list_recent_table () {
// @todo This should be in a config file.
$css = '<style type="text/css">' ;
$css .= 'table.box-left { border: 1px solid #AAAACC; margin-right: auto; }' ;
$css .= 'tr.head { font-weight: bold; }' ;
$css .= 'td.head { font-weight: bold; }' ;
$css .= 'td.right { text-align: right; }' ;
$css .= 'tr.odd { background-color: #FCFCFE; }' ;
$css .= 'tr.even { background-color: #F6F6F8; }' ;
$css .= '</style>' ;
return $css . Table :: display (
$this -> limit ( 10 ) -> find_all (),
25 ,
array (
'id' => array ( 'label' => 'ID' ),
'date_payment' => array ( 'label' => 'Date' ),
'checkout->display("name")' => array ( 'label' => 'Method' ),
'total_amt' => array ( 'label' => 'Total' , 'class' => 'right' ),
'balance(TRUE)' => array ( 'label' => 'Balance' , 'class' => 'right' ),
'invoicelist()' => array ( 'label' => 'Invoices' ),
),
array (
'type' => 'list' ,
));
}
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 should not be mandatory - or there should be a source for non-users (automatic postings)
$this -> source_id = Auth :: instance () -> get_user () ? Auth :: instance () -> get_user () -> id : 1 ;
$this -> ip = Request :: $client_ip ;
// Make sure we dont over allocate
$t = 0 ;
$msg = '' ;
foreach ( $items as $pio ) {
// Only need to check items that ave actually changed.
if ( $pio -> changed ()) {
$old_pio = ORM :: factory ( 'Payment_Item' , $pio -> id );
if (( $it = $pio -> invoice -> due () + ORM :: factory ( 'Payment_Item' , $pio -> id ) -> alloc_amt - $pio -> alloc_amt ) < 0 )
$msg .= ( $msg ? ' ' : '' ) . sprintf ( 'Invoice %s over allocated by %3.2f.' , $pio -> invoice_id , $it );
}
$t += $pio -> alloc_amt ;
}
if ( $t > ( float ) $this -> total_amt )
$msg .= ( $msg ? ' ' : '' ) . sprintf ( 'Payment over allocated by %3.2f.' , $t - $this -> total_amt );
if ( $msg ) {
SystemMessage :: add ( array (
'title' => 'Payment NOT Recorded' ,
'type' => 'warning' ,
'body' => $msg ,
));
return FALSE ;
}
// Save the payment
parent :: save ( $validation );
// Need to save the associated items and their taxes
if ( ! $this -> changed () OR $this -> saved ()) {
foreach ( $items as $pio ) {
// Skip applying 0 payments to invoices.
if ( Currency :: round ( $pio -> alloc_amt ) == 0 AND ! $pio -> loaded ())
continue ;
$pio -> payment_id = $this -> id ;
if ( ! $pio -> check ()) {
// @todo Mark payment as cancelled and write a memo, then...
throw new Kohana_Exception ( 'Problem saving payment_item for invoice :invoice - Failed check()' , array ( ':invoice' => $invoice -> id ));
}
$pio -> save ();
if ( ! $pio -> saved ()) {
// @todo Mark payment as cancelled and write a memo, then...
throw new Kohana_Exception ( 'Problem saving payment_item for invoice :invoice - Failed save()' , array ( ':invoice' => $invoice -> id ));
}
}
} else {
throw new Kohana_Exception ( 'Couldnt save payment for some reason?' );
}
return TRUE ;
}
}
?>