mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-10 05:02:36 +01:00
Working on taxes
This commit is contained in:
parent
7a90856025
commit
309442cab3
@ -134,7 +134,7 @@ class InvoiceController extends \BaseController {
|
|||||||
return View::make('invoices.deleted');
|
return View::make('invoices.deleted');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($invoice->invoice_status_id < INVOICE_STATUS_VIEWED)
|
if (!$invoice->isViewed())
|
||||||
{
|
{
|
||||||
$invoice->invoice_status_id = INVOICE_STATUS_VIEWED;
|
$invoice->invoice_status_id = INVOICE_STATUS_VIEWED;
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
@ -241,15 +241,13 @@ class InvoiceController extends \BaseController {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
return Utils::fatalError('Sorry, there was an error processing your payment. Please try again later.<p>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (\Exception $e)
|
catch (\Exception $e)
|
||||||
{
|
{
|
||||||
exit('Sorry, there was an error processing your payment. Please try again later.<p>'.$e);
|
return Utils::fatalError('Sorry, there was an error processing your payment. Please try again later.<p>'.$e);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function do_payment()
|
public function do_payment()
|
||||||
@ -274,9 +272,12 @@ class InvoiceController extends \BaseController {
|
|||||||
$payment->transaction_reference = $ref;
|
$payment->transaction_reference = $ref;
|
||||||
$payment->save();
|
$payment->save();
|
||||||
|
|
||||||
if ($payment->amount >= $invoice->amount) {
|
if ($payment->amount >= $invoice->amount)
|
||||||
|
{
|
||||||
$invoice->invoice_status_id = INVOICE_STATUS_PAID;
|
$invoice->invoice_status_id = INVOICE_STATUS_PAID;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
$invoice->invoice_status_id = INVOICE_STATUS_PARTIAL;
|
$invoice->invoice_status_id = INVOICE_STATUS_PARTIAL;
|
||||||
}
|
}
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
@ -286,12 +287,12 @@ class InvoiceController extends \BaseController {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
exit($response->getMessage());
|
return Utils::fatalError('Sorry, there was an error processing your payment. Please try again later.<p>'.$response->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (\Exception $e)
|
catch (\Exception $e)
|
||||||
{
|
{
|
||||||
exit('Sorry, there was an error processing your payment. Please try again later.' . $e);
|
return Utils::fatalError('Sorry, there was an error processing your payment. Please try again later.<p>'.$e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,11 +405,16 @@ class InvoiceController extends \BaseController {
|
|||||||
$invoiceData['client_id'] = $client->id;
|
$invoiceData['client_id'] = $client->id;
|
||||||
$invoice = $this->invoiceRepo->save($publicId, $invoiceData);
|
$invoice = $this->invoiceRepo->save($publicId, $invoiceData);
|
||||||
|
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
if ($account->invoice_taxes != $input->invoice_taxes || $account->invoice_item_taxes != $input->invoice_item_taxes)
|
||||||
|
{
|
||||||
|
$account->invoice_taxes = $input->invoice_taxes;
|
||||||
|
$account->invoice_item_taxes = $input->invoice_item_taxes;
|
||||||
|
$account->save();
|
||||||
|
}
|
||||||
|
|
||||||
if ($action == 'email' && $invoice->invoice_status_id == INVOICE_STATUS_DRAFT)
|
if ($action == 'email' && $invoice->invoice_status_id == INVOICE_STATUS_DRAFT)
|
||||||
{
|
{
|
||||||
$invoice->invoice_status_id = INVOICE_STATUS_SENT;
|
|
||||||
$invoice->save();
|
|
||||||
|
|
||||||
$client->balance = $client->balance + $invoice->amount;
|
$client->balance = $client->balance + $invoice->amount;
|
||||||
$client->save();
|
$client->save();
|
||||||
}
|
}
|
||||||
|
@ -125,6 +125,9 @@ class ConfideSetupUsersTable extends Migration {
|
|||||||
$t->unsignedInteger('country_id')->nullable();
|
$t->unsignedInteger('country_id')->nullable();
|
||||||
$t->text('invoice_terms');
|
$t->text('invoice_terms');
|
||||||
|
|
||||||
|
$t->boolean('invoice_taxes')->default(true);
|
||||||
|
$t->boolean('invoice_item_taxes')->default(false);
|
||||||
|
|
||||||
$t->foreign('timezone_id')->references('id')->on('timezones');
|
$t->foreign('timezone_id')->references('id')->on('timezones');
|
||||||
$t->foreign('date_format_id')->references('id')->on('date_formats');
|
$t->foreign('date_format_id')->references('id')->on('date_formats');
|
||||||
$t->foreign('datetime_format_id')->references('id')->on('datetime_formats');
|
$t->foreign('datetime_format_id')->references('id')->on('datetime_formats');
|
||||||
@ -303,6 +306,9 @@ class ConfideSetupUsersTable extends Migration {
|
|||||||
$t->timestamp('last_sent_date')->nullable();
|
$t->timestamp('last_sent_date')->nullable();
|
||||||
$t->unsignedInteger('recurring_invoice_id')->index()->nullable();
|
$t->unsignedInteger('recurring_invoice_id')->index()->nullable();
|
||||||
|
|
||||||
|
$t->string('tax_name');
|
||||||
|
$t->decimal('tax_rate', 13, 4);
|
||||||
|
|
||||||
$t->decimal('amount', 13, 4);
|
$t->decimal('amount', 13, 4);
|
||||||
$t->decimal('balance', 13, 4);
|
$t->decimal('balance', 13, 4);
|
||||||
|
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
class Utils
|
class Utils
|
||||||
{
|
{
|
||||||
|
public static function fatalError($error)
|
||||||
|
{
|
||||||
|
Log::error($error);
|
||||||
|
return View::make('error')->with('error', $error);
|
||||||
|
}
|
||||||
|
|
||||||
public static function formatPhoneNumber($phoneNumber)
|
public static function formatPhoneNumber($phoneNumber)
|
||||||
{
|
{
|
||||||
$phoneNumber = preg_replace('/[^0-9]/','',$phoneNumber);
|
$phoneNumber = preg_replace('/[^0-9]/','',$phoneNumber);
|
||||||
|
@ -42,9 +42,15 @@ class Invoice extends EntityModel
|
|||||||
return $this->invoice_status_id >= INVOICE_STATUS_SENT;
|
return $this->invoice_status_id >= INVOICE_STATUS_SENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isViewed()
|
||||||
|
{
|
||||||
|
return $this->invoice_status_id >= INVOICE_STATUS_VIEWED;
|
||||||
|
}
|
||||||
|
|
||||||
public function hidePrivateFields()
|
public function hidePrivateFields()
|
||||||
{
|
{
|
||||||
$this->setVisible(['invoice_number', 'discount', 'po_number', 'invoice_date', 'due_date', 'terms', 'currency_id', 'public_notes', 'amount', 'balance', 'invoice_items', 'client']);
|
$this->setVisible(['invoice_number', 'discount', 'po_number', 'invoice_date', 'due_date', 'terms', 'currency_id', 'public_notes', 'amount', 'balance', 'invoice_items', 'client', 'tax_name', 'tax_rate']);
|
||||||
|
|
||||||
$this->client->setVisible(['name', 'address1', 'address2', 'city', 'state', 'postal_code', 'work_phone', 'payment_terms', 'contacts']);
|
$this->client->setVisible(['name', 'address1', 'address2', 'city', 'state', 'postal_code', 'work_phone', 'payment_terms', 'contacts']);
|
||||||
|
|
||||||
foreach ($this->invoice_items as $invoiceItem)
|
foreach ($this->invoice_items as $invoiceItem)
|
||||||
|
@ -80,7 +80,7 @@ class InvoiceRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
$invoice->client_id = $data['client_id'];
|
$invoice->client_id = $data['client_id'];
|
||||||
$invoice->discount = $data['discount'];
|
$invoice->discount = floatval($data['discount']);
|
||||||
$invoice->invoice_number = trim($data['invoice_number']);
|
$invoice->invoice_number = trim($data['invoice_number']);
|
||||||
$invoice->invoice_date = Utils::toSqlDate($data['invoice_date']);
|
$invoice->invoice_date = Utils::toSqlDate($data['invoice_date']);
|
||||||
$invoice->due_date = Utils::toSqlDate($data['due_date']);
|
$invoice->due_date = Utils::toSqlDate($data['due_date']);
|
||||||
@ -93,30 +93,19 @@ class InvoiceRepository
|
|||||||
$invoice->public_notes = trim($data['public_notes']);
|
$invoice->public_notes = trim($data['public_notes']);
|
||||||
$invoice->po_number = trim($data['po_number']);
|
$invoice->po_number = trim($data['po_number']);
|
||||||
$invoice->currency_id = $data['currency_id'];
|
$invoice->currency_id = $data['currency_id'];
|
||||||
|
$invoice->tax_rate = 0;
|
||||||
|
|
||||||
|
if (isset($data['tax']) && isset($data['tax']->rate) && floatval($data['tax']->rate) > 0)
|
||||||
|
{
|
||||||
|
$invoice->tax_rate = floatval($data['tax']->rate);
|
||||||
|
$invoice->tax_name = trim($data['tax']->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice->save();
|
||||||
|
$invoice->invoice_items()->forceDelete();
|
||||||
|
|
||||||
$total = 0;
|
$total = 0;
|
||||||
|
|
||||||
foreach ($data['invoice_items'] as $item)
|
|
||||||
{
|
|
||||||
if (!isset($item->cost))
|
|
||||||
{
|
|
||||||
$item->cost = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($item->qty))
|
|
||||||
{
|
|
||||||
$item->qty = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$total += floatval($item->qty) * floatval($item->cost);
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->amount = $total;
|
|
||||||
$invoice->balance = $total;
|
|
||||||
$invoice->save();
|
|
||||||
|
|
||||||
$invoice->invoice_items()->forceDelete();
|
|
||||||
|
|
||||||
foreach ($data['invoice_items'] as $item)
|
foreach ($data['invoice_items'] as $item)
|
||||||
{
|
{
|
||||||
if (!$item->cost && !$item->qty && !$item->product_key && !$item->notes)
|
if (!$item->cost && !$item->qty && !$item->product_key && !$item->notes)
|
||||||
@ -149,17 +138,31 @@ class InvoiceRepository
|
|||||||
$invoiceItem->notes = trim($item->notes);
|
$invoiceItem->notes = trim($item->notes);
|
||||||
$invoiceItem->cost = floatval($item->cost);
|
$invoiceItem->cost = floatval($item->cost);
|
||||||
$invoiceItem->qty = floatval($item->qty);
|
$invoiceItem->qty = floatval($item->qty);
|
||||||
|
$invoiceItem->tax_rate = 0;
|
||||||
|
|
||||||
if ($item->tax && isset($item->tax->rate) && isset($item->tax->name))
|
if ($item->tax && isset($item->tax->rate) && floatval($item->tax->rate) > 0)
|
||||||
{
|
{
|
||||||
$invoiceItem->tax_rate = floatval($item->tax->rate);
|
$invoiceItem->tax_rate = floatval($item->tax->rate);
|
||||||
$invoiceItem->tax_name = trim($item->tax->name);
|
$invoiceItem->tax_name = trim($item->tax->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice->invoice_items()->save($invoiceItem);
|
$invoice->invoice_items()->save($invoiceItem);
|
||||||
$total += floatval($item->qty) * floatval($item->cost);
|
|
||||||
|
$lineTotal = $invoiceItem->cost * $invoiceItem->qty;
|
||||||
|
$total += $lineTotal + ($lineTotal * $invoiceItem->tax_rate / 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($invoice->discount > 0)
|
||||||
|
{
|
||||||
|
$total *= (100 - $invoice->discount) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
$total += $total * $invoice->tax_rate / 100;
|
||||||
|
|
||||||
|
$invoice->amount = $total;
|
||||||
|
$invoice->balance = $total;
|
||||||
|
$invoice->save();
|
||||||
|
|
||||||
return $invoice;
|
return $invoice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
7
app/views/error.blade.php
Executable file
7
app/views/error.blade.php
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
@extends('header')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
{{ $error }}
|
||||||
|
|
||||||
|
@stop
|
@ -108,36 +108,36 @@
|
|||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
<th>Unit Cost</th>
|
<th>Unit Cost</th>
|
||||||
<th>Quantity</th>
|
<th>Quantity</th>
|
||||||
<th data-bind="visible: tax_rates().length > 1">Tax</th>
|
<th data-bind="visible: showInvoiceItemTaxes">Tax</th>
|
||||||
<th>Line Total</th>
|
<th>Line Total</th>
|
||||||
<th class="hide-border"></th>
|
<th class="hide-border"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody data-bind="sortable: { data: invoice_items, afterMove: onDragged }">
|
<tbody data-bind="sortable: { data: invoice_items, afterMove: onDragged }">
|
||||||
<tr data-bind="event: { mouseover: showActions, mouseout: hideActions }" class="sortable-row">
|
<tr data-bind="event: { mouseover: showActions, mouseout: hideActions }" class="sortable-row">
|
||||||
<td style="width:20px;" class="hide-border td-icon">
|
<td style="min-width:20px;" class="hide-border td-icon">
|
||||||
<i data-bind="visible: actionsVisible() && $parent.invoice_items().length > 1" class="fa fa-sort"></i>
|
<i data-bind="visible: actionsVisible() && $parent.invoice_items().length > 1" class="fa fa-sort"></i>
|
||||||
</td>
|
</td>
|
||||||
<td style="width:120px">
|
<td style="min-width:120px">
|
||||||
{{ Former::text('product_key')->useDatalist(Product::getProductKeys($products), 'key')->onkeyup('onItemChange()')
|
{{ Former::text('product_key')->useDatalist(Product::getProductKeys($products), 'key')->onkeyup('onItemChange()')
|
||||||
->raw()->data_bind("value: product_key, valueUpdate: 'afterkeydown'")->addClass('datalist') }}
|
->raw()->data_bind("value: product_key, valueUpdate: 'afterkeydown'")->addClass('datalist') }}
|
||||||
</td>
|
</td>
|
||||||
<td style="width:300px">
|
<td style="width:100%">
|
||||||
<textarea data-bind="value: wrapped_notes, valueUpdate: 'afterkeydown'" rows="1" cols="60" style="resize: none;" class="form-control word-wrap"></textarea>
|
<textarea data-bind="value: wrapped_notes, valueUpdate: 'afterkeydown'" rows="1" cols="60" style="resize: none;" class="form-control word-wrap"></textarea>
|
||||||
</td>
|
</td>
|
||||||
<td style="width:100px">
|
<td style="min-width:120px">
|
||||||
<input onkeyup="onItemChange()" data-bind="value: prettyCost, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control"//>
|
<input onkeyup="onItemChange()" data-bind="value: prettyCost, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control"//>
|
||||||
</td>
|
</td>
|
||||||
<td style="width:80px">
|
<td style="min-width:120px">
|
||||||
<input onkeyup="onItemChange()" data-bind="value: prettyQty, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control"//>
|
<input onkeyup="onItemChange()" data-bind="value: prettyQty, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control"//>
|
||||||
</td>
|
</td>
|
||||||
<td style="width:120px; vertical-align:middle" data-bind="visible: $parent.tax_rates().length > 1">
|
<td style="min-width:120px; vertical-align:middle" data-bind="visible: $parent.showInvoiceItemTaxes">
|
||||||
<select class="form-control" style="width:100%" data-bind="value: tax, options: $parent.tax_rates, optionsText: 'displayName'"></select>
|
<select class="form-control" style="width:100%" data-bind="value: tax, options: $parent.tax_rates, optionsText: 'displayName'"></select>
|
||||||
</td>
|
</td>
|
||||||
<td style="width:100px;text-align: right;padding-top:9px !important">
|
<td style="min-width:120px;text-align: right;padding-top:9px !important">
|
||||||
<span data-bind="text: total"></span>
|
<span data-bind="text: total"></span>
|
||||||
</td>
|
</td>
|
||||||
<td style="width:20px; cursor:pointer" class="hide-border td-icon">
|
<td style="min-width:20px; cursor:pointer" class="hide-border td-icon">
|
||||||
<i data-bind="click: $parent.removeItem, visible: actionsVisible() && $parent.invoice_items().length > 1" class="fa fa-minus-circle" title="Remove item"/>
|
<i data-bind="click: $parent.removeItem, visible: actionsVisible() && $parent.invoice_items().length > 1" class="fa fa-minus-circle" title="Remove item"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -145,22 +145,33 @@
|
|||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="hide-border"/>
|
<td class="hide-border"/>
|
||||||
<td data-bind="attr: {colspan: tax_rates().length > 1 ? 3 : 2}"/>
|
<td colspan="2"/>
|
||||||
|
<td data-bind="visible: showInvoiceItemTaxes"/>
|
||||||
<td colspan="2">Subtotal</td>
|
<td colspan="2">Subtotal</td>
|
||||||
<td style="text-align: right"><span data-bind="text: subtotal"/></td>
|
<td style="text-align: right"><span data-bind="text: subtotal"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-bind="visible: discount() > 0">
|
<tr data-bind="visible: discount() > 0">
|
||||||
<td class="hide-border" data-bind="attr: {colspan: tax_rates().length > 1 ? 4 : 3}"/>
|
<td class="hide-border" colspan="3"/>
|
||||||
|
<td class="hide-border" data-bind="visible: showInvoiceItemTaxes"/>
|
||||||
<td colspan="2">Discount</td>
|
<td colspan="2">Discount</td>
|
||||||
<td style="text-align: right"><span data-bind="text: discounted"/></td>
|
<td style="text-align: right"><span data-bind="text: discounted"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr data-bind="visible: showInvoiceTaxes">
|
||||||
|
<td class="hide-border" colspan="3"/>
|
||||||
|
<td class="hide-border" data-bind="visible: showInvoiceItemTaxes"/>
|
||||||
|
<td style="vertical-align: middle">Tax</td>
|
||||||
|
<td><select class="form-control" style="width:100%" data-bind="value: tax, options: tax_rates, optionsText: 'displayName'"></select></td>
|
||||||
|
<td style="vertical-align: middle; text-align: right"><span data-bind="text: taxAmount"/></td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="hide-border" data-bind="attr: {colspan: tax_rates().length > 1 ? 4 : 3}"/>
|
<td class="hide-border" colspan="3"/>
|
||||||
|
<td class="hide-border" data-bind="visible: showInvoiceItemTaxes"/>
|
||||||
<td colspan="2">Paid to Date</td>
|
<td colspan="2">Paid to Date</td>
|
||||||
<td style="text-align: right"></td>
|
<td style="text-align: right"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="hide-border" data-bind="attr: {colspan: tax_rates().length > 1 ? 4 : 3}"/>
|
<td class="hide-border" colspan="3"/>
|
||||||
|
<td class="hide-border" data-bind="visible: showInvoiceItemTaxes"/>
|
||||||
<td colspan="2"><b>Balance Due</b></td>
|
<td colspan="2"><b>Balance Due</b></td>
|
||||||
<td style="text-align: right"><span data-bind="text: total"/></td>
|
<td style="text-align: right"><span data-bind="text: total"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -319,6 +330,12 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
{{ Former::checkbox('invoice_taxes')->text('Enable specifying an <b>invoice tax</b>')
|
||||||
|
->label('Settings')->data_bind('checked: invoice_taxes, enable: tax_rates().length > 1') }}
|
||||||
|
{{ Former::checkbox('invoice_item_taxes')->text('Enable specifying <b>line item taxes</b>')
|
||||||
|
->label(' ')->data_bind('checked: invoice_item_taxes, enable: tax_rates().length > 1') }}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer" style="margin-top: 0px">
|
<div class="modal-footer" style="margin-top: 0px">
|
||||||
@ -394,9 +411,24 @@
|
|||||||
$('#taxModal').on('shown.bs.modal', function () {
|
$('#taxModal').on('shown.bs.modal', function () {
|
||||||
$('#taxModal input:first').focus();
|
$('#taxModal input:first').focus();
|
||||||
}).on('hidden.bs.modal', function () {
|
}).on('hidden.bs.modal', function () {
|
||||||
|
console.log('TAX HIDDEN: %s %s', model.invoice_taxes(), model.invoice_item_taxes())
|
||||||
|
/*
|
||||||
|
var blank = model.getBlankTaxRate();
|
||||||
|
if (!model.invoice_taxes()) {
|
||||||
|
model.tax(blank);
|
||||||
|
}
|
||||||
|
if (!model.invoice_item_taxes()) {
|
||||||
|
for (var i=0; i<model.invoice_items().length; i++) {
|
||||||
|
var item = model.invoice_items()[i];
|
||||||
|
item.tax(blank);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
if (model.taxBackup) {
|
if (model.taxBackup) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
})
|
})
|
||||||
|
|
||||||
$('#actionDropDown > button:first').click(function() {
|
$('#actionDropDown > button:first').click(function() {
|
||||||
@ -558,12 +590,16 @@
|
|||||||
self.due_date = ko.observable('');
|
self.due_date = ko.observable('');
|
||||||
self.start_date = ko.observable('');
|
self.start_date = ko.observable('');
|
||||||
self.end_date = ko.observable('');
|
self.end_date = ko.observable('');
|
||||||
|
self.tax = ko.observable('');
|
||||||
self.is_recurring = ko.observable(false);
|
self.is_recurring = ko.observable(false);
|
||||||
self.invoice_status_id = ko.observable(0);
|
self.invoice_status_id = ko.observable(0);
|
||||||
|
|
||||||
self.invoice_items = ko.observableArray();
|
self.invoice_items = ko.observableArray();
|
||||||
self.tax_rates = ko.observableArray();
|
self.tax_rates = ko.observableArray();
|
||||||
|
|
||||||
|
self.invoice_taxes = ko.observable({{ Auth::user()->account->invoice_taxes ? 'true' : 'false' }});
|
||||||
|
self.invoice_item_taxes = ko.observable({{ Auth::user()->account->invoice_item_taxes ? 'true' : 'false' }});
|
||||||
|
|
||||||
self.mapping = {
|
self.mapping = {
|
||||||
'invoice_items': {
|
'invoice_items': {
|
||||||
create: function(options) {
|
create: function(options) {
|
||||||
@ -590,6 +626,30 @@
|
|||||||
owner: this
|
owner: this
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.showInvoiceTaxes = ko.computed(function() {
|
||||||
|
if (self.tax_rates().length > 1 && self.invoice_taxes()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (self.tax() && self.tax().rate() > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
self.showInvoiceItemTaxes = ko.computed(function() {
|
||||||
|
if (self.tax_rates().length > 1 && self.invoice_item_taxes()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (var i=0; i<self.invoice_items().length; i++) {
|
||||||
|
var item = self.invoice_items()[i];
|
||||||
|
if (item.tax() && item.tax().rate() > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
self.wrapped_notes = ko.computed({
|
self.wrapped_notes = ko.computed({
|
||||||
read: function() {
|
read: function() {
|
||||||
$('#public_notes').height(this.public_notes().split('\n').length * 36);
|
$('#public_notes').height(this.public_notes().split('\n').length * 36);
|
||||||
@ -653,7 +713,7 @@
|
|||||||
|
|
||||||
$('#emailError').css( "display", "none" );
|
$('#emailError').css( "display", "none" );
|
||||||
//$('.client_select input.form-control').focus();
|
//$('.client_select input.form-control').focus();
|
||||||
$('#terms').focus();
|
$('#invoice_number').focus();
|
||||||
|
|
||||||
refreshPDF();
|
refreshPDF();
|
||||||
model.clientBackup = false;
|
model.clientBackup = false;
|
||||||
@ -682,6 +742,15 @@
|
|||||||
applyComboboxListeners();
|
applyComboboxListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.getBlankTaxRate = function() {
|
||||||
|
for (var i=0; i<self.tax_rates().length; i++) {
|
||||||
|
var taxRate = self.tax_rates()[i];
|
||||||
|
if (!taxRate.name()) {
|
||||||
|
return taxRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.rawSubtotal = ko.computed(function() {
|
this.rawSubtotal = ko.computed(function() {
|
||||||
var total = 0;
|
var total = 0;
|
||||||
for(var p = 0; p < self.invoice_items().length; ++p)
|
for(var p = 0; p < self.invoice_items().length; ++p)
|
||||||
@ -696,12 +765,32 @@
|
|||||||
return total > 0 ? formatMoney(total, self.currency_id()) : '';
|
return total > 0 ? formatMoney(total, self.currency_id()) : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.rawDiscounted = ko.computed(function() {
|
||||||
|
return self.rawSubtotal() * (self.discount()/100);
|
||||||
|
});
|
||||||
|
|
||||||
this.discounted = ko.computed(function() {
|
this.discounted = ko.computed(function() {
|
||||||
var total = self.rawSubtotal() * (self.discount()/100);
|
return formatMoney(self.rawDiscounted(), self.currency_id());
|
||||||
return formatMoney(total, self.currency_id());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
self.taxAmount = ko.computed(function() {
|
||||||
|
var total = self.rawSubtotal();
|
||||||
|
|
||||||
|
var discount = parseFloat(self.discount());
|
||||||
|
if (discount > 0) {
|
||||||
|
total = total * ((100 - discount)/100);
|
||||||
|
}
|
||||||
|
|
||||||
|
var taxRate = self.tax() ? parseFloat(self.tax().rate()) : 0;
|
||||||
|
if (taxRate > 0) {
|
||||||
|
var tax = total * (taxRate/100);
|
||||||
|
return formatMoney(tax, self.currency_id());
|
||||||
|
} else {
|
||||||
|
return formatMoney(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
this.total = ko.computed(function() {
|
this.total = ko.computed(function() {
|
||||||
var total = self.rawSubtotal();
|
var total = self.rawSubtotal();
|
||||||
|
|
||||||
@ -710,6 +799,11 @@
|
|||||||
total = total * ((100 - discount)/100);
|
total = total * ((100 - discount)/100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var taxRate = self.tax() ? parseFloat(self.tax().rate()) : 0;
|
||||||
|
if (taxRate > 0) {
|
||||||
|
total = parseFloat(total) + (total * (taxRate/100));
|
||||||
|
}
|
||||||
|
|
||||||
return total > 0 ? formatMoney(total, self.currency_id()) : '';
|
return total > 0 ? formatMoney(total, self.currency_id()) : '';
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -821,9 +915,9 @@
|
|||||||
|
|
||||||
|
|
||||||
self.displayName = ko.computed(function() {
|
self.displayName = ko.computed(function() {
|
||||||
var name = self.name() ? self.name() : false;
|
var name = self.name() ? self.name() : '';
|
||||||
var rate = self.rate() ? parseFloat(self.rate()) : false;
|
var rate = self.rate() ? parseFloat(self.rate()) + '% -' : '';
|
||||||
return (name && rate) ? (rate + '%' + ' - ' + name) : '';
|
return rate + name;
|
||||||
});
|
});
|
||||||
|
|
||||||
self.hideActions = function() {
|
self.hideActions = function() {
|
||||||
|
@ -32,7 +32,7 @@ function generatePDF(invoice) {
|
|||||||
for (var i=0; i<invoice.invoice_items.length; i++)
|
for (var i=0; i<invoice.invoice_items.length; i++)
|
||||||
{
|
{
|
||||||
var item = invoice.invoice_items[i];
|
var item = invoice.invoice_items[i];
|
||||||
if (item.tax && item.tax.rate > 0) {
|
if ((item.tax && item.tax.rate > 0) || (item.tax_rate && parseFloat(item.tax_rate) > 0)) {
|
||||||
hasTaxes = true;
|
hasTaxes = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -141,7 +141,12 @@ function generatePDF(invoice) {
|
|||||||
var qty = item.qty ? parseFloat(item.qty) + '' : '';
|
var qty = item.qty ? parseFloat(item.qty) + '' : '';
|
||||||
var notes = item.notes;
|
var notes = item.notes;
|
||||||
var productKey = item.product_key;
|
var productKey = item.product_key;
|
||||||
var tax = item.tax && parseFloat(item.tax.rate) ? parseFloat(item.tax.rate) + '%' : false;
|
var tax = 0;
|
||||||
|
if (item.tax && parseFloat(item.tax.rate)) {
|
||||||
|
tax = parseFloat(item.tax.rate);
|
||||||
|
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
|
||||||
|
tax = parseFloat(item.tax_rate);
|
||||||
|
}
|
||||||
|
|
||||||
// show at most one blank line
|
// show at most one blank line
|
||||||
if (shownItem && (!cost || cost == '0.00') && !qty && !notes && !productKey) {
|
if (shownItem && (!cost || cost == '0.00') && !qty && !notes && !productKey) {
|
||||||
@ -155,7 +160,7 @@ function generatePDF(invoice) {
|
|||||||
|
|
||||||
var lineTotal = item.cost * item.qty;
|
var lineTotal = item.cost * item.qty;
|
||||||
if (tax) {
|
if (tax) {
|
||||||
lineTotal += lineTotal * parseFloat(item.tax.rate) / 100;
|
lineTotal += lineTotal * tax / 100;
|
||||||
}
|
}
|
||||||
if (lineTotal) {
|
if (lineTotal) {
|
||||||
total += lineTotal;
|
total += lineTotal;
|
||||||
@ -164,7 +169,7 @@ function generatePDF(invoice) {
|
|||||||
|
|
||||||
var costX = unitCostRight - (doc.getStringUnitWidth(cost) * doc.internal.getFontSize());
|
var costX = unitCostRight - (doc.getStringUnitWidth(cost) * doc.internal.getFontSize());
|
||||||
var qtyX = qtyRight - (doc.getStringUnitWidth(qty) * doc.internal.getFontSize());
|
var qtyX = qtyRight - (doc.getStringUnitWidth(qty) * doc.internal.getFontSize());
|
||||||
var taxX = taxRight - (doc.getStringUnitWidth(tax) * doc.internal.getFontSize());
|
var taxX = taxRight - (doc.getStringUnitWidth(tax+'%') * doc.internal.getFontSize());
|
||||||
var totalX = lineTotalRight - (doc.getStringUnitWidth(lineTotal) * doc.internal.getFontSize());
|
var totalX = lineTotalRight - (doc.getStringUnitWidth(lineTotal) * doc.internal.getFontSize());
|
||||||
var x = tableTop + (line * tableRowHeight) + 6;
|
var x = tableTop + (line * tableRowHeight) + 6;
|
||||||
if (i==0) x -= 4;
|
if (i==0) x -= 4;
|
||||||
@ -176,7 +181,7 @@ function generatePDF(invoice) {
|
|||||||
doc.text(totalX, x, lineTotal);
|
doc.text(totalX, x, lineTotal);
|
||||||
|
|
||||||
if (tax) {
|
if (tax) {
|
||||||
doc.text(taxX, x, tax);
|
doc.text(taxX, x, tax+'%');
|
||||||
}
|
}
|
||||||
|
|
||||||
line += doc.splitTextToSize(item.notes, 200).length;
|
line += doc.splitTextToSize(item.notes, 200).length;
|
||||||
@ -206,12 +211,30 @@ function generatePDF(invoice) {
|
|||||||
|
|
||||||
x += 16;
|
x += 16;
|
||||||
doc.text(footerLeft, x, 'Discount');
|
doc.text(footerLeft, x, 'Discount');
|
||||||
var discount = formatMoney(total * (invoice.discount/100), currencyId, true);
|
var discount = total * (invoice.discount/100);
|
||||||
total -= discount;
|
total -= discount;
|
||||||
|
discount = formatMoney(discount, currencyId, true);
|
||||||
var discountX = headerRight - (doc.getStringUnitWidth(discount) * doc.internal.getFontSize());
|
var discountX = headerRight - (doc.getStringUnitWidth(discount) * doc.internal.getFontSize());
|
||||||
doc.text(discountX, x, discount);
|
doc.text(discountX, x, discount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tax = 0;
|
||||||
|
if (invoice.tax && parseFloat(invoice.tax.rate)) {
|
||||||
|
tax = parseFloat(invoice.tax.rate);
|
||||||
|
} else if (invoice.tax_rate && parseFloat(invoice.tax_rate)) {
|
||||||
|
tax = parseFloat(invoice.tax_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tax) {
|
||||||
|
x += 16;
|
||||||
|
doc.text(footerLeft, x, 'Tax ' + tax + '%');
|
||||||
|
var tax = total * (tax/100);
|
||||||
|
total = parseFloat(total) + parseFloat(tax);
|
||||||
|
tax = formatMoney(tax, currencyId, true);
|
||||||
|
var taxX = headerRight - (doc.getStringUnitWidth(tax) * doc.internal.getFontSize());
|
||||||
|
doc.text(taxX, x, tax);
|
||||||
|
}
|
||||||
|
|
||||||
x += 16;
|
x += 16;
|
||||||
doc.text(footerLeft, x, 'Paid to Date');
|
doc.text(footerLeft, x, 'Paid to Date');
|
||||||
var paid = formatMoney(0, currencyId, true);
|
var paid = formatMoney(0, currencyId, true);
|
||||||
|
Loading…
Reference in New Issue
Block a user