2013-05-14 13:53:04 +00:00
< ? php defined ( 'SYSPATH' ) or die ( 'No direct access allowed.' );
/**
* This class provides OSB exporting capabilities for Quickbooks .
*
* @ package Export
* @ category Plugins
* @ author Deon George
* @ copyright ( c ) 2009 - 2013 Open Source Billing
* @ license http :// dev . osbill . net / license . html
*/
class Export_Plugin_Quicken extends Export_Plugin {
public function export ( Response $response ) {
$output = '' ;
if ( ! isset ( $_POST [ 'id' ]) OR ! $_POST [ 'id' ] OR ! $this -> emo -> loaded ())
HTTP :: redirect ( URL :: link ( 'reseller' , 'export/index' ));
$o = ORM :: factory ( 'Module' , $this -> emo -> module_id );
if ( ! $o -> loaded ())
HTTP :: redirect ( URL :: link ( 'reseller' , 'export/index' ));
switch ( $o -> name ) {
case 'invoice' : $output .= $this -> invoices ( $_POST [ 'id' ]);
break ;
case 'payment' : $output .= $this -> payments ( $_POST [ 'id' ]);
break ;
default :
throw HTTP_Exception :: factory ( 501 , 'Dont know how to export :name' , array ( ':name' => $o -> name ));
}
$response -> body ( $output );
$response -> send_file ( TRUE , 'quicken-import.iif' , array ( 'mime_type' => 'text/plain' ));
}
/**
* Export an invoice
*/
private function invoice ( Model_Invoice $io ) {
$defaults = array (
'ACCNT' => 'Accounts Receivable' ,
'TRNSTYPE' => 'TAX_INVOICE' ,
'INVMEMO' => 'Thank you for using ' . Company :: instance () -> name (),
'CLEAR' => 'N' ,
'TOPRINT' => 'N' ,
'PAID' => 'N' ,
'MEMO' => 'Import from OSB' ,
'INVTITLE' => Company :: instance () -> name () . ' Invoice' ,
);
$invoice = $items = array ();
$invoice [ 'TRNSID' ] = sprintf ( '%06s' , $io -> id );
$invoice [ 'DATE' ] = date ( 'm/d/Y' , $io -> date_orig );
$invoice [ 'ADDR1' ] = $io -> account -> address1 ;
$invoice [ 'ADDR2' ] = $io -> account -> address2 ;
$invoice [ 'ADDR3' ] = sprintf ( '%s, %s %s' , $io -> account -> city , $io -> account -> state , $io -> account -> zip );
// @todo - should be configurable
# $invoice['TERMS'] = '7 Days';
$invoice [ 'DOCNUM' ] = sprintf ( '%06s' , $io -> id );
$invoice [ 'DUEDATE' ] = date ( 'm/d/Y' , $io -> due_date );
$invoice [ 'AMOUNT' ] = sprintf ( '%3.2f' , $io -> total ());
$invoice [ 'NAME' ] = $io -> account -> company ? $io -> account -> company : sprintf ( '%s %s' , $io -> account -> last_name , $io -> account -> first_name );
// Other Quicken fields not used.
#$invoice['CLASS'] = '';
#$invoice['SHIPVIA'] = '';
#$invoice['SHIPDATE'] = '';
#$invoice['OTHER1'] = '';
#$invoice['REP'] = '';
#$invoice['FOB'] = '';
#$invoice['PONUM'] = '';
#$invoice['SADDR1'] = '';
#$invoice['SADDR2'] = '';
#$invoice['SADDR3'] = '';
#$invoice['SADDR4'] = '';
#$invoice['SADDR5'] = '';
$c = 0 ;
// Add the items to the invoice
2013-12-05 05:22:23 +00:00
foreach ( $io -> subitems ( 'CHARGE' ) as $iio ) {
2013-05-14 13:53:04 +00:00
// Skip any zero amount items not relating to a service
if ( $iio -> total () == 0 and ! $iio -> service_id )
continue ;
// Get the mapping item for account purposes
2014-01-07 12:29:18 +00:00
if ( $iio -> module () instanceof Model_Product ) {
2013-05-14 13:53:04 +00:00
$edo = ORM :: factory ( 'Export_DataMap' )
2014-01-07 12:29:18 +00:00
-> where ( 'module_id' , '=' , $iio -> module_id )
-> and_where ( 'item_id' , '=' , $iio -> module_ref )
2013-05-14 13:53:04 +00:00
-> find ();
if ( $edo -> loaded ()) {
$items [ $c ][ 'ACCNT' ] = $edo -> map_data [ 'account' ];
$items [ $c ][ 'INVITEM' ] = $edo -> map_data [ 'item' ];
} else {
2016-08-15 11:23:18 +00:00
throw HTTP_Exception :: factory ( 501 , 'Missing product map data for :product (:id)' , array ( ':product' => $iio -> product -> name ( Site :: language ()), ':id' => $iio -> module_ref ));
2013-05-14 13:53:04 +00:00
}
2016-08-15 11:23:18 +00:00
$items [ $c ][ 'MEMO' ] = $iio -> name ();
2013-05-14 13:53:04 +00:00
// Non product item
} else {
$items [ $c ][ 'ACCNT' ] = 'Other Income' ;
$items [ $c ][ 'INVITEM' ] = 'Unknown' ;
$items [ $c ][ 'MEMO' ] = $iio -> period ();
}
$items [ $c ][ 'CLEAR' ] = 'N' ;
$items [ $c ][ 'QNTY' ] = - 1 ;
if ( $iio -> tax_items ()) {
// @todo, need to figure out how multiple tax items are handled
if ( count ( $iio -> tax_items ()) > 1 )
throw HTTP_Exception ( 501 , 'Export cant handle multiple tax items yet' );
foreach ( $iio -> tax_items () as $tid => $amount ) {
$to = ORM :: factory ( 'Tax' , $tid );
$items [ $c ][ 'TAXABLE' ] = 'Y' ;
$items [ $c ][ 'TAXCODE' ] = $to -> description ;
$items [ $c ][ 'TAXRATE' ] = sprintf ( '%3.2f%%' , $to -> rate );
$items [ $c ][ 'TAXAMOUNT' ] = sprintf ( '%3.2f' , $amount *- 1 );
}
} else {
$items [ $c ][ 'TAXAMOUNT' ] = 0 ;
}
2014-01-08 04:48:42 +00:00
// @todo This rounding should be a system config.
2014-01-07 12:29:18 +00:00
if ( $iio -> module () instanceof Model_Charge ) {
$items [ $c ][ 'QNTY' ] *= $iio -> module () -> quantity ;
2014-01-08 04:48:42 +00:00
$items [ $c ][ 'PRICE' ] = sprintf ( '%3.2f' , round ( $iio -> module () -> amount - $iio -> discount (), 2 ));
$items [ $c ][ 'AMOUNT' ] = sprintf ( '%3.2f' , round ( $iio -> subtotal () - $iio -> discount (), 2 ) *- 1 );
2014-01-07 12:29:18 +00:00
} else {
$items [ $c ][ 'PRICE' ] = sprintf ( '%3.2f' , round ( $iio -> subtotal () - $iio -> discount (), 2 ));
$items [ $c ][ 'AMOUNT' ] = sprintf ( '%3.2f' , round ( $iio -> subtotal () - $iio -> discount (), 2 ) *- 1 );
}
2013-05-14 13:53:04 +00:00
$c ++ ;
}
// Add credits as a other item
2013-12-05 05:22:23 +00:00
foreach ( $io -> subitems ( 'CREDIT' ) as $iio ) {
2013-05-14 13:53:04 +00:00
$items [ $c ][ 'ACCNT' ] = 'Other Income' ;
$items [ $c ][ 'INVITEM' ] = 'Product:Unknown' ;
$items [ $c ][ 'CLEAR' ] = 'N' ;
$items [ $c ][ 'QNTY' ] = 1 ;
$items [ $c ][ 'MEMO' ] = 'Credit Item' ;
2013-10-09 12:26:59 +00:00
foreach ( $iio -> tax_items () as $tid => $amount ) {
$to = ORM :: factory ( 'Tax' , $tid );
$items [ $c ][ 'TAXABLE' ] = 'Y' ;
$items [ $c ][ 'TAXCODE' ] = $to -> description ;
$items [ $c ][ 'TAXRATE' ] = sprintf ( '%3.2f%%' , $to -> rate );
$items [ $c ][ 'TAXAMOUNT' ] = sprintf ( '%3.2f' , $amount *- 1 );
}
$items [ $c ][ 'PRICE' ] = sprintf ( '%3.2f' , round ( $iio -> subtotal () - $iio -> discount (), 2 ));
$items [ $c ][ 'AMOUNT' ] = sprintf ( '%3.2f' , round ( $iio -> subtotal () - $iio -> discount (), 2 ) *- 1 );
$c ++ ;
2013-05-14 13:53:04 +00:00
}
return $this -> output ( Arr :: merge ( $defaults , $invoice ), $items );
}
/**
* Export selected invoices
*/
private function invoices ( array $ids ) {
$output = '' ;
foreach ( $ids as $id )
$output .= $this -> invoice ( ORM :: factory ( 'Invoice' , $id ));
// If all went OK, update our export status
$this -> update ( $ids );
return $output ;
}
/**
* Return exported data for download
*/
private function output ( array $trans , array $items ) {
$output = '' ;
$output .= " !TRNS \t " ;
$output .= implode ( " \t " , array_keys ( $trans )) . " \n " ;
$output .= " TRNS \t " ;
$output .= implode ( " \t " , array_values ( $trans )) . " \n " ;
$spl = 0 ;
foreach ( $items as $detail ) {
if ( ! $spl ) {
$output .= " !SPL \t SPLID \t " ;
$output .= implode ( " \t " , array_keys ( $detail )) . " \n " ;
}
$output .= sprintf ( " SPL \t %s \t %s \n " , $spl ++ , implode ( " \t " , array_values ( $detail )));
}
$output .= " ENDTRNS \n " ;
return $output ;
}
/**
* Export a payment
*/
private function payment ( Model_Payment $po ) {
$defaults = array (
'CLEAR' => 'N' ,
'TRNSTYPE' => 'PAYMENT' ,
);
$payment = $items = array ();
$payment [ 'AMOUNT' ] = sprintf ( '%3.2f' , $po -> total_amt );
$payment [ 'TRNSID' ] = sprintf ( 'P%06s' , $po -> id );
$payment [ 'DATE' ] = date ( 'm/d/Y' , $po -> date_payment );
$payment [ 'NAME' ] = $po -> account -> company ? $po -> account -> company : sprintf ( '%s %s' , $po -> account -> last_name , $po -> account -> first_name );
2013-06-19 09:26:07 +00:00
$payment [ 'MEMO' ] = sprintf ( 'Payment for invoice(s) %s (%s)' , $po -> invoicelist (), $po -> checkout -> name );
2013-05-14 13:53:04 +00:00
// @todo Accounts/Payment should be configurable
switch ( $po -> checkout -> plugin ) {
// @todo this is direct debit
case 'DD_EZYPAY' :
$payment [ 'PAYMETH' ] = 'DirectDebit' ;
$payment [ 'ACCNT' ] = 'Ezypay' ;
break ;
case 'REMIT_CHEQUE' :
$payment [ 'PAYMETH' ] = 'Cheque' ;
$payment [ 'ACCNT' ] = 'Undeposited Funds' ;
break ;
case 'REMIT_BANK_WIRE' :
$payment [ 'PAYMETH' ] = 'DirectCredit' ;
$payment [ 'ACCNT' ] = 'Bendigo Bank' ;
break ;
case 'PAYPAL_CART' :
$payment [ 'PAYMETH' ] = 'Paypal' ;
$payment [ 'ACCNT' ] = 'Paypal' ;
break ;
default :
$payment [ 'PAYMETH' ] = 'TBA' ;
$payment [ 'ACCNT' ] = 'Undeposited Funds' ;
}
$items [ 0 ][ 'TRANSTYPE' ] = 'PAYMENT' ;
$items [ 0 ][ 'CLEAR' ] = 'N' ;
$items [ 0 ][ 'ACCNT' ] = 'Accounts Receivable' ;
$items [ 0 ][ 'AMOUNT' ] = $po -> total ();
return $this -> output ( Arr :: merge ( $defaults , $payment ), $items );
}
/**
* Export selected invoices
*/
private function payments ( array $ids ) {
$output = '' ;
foreach ( $ids as $id )
$output .= $this -> payment ( ORM :: factory ( 'Payment' , $id ));
// If all went OK, update our export status
$this -> update ( $ids );
return $output ;
}
private function update ( array $ids ) {
foreach ( $ids as $id ) {
// Check if we have exported this item already
$eio = ORM :: factory ( 'Export_Item' )
-> where ( 'item_id' , '=' , $id )
-> and_where ( 'export_module_id' , '=' , $this -> emo -> id )
-> find ();
if ( ! $eio -> loaded ()) {
$eio -> item_id = $id ;
$eio -> export_module_id = $this -> emo -> id ;
}
$eio -> save ();
}
}
}
?>