UPDATE: Our good friend Derek Allard (whose brainchild is said BambooInvoice) has informed me over at the BI Forums that an update is forthcoming which will include a much more versitile taxation system. /me wonders what other delicious treats will be bundled with this new incarnation... shall it even be 1.0 ??!
--==:[0000.0000]:==--
Not just for Canadians, but anyone who may want to use one, the other or both taxes on a single line item in Bamboo Invoice.
**WARNING** This hack is not for the faint of heart, I may have missed something in the chronicling of this adventure and I can't guarantee this will work for you in any way.
In case you haven't heard, BambooInvoice is only the slickest open source online invoicing system built with CodeIgnitor.
This mod is quite a hack, but the principal is to double the 'taxable' functionality for each line item, thus having a taxable1 and taxable2 for each item on the invoice.
To pull this off, modify the existing bamboo_invoice_items.taxable field to be called bamboo_invoice_items.taxable1 and add another field of INT(1) or BOOLEAN (if you will) called bamboo_invoice_items.taxable2
...Then make the following changes to the following files.
***********
[/bamboo_system_files/application/controllers/invoices.php]
-> Line 141:
foreach ($items as $item)
{
//$taxable = (isset($item['taxable']) && $item['taxable'] == 1) ? 1 : 0;
$taxable1 = (isset($item['taxable1']) && $item['taxable1'] == 1) ? 1 : 0;
$taxable2 = (isset($item['taxable2']) && $item['taxable2'] == 1) ? 1 : 0;
$sub_amount = $item['quantity'] * $item['amount'];
$amount += $sub_amount;
$tax1_amount += $sub_amount * (($tax1_rate)/100) * $taxable1;
$tax2_amount += $sub_amount * (($tax2_rate)/100) * $taxable2;
}
echo '{"amount" : "'.number_format($amount, 2, $this->config->item('currency_decimal'), '').'", "tax1_amount" : "'.number_format($tax1_amount, 2, $this->config->item('currency_decimal'), '').'", "tax2_amount" : "'.number_format($tax2_amount, 2, $this->config->item('currency_decimal'), '').'", "total_amount" : "'.number_format($amount + $tax1_amount+$tax2_amount, 2, $this->config->item('currency_decimal'), '').'"}';
}
-> Line 225:
$amount = 0;
foreach ($items as $item)
{
$taxable1 = (isset($item['taxable1']) && $item['taxable1'] == 1) ? 1 : 0;
$taxable2 = (isset($item['taxable2']) && $item['taxable2'] == 1) ? 1 : 0;
$invoice_items = array(
'invoice_id' => $invoice_id,
'quantity' => $item['quantity'],
'amount' => $item['amount'],
'work_description' => $item['work_description'],
'taxable1' => $taxable1,
'taxable2' => $taxable2
);
$this->invoices_model->addInvoiceItem($invoice_items);
}
redirect('invoices/view/'.$invoice_id);
-> Line 426:
// add them back
$items = $this->input->post('items');
foreach ($items as $item)
{
$taxable1 = (isset($item['taxable1']) && $item['taxable1'] == 1) ? 1 : 0;
$taxable2 = (isset($item['taxable2']) && $item['taxable2'] == 1) ? 1 : 0;
$invoice_items = array(
'invoice_id' => $invoice_id,
'quantity' => $item['quantity'],
'amount' => $item['amount'],
'work_description' => $item['work_description'],
'taxable1' => $taxable1,
'taxable2' => $taxable2
);
$this->invoices_model->addInvoiceItem($invoice_items);
}
// give a session telling them it worked
-> Line 550:
$amount = 0;
foreach ($items as $item)
{
$taxable1 = (isset($item['taxable1']) && $item['taxable1'] == 1) ? 1 : 0;
$taxable2 = (isset($item['taxable2']) && $item['taxable2'] == 1) ? 1 : 0;
$invoice_items = array(
'invoice_id' => htmlspecialchars($invoice_id),
'quantity' => htmlspecialchars($item['quantity']),
'amount' => htmlspecialchars($item['amount']),
'work_description' => htmlspecialchars($item['work_description']),
'taxable1' => htmlspecialchars($taxable1),
'taxable2' => htmlspecialchars($taxable2)
);
$this->invoices_model->addInvoiceItem($invoice_items);
}
}
***********
[/bamboo_system_files/application/language/english/bamboo_lang.php]
-> Line 108:
$lang['invoice_item'] = 'Item';
$lang['invoice_item_no_tax1'] = 'GST Exempt';
$lang['invoice_item_no_tax2'] = 'PST Exempt';
$lang['invoice_last_used'] = 'last number used ';
***********
[/bamboo_system_files/application/models/invoices_model.php]
-> Line 92: ...replace the whole function...
function getSingleInvoice($invoice_id)
{
$this->db->select('invoices.*, clients.name, clients.address1, clients.address2, clients.city, clients.country, clients.province, clients.website, clients.postal_code, clients.tax_code');
$this->db->select('(SELECT SUM('.$this->db->dbprefix('invoice_payments').'.amount_paid) FROM '.$this->db->dbprefix('invoice_payments').' WHERE '.$this->db->dbprefix('invoice_payments').'.invoice_id=' . $invoice_id . ') AS amount_paid', FALSE);
$this->db->select('TO_DAYS('.$this->db->dbprefix('invoices').'.dateIssued) - TO_DAYS(curdate()) AS daysOverdue', FALSE);
$this->db->select('(SELECT SUM('.$this->db->dbprefix('invoice_items').'.amount * '.$this->db->dbprefix('invoice_items').'.quantity) FROM '.$this->db->dbprefix('invoice_items').' WHERE '.$this->db->dbprefix('invoice_items').'.invoice_id=' . $invoice_id . ') AS total_notax', FALSE);
$this->db->select('(SELECT ROUND(SUM(SubTotal_Tax1) * tax1, 3) as total_tax1
FROM (SELECT tax1, amt * qty AS SubTotal_Tax1
FROM (SELECT '.$this->db->dbprefix('invoice_items').'.quantity AS qty, '.$this->db->dbprefix('invoice_items').'.amount AS amt, ('.$this->db->dbprefix('invoices').'.tax1_rate / 100) as tax1
FROM '.$this->db->dbprefix('invoices').' LEFT JOIN '.$this->db->dbprefix('invoice_items').' ON '.$this->db->dbprefix('invoices').'.id = '.$this->db->dbprefix('invoice_items').'.invoice_id WHERE '.$this->db->dbprefix('invoice_items').'.invoice_id =' . $invoice_id . ' AND '.$this->db->dbprefix('invoice_items').'.taxable1 =1 ) AS tmp_Tax_Total ) AS tmp_Total) AS total_tax1', FALSE);
$this->db->select('(SELECT ROUND(SUM(SubTotal_tax2) * tax2, 3) as total_tax2
FROM (SELECT tax2, amt * qty AS SubTotal_tax2
FROM (SELECT '.$this->db->dbprefix('invoice_items').'.quantity AS qty, '.$this->db->dbprefix('invoice_items').'.amount AS amt, ('.$this->db->dbprefix('invoices').'.tax2_rate / 100) as tax2
FROM '.$this->db->dbprefix('invoices').' LEFT JOIN '.$this->db->dbprefix('invoice_items').' ON '.$this->db->dbprefix('invoices').'.id = '.$this->db->dbprefix('invoice_items').'.invoice_id WHERE '.$this->db->dbprefix('invoice_items').'.invoice_id =' . $invoice_id . ' AND '.$this->db->dbprefix('invoice_items').'.taxable2 =1 ) AS tmp_Tax_Total ) AS tmp_Total) AS total_tax2', FALSE);
$this->db->select('(SELECT SUM(total_notax + COALESCE(total_tax1,0) + COALESCE(total_tax2,0))) AS total_with_tax');
$this->db->join('clients', 'invoices.client_id = clients.id');
$this->db->join('invoice_items', 'invoices.id = invoice_items.invoice_id', 'left');
$this->db->join('invoice_payments', 'invoices.id = invoice_payments.invoice_id', 'left');
$this->db->groupby('invoices.id');
$this->db->where('invoices.id', $invoice_id);
return $this->db->get('invoices');
}
// --------------------------------------------------------------------
-> Line 238:
$this->db->select('TO_DAYS('.$this->db->dbprefix('invoices').'.dateIssued) - TO_DAYS(curdate()) AS daysOverdue', FALSE);
$this->db->select('(SELECT SUM('.$this->db->dbprefix('invoice_items').'.amount * '.$this->db->dbprefix('invoice_items').'.quantity) FROM '.$this->db->dbprefix('invoice_items').' WHERE '.$this->db->dbprefix('invoice_items').'.invoice_id='.$this->db->dbprefix('invoices').'.id) AS subtotal', FALSE);
$this->db->join('clients', 'invoices.client_id = clients.id');
***********
[/bamboo_system_files/application/views/invoices/edit.php]
-> Line 42:
<th><?php echo $this->lang->line('invoice_work_description');?></th>
<th><?php echo $this->lang->line('invoice_taxable1');?></th>
<th><?php echo $this->lang->line('invoice_taxable2');?></th>
<th><?php echo $this->lang->line('invoice_amount_item');?></th>
-> Line 64:
</td>
<td><p><label><input type="checkbox" name="items[<?php echo $item_count;?>][taxable1]" value="1" onclick="recalculate_items();" <?php if ($item->taxable1 == 1) {echo 'checked="checked" ';}?>/><span><?php echo $this->lang->line('invoice_taxable1');?>?</span></label></p></td>
<td><p><label><input type="checkbox" name="items[<?php echo $item_count;?>][taxable2]" value="1" onclick="recalculate_items();" <?php if ($item->taxable2 == 1) {echo 'checked="checked" ';}?>/><span><?php echo $this->lang->line('invoice_taxable2');?>?</span></label></p></td>
<td nowrap="nowrap"><p><label><span><?php echo $this->lang->line('invoice_amount');?></span><?php echo $this->settings_model->get_setting('currency_symbol');?><input type="text" id="amount" name="items[<?php echo $item_count;?>][amount]" size="5" value="<?php echo $item->amount;?>" onkeyup="recalculate_items();" value="" /></label></p></td>
***********
[/bamboo_system_files/application/views/invoices/newinvoice.php]
-> Line 38:
<th><?php echo $this->lang->line('invoice_work_description');?></th>
<th><?php echo $tax1_desc;?></th>
<th><?php echo $tax2_desc;?></th>
<th><?php echo $this->lang->line('invoice_amount_item');?></th>
-> Line 54:
</td>
<td><p><label><input type="checkbox" name="items[1][taxable1]" value="1" onclick="recalculate_items();" <?php if ($row->tax_status) {echo 'checked="checked" ';}?>/><span><?php echo $this->lang->line('invoice_taxable1');?>?</span></label></p></td>
<td><p><label><input type="checkbox" name="items[1][taxable2]" value="1" onclick="recalculate_items();" <?php if ($row->tax_status) {echo 'checked="checked" ';}?>/><span><?php echo $this->lang->line('invoice_taxable2');?>?</span></label></p></td> <td nowrap="nowrap"><p><label><span><?php echo $this->lang->line('invoice_amount');?></span><?php echo $this->settings_model->get_setting('currency_symbol');?><input type="text" id="amount" name="items[1][amount]" size="5" value="0.00" onkeyup="recalculate_items();" value="" /></label></p></td>
<td> </td>
***********
[/bamboo_system_files/application/views/invoices/view.php]
-> Line 169:
<td><?php echo auto_typography($item->work_description);?></td>
<td><p><?php echo $this->settings_model->get_setting('currency_symbol') . str_replace('.', $this->config->item('currency_decimal'), $item->amount);?> <?php if ($item->taxable1 == 0){echo '(' . $this->lang->line('invoice_item_no_tax1') . ')';}?>
<?php if ($item->taxable2 == 0){echo '(' . $this->lang->line('invoice_item_no_tax2') . ')';}?></p></td>
<td><p><?php echo $this->settings_model->get_setting('currency_symbol') . number_format($item->quantity * $item->amount, 2, $this->config->item('currency_decimal'), '');?></p></td>
***********
[/js/createinvoice.js]
-> Line 84:
theInput.setAttribute('type', 'checkbox');
theInput.setAttribute('name', 'items['+item_count+'][taxable1]');
if (taxable)
-> Line 105: ...insert the following...
var td = document.createElement('td');
var p = document.createElement('p');
var label = document.createElement('label');
var span = document.createElement('span');
var theData = document.createTextNode(lang_taxable);
var theInput = document.createElement('input');
theInput.setAttribute('type', 'checkbox');
theInput.setAttribute('name', 'items['+item_count+'][taxable2]');
if (taxable)
{
theInput.setAttribute('checked', 'checked');
}
else
{
theInput.checked = false;
}
theInput.setAttribute('value', '1');
theInput.setAttribute('onclick', 'recalculate_items();');
span.appendChild(theData);
label.appendChild(span);
label.appendChild(theInput);
p.appendChild(label);
td.appendChild(p);
row.appendChild(td);