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 {
|
|
|
|
throw HTTP_Exception::factory(501,'Missing product map data for :product (:id)',array(':product'=>$iio->product->title(),':id'=>$iio->product_id));
|
|
|
|
}
|
|
|
|
|
2014-01-07 12:29:18 +00:00
|
|
|
$items[$c]['MEMO'] = sprintf('%s (%s)',$iio->module()->title(),$iio->period());
|
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-07 12:29:18 +00:00
|
|
|
if ($iio->module() instanceof Model_Charge) {
|
|
|
|
$items[$c]['QNTY'] *= $iio->module()->quantity;
|
|
|
|
$items[$c]['PRICE'] = sprintf('%3.2f',round($iio->subtotal()-$iio->discount(),2));
|
|
|
|
$items[$c]['AMOUNT'] = sprintf('%3.2f',round($iio->module()->amount-$iio->discount(),2)*-1);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// @todo This rounding should be a system config.
|
|
|
|
$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\tSPLID\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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
?>
|