2013-10-10 02:44:53 +00:00
< ? php defined ( 'SYSPATH' ) or die ( 'No direct access allowed.' );
/**
* This class provides invoice information
*
* @ package Invoice
* @ category Helpers
* @ author Deon George
* @ copyright ( c ) 2009 - 2013 Open Source Billing
* @ license http :// dev . osbill . net / license . html
*/
class Invoice {
// This invoice Object
2013-12-05 05:22:23 +00:00
private $_io ;
2013-10-10 02:44:53 +00:00
2013-09-06 05:39:56 +00:00
private $_methods = array (
2013-12-05 05:22:23 +00:00
'dump' ,
2013-09-06 05:39:56 +00:00
'save' ,
'saved' ,
2013-12-05 05:22:23 +00:00
'total' ,
2013-09-06 05:39:56 +00:00
);
// Enable passing calls to ORM::Invoice()
public function __call ( $method , array $args ) {
if ( in_array ( $method , $this -> _methods ))
2013-12-05 05:22:23 +00:00
return call_user_func_array ( array ( $this -> _io , $method ), $args );
2013-09-06 05:39:56 +00:00
else
throw HTTP_Exception :: factory ( 501 , 'Unknown/unauthorised method :method' , array ( ':method' => $method ));
}
2013-06-13 13:35:19 +00:00
public function __construct ( Model_Invoice $io = NULL ) {
2013-12-05 05:22:23 +00:00
$this -> _io = is_null ( $io ) ? ORM :: factory ( 'Invoice' ) : $io ;
2013-09-06 05:39:56 +00:00
// Set our invoice as valid
if ( is_null ( $io ))
2016-08-31 05:03:09 +00:00
$this -> _io -> active = 1 ;
2013-10-10 02:44:53 +00:00
}
/**
2013-06-13 13:35:19 +00:00
* Add a Service to an Invoice
2013-10-10 02:44:53 +00:00
*
2013-06-13 13:35:19 +00:00
* @ param $so Model_Servie
2013-10-10 02:44:53 +00:00
*/
2013-06-13 13:35:19 +00:00
public function add_service ( Model_Service $so ) {
2013-12-05 05:22:23 +00:00
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 ));
2013-09-06 05:39:56 +00:00
2013-12-05 05:22:23 +00:00
if ( ! $this -> _io -> account_id )
$this -> _io -> account_id = $so -> account_id ;
2013-09-06 05:39:56 +00:00
2013-12-05 05:22:23 +00:00
else if ( $this -> _io -> account_id != $so -> account_id )
2013-09-06 05:39:56 +00:00
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
2013-12-19 23:00:32 +00:00
if ( ! $this -> _io -> due_date OR $this -> _io -> due_date > $this -> min_due ( $so -> date_next_invoice ))
$this -> _io -> due_date = $this -> min_due ( $so -> date_next_invoice );
2013-09-06 05:39:56 +00:00
2013-06-13 13:35:19 +00:00
$pdata = Period :: details ( $so -> recur_schedule , $so -> product -> price_recurr_day , $so -> invoiced_to () + 86400 , FALSE , $so -> product -> price_recurr_strict );
2013-10-10 02:44:53 +00:00
2013-06-13 13:35:19 +00:00
$iio = ORM :: factory ( 'Invoice_Item' );
$iio -> service_id = $so -> id ;
2016-08-03 06:25:26 +00:00
$iio -> product_id = $so -> product -> id ;
2013-06-13 13:35:19 +00:00
$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' ];
2016-09-22 00:19:19 +00:00
$iio -> active = TRUE ;
2013-10-10 02:44:53 +00:00
2013-06-13 13:35:19 +00:00
// Service Billing
2013-09-06 05:39:56 +00:00
$iio -> item_type = 0 ;
2013-10-10 02:44:53 +00:00
2016-07-27 06:55:07 +00:00
$this -> _io -> add_sub_item ( $iio );
2013-10-10 02:44:53 +00:00
2013-06-13 13:35:19 +00:00
// Check if there are any charges
$c = ORM :: factory ( 'Charge' )
2016-08-31 05:03:09 +00:00
-> where_active ()
2013-06-13 13:35:19 +00:00
-> where ( 'service_id' , '=' , $so -> id )
-> where ( 'processed' , 'is' , NULL );
2013-10-10 02:44:53 +00:00
2013-06-13 13:35:19 +00:00
foreach ( $c -> find_all () as $co ) {
$iio = ORM :: factory ( 'Invoice_Item' );
$iio -> service_id = $co -> service_id ;
2016-08-03 06:25:26 +00:00
$iio -> product_id = $co -> service -> product_id ;
2013-12-19 23:00:32 +00:00
$iio -> module_id = $co -> mid ();
$iio -> module_ref = $co -> id ;
2013-06-13 13:35:19 +00:00
$iio -> quantity = $co -> quantity ;
$iio -> price_base = $co -> amount ;
$iio -> date_start = $co -> date_orig ;
$iio -> date_stop = $co -> date_orig ;
2013-09-06 05:39:56 +00:00
$iio -> item_type = $co -> type ;
2016-09-22 00:19:19 +00:00
$iio -> active = TRUE ;
2013-10-10 02:44:53 +00:00
2016-07-27 06:55:07 +00:00
$this -> _io -> add_sub_item ( $iio );
2013-06-13 13:35:19 +00:00
}
2013-10-10 02:44:53 +00:00
2013-06-13 13:35:19 +00:00
return $this ;
2013-10-10 02:44:53 +00:00
}
2013-12-19 23:00:32 +00:00
/**
* Draw an invoice with a summary first page , and a detail subsequent pages
*/
private function draw_summary_invoice ( Invoice_TCPDF $pdfo ) {
// Draw Invoice Basics
$pdfo -> drawCompanyLogo ();
$pdfo -> drawCompanyAddress ();
$pdfo -> drawInvoiceHeader ();
// @todo Get news from DB
$pdfo -> drawNews ( '' );
$pdfo -> drawRemittenceStub ();
$pdfo -> drawPaymentMethods ();
if ( $this -> _io -> billing_status != 1 && $this -> _io -> due_date <= time ())
$pdfo -> drawInvoiceDueNotice ();
elseif ( $this -> _io -> billing_status == 1 )
$pdfo -> drawInvoicePaidNotice ();
2016-08-10 06:07:00 +00:00
if ( $this -> _io -> account -> invoices_due_total () > $this -> _io -> due ())
2013-12-19 23:00:32 +00:00
$pdfo -> drawSummaryInvoicesDue ();
$pdfo -> drawSummaryLineItems ();
// Next Page
$pdfo -> drawDetailLineItems ();
// Draw any Custom functions:
$pdfo -> drawCustom ();
}
public static function instance ( Model_Invoice $io = NULL ) {
return new Invoice ( $io );
}
public function min_due ( $date ) {
return strtotime ( date ( 'Y-M-d' ,( $date < time ()) ? time () + ORM :: factory ( 'Invoice' ) -> config ( 'DUE_DAYS_MIN' ) * 86400 : $date ));
}
2013-09-06 05:39:56 +00:00
public function render ( $type , $section , $args = array ()) {
2013-06-13 13:35:19 +00:00
switch ( $type ) {
2013-12-19 23:00:32 +00:00
case 'email' :
switch ( $section ) {
case 'all' :
$token = ORM :: factory ( 'Module_Method_Token' )
2016-09-22 00:19:19 +00:00
-> method ( array ( 'invoice' , 'user:download' ))
2013-12-19 23:00:32 +00:00
-> account ( $this -> _io -> account )
-> expire ( time () + 86400 * 21 )
-> uses ( 3 )
-> generate ();
$et = Email_Template :: instance ( 'task_invoice_send' );
$et -> to = array ( 'account' => array ( $this -> _io -> account_id ));
$et -> variables = array (
'DUE' => $this -> _io -> due ( TRUE ),
'DUE_DATE' => $this -> _io -> display ( 'due_date' ),
'EMAIL' => Company :: instance () -> email (),
'FIRST_NAME' => $this -> _io -> account -> first_name ,
'HTML_INVOICE' => View :: factory ( 'invoice/user/viewemail' ) -> set ( 'html' , $this -> render_html ()),
'INV_NUM' => $this -> _io -> refnum (),
'INV_URL' => URL :: site ( URL :: link ( 'user' , 'invoice/view/' . $this -> _io -> id ), 'http' ),
'INV_URL_DOWNLOAD' => URL :: site ( URL :: link ( 'user' , sprintf ( 'invoice/download/%s?token=%s' , $this -> _io -> id , $token )), 'http' ),
'SITE_NAME' => Company :: instance () -> name (),
);
return $et -> send ();
break ;
default :
throw HTTP_Exception :: factory ( 501 , 'Unknown section type :section' , array ( ':section' => $section ));
}
break ;
2013-06-13 13:35:19 +00:00
case 'html' :
2018-06-13 11:40:08 +00:00
// @todo What happened to rounding, look at service 410. Why is cost correct and invoice generation not? Maybe fixed - need to validate.
//echo Debug::vars(['m'=>__METHOD__,'i'=>$this->_io->dump()]);
2013-06-13 13:35:19 +00:00
switch ( $section ) {
case 'body' :
2016-08-31 05:03:09 +00:00
if ( ! $this -> _io -> active )
2016-08-03 06:25:26 +00:00
Style :: factory ()
-> type ( 'file' )
-> data ( 'media/css/pages/invoice.css' );
2013-06-13 13:35:19 +00:00
return View :: factory ( 'invoice/user/view/body' )
2013-09-06 05:39:56 +00:00
-> set ( 'show_id' ,( isset ( $args [ 'noid' ]) AND $args [ 'noid' ]) ? FALSE : TRUE )
2013-12-05 05:22:23 +00:00
-> set ( 'o' , $this -> _io );
2013-06-13 13:35:19 +00:00
break ;
2013-12-19 23:00:32 +00:00
case 'all' :
return $this -> render_html ();
break ;
default :
throw HTTP_Exception :: factory ( 501 , 'Unknown section type :section' , array ( ':section' => $section ));
}
break ;
case 'pdf' :
switch ( $section ) {
case 'all' :
if ( isset ( $args [ 'download' ]))
return $this -> render_pdf () -> Output ( $args [ 'download' ], 'D' );
else
return $this -> render_pdf ();
break ;
2013-06-13 13:35:19 +00:00
default :
throw HTTP_Exception :: factory ( 501 , 'Unknown section type :section' , array ( ':section' => $section ));
}
break ;
default :
throw HTTP_Exception :: factory ( 501 , 'Unknown render type :type' , array ( ':type' => $type ));
}
2013-10-10 02:44:53 +00:00
}
/**
2013-12-19 23:00:32 +00:00
* Renders the invoice in HTML
2013-10-10 02:44:53 +00:00
*/
2013-12-19 23:00:32 +00:00
private function render_html () {
2016-07-24 14:44:17 +00:00
return View :: factory ( 'invoice/render' )
2013-12-19 23:00:32 +00:00
-> set ( 'o' , $this -> _io );
}
2013-10-10 02:44:53 +00:00
2013-12-19 23:00:32 +00:00
/**
* Renders the invoice as a PDF and returns the PDF object
*
* @ return Object Invoice_TCPDF
*/
private function render_pdf () {
$class = Kohana :: classname ( 'Invoice_TCPDF_' . Kohana :: $config -> load ( 'invoice' ) -> driver );
$pdfo = new $class ( $this -> _io );
2013-10-10 02:44:53 +00:00
2013-12-19 23:00:32 +00:00
if ( $pdfo -> getTemplate ()) {
$pagecount = $pdfo -> setSourceFile ( $pdfo -> getTemplate ());
$tplidx = $pdfo -> ImportPage ( 1 );
2013-10-10 02:44:53 +00:00
}
2013-12-19 23:00:32 +00:00
$pdfo -> addPage ();
2013-10-10 02:44:53 +00:00
# If we are using FPDI
if ( isset ( $tplidx ))
2013-12-19 23:00:32 +00:00
$pdfo -> useTemplate ( $tplidx );
2013-10-10 02:44:53 +00:00
2013-12-19 23:00:32 +00:00
$this -> draw_summary_invoice ( $pdfo );
2013-10-10 02:44:53 +00:00
# If we get here, all is OK.
2013-12-19 23:00:32 +00:00
return $pdfo ;
2013-10-10 02:44:53 +00:00
}
}
?>