mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-17 16:42:48 +01:00
Support for multiple tax rates
This commit is contained in:
parent
f91f32323f
commit
be9e7beaed
@ -258,10 +258,11 @@ class InvoiceApiController extends BaseAPIController
|
|||||||
// initialize the line items
|
// initialize the line items
|
||||||
if (isset($data['product_key']) || isset($data['cost']) || isset($data['notes']) || isset($data['qty'])) {
|
if (isset($data['product_key']) || isset($data['cost']) || isset($data['notes']) || isset($data['qty'])) {
|
||||||
$data['invoice_items'] = [self::prepareItem($data)];
|
$data['invoice_items'] = [self::prepareItem($data)];
|
||||||
|
|
||||||
// make sure the tax isn't applied twice (for the invoice and the line item)
|
// make sure the tax isn't applied twice (for the invoice and the line item)
|
||||||
unset($data['invoice_items'][0]['tax_name']);
|
unset($data['invoice_items'][0]['tax_name1']);
|
||||||
unset($data['invoice_items'][0]['tax_rate']);
|
unset($data['invoice_items'][0]['tax_rate1']);
|
||||||
|
unset($data['invoice_items'][0]['tax_name2']);
|
||||||
|
unset($data['invoice_items'][0]['tax_rate2']);
|
||||||
} else {
|
} else {
|
||||||
foreach ($data['invoice_items'] as $index => $item) {
|
foreach ($data['invoice_items'] as $index => $item) {
|
||||||
$data['invoice_items'][$index] = self::prepareItem($item);
|
$data['invoice_items'][$index] = self::prepareItem($item);
|
||||||
|
@ -25,6 +25,13 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
protected $presenter = 'App\Ninja\Presenters\InvoicePresenter';
|
protected $presenter = 'App\Ninja\Presenters\InvoicePresenter';
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['deleted_at'];
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'tax_name1',
|
||||||
|
'tax_rate1',
|
||||||
|
'tax_name2',
|
||||||
|
'tax_rate2',
|
||||||
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'is_recurring' => 'boolean',
|
'is_recurring' => 'boolean',
|
||||||
'has_tasks' => 'boolean',
|
'has_tasks' => 'boolean',
|
||||||
@ -394,8 +401,10 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
'documents',
|
'documents',
|
||||||
'expenses',
|
'expenses',
|
||||||
'client',
|
'client',
|
||||||
'tax_name',
|
'tax_name1',
|
||||||
'tax_rate',
|
'tax_rate1',
|
||||||
|
'tax_name2',
|
||||||
|
'tax_rate2',
|
||||||
'account',
|
'account',
|
||||||
'invoice_design',
|
'invoice_design',
|
||||||
'invoice_design_id',
|
'invoice_design_id',
|
||||||
@ -476,8 +485,10 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
'custom_value2',
|
'custom_value2',
|
||||||
'cost',
|
'cost',
|
||||||
'qty',
|
'qty',
|
||||||
'tax_name',
|
'tax_name1',
|
||||||
'tax_rate',
|
'tax_rate1',
|
||||||
|
'tax_name2',
|
||||||
|
'tax_rate2',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,54 +854,68 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
return $total;
|
return $total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if $calculatePaid is true we'll loop through each payment to
|
||||||
|
// determine the sum, otherwise we'll use the cached paid_to_date amount
|
||||||
public function getTaxes($calculatePaid = false)
|
public function getTaxes($calculatePaid = false)
|
||||||
{
|
{
|
||||||
$taxes = [];
|
$taxes = [];
|
||||||
$taxable = $this->getTaxable();
|
$taxable = $this->getTaxable();
|
||||||
|
$paidAmount = $this->getAmountPaid($calculatePaid);
|
||||||
if ($this->tax_rate && $this->tax_name) {
|
|
||||||
$taxAmount = $taxable * ($this->tax_rate / 100);
|
if ($this->tax_name1) {
|
||||||
$taxAmount = round($taxAmount, 2);
|
$invoiceTaxAmount = round($taxable * ($this->tax_rate1 / 100), 2);
|
||||||
|
$invoicePaidAmount = $this->amount && $invoiceTaxAmount ? ($paidAmount / $this->amount * $invoiceTaxAmount) : 0;
|
||||||
|
$this->calculateTax($taxes, $this->tax_name1, $this->tax_rate1, $invoiceTaxAmount, $invoicePaidAmount);
|
||||||
|
}
|
||||||
|
|
||||||
if ($taxAmount) {
|
if ($this->tax_name2) {
|
||||||
$taxes[$this->tax_rate . ' ' . $this->tax_name] = [
|
$invoiceTaxAmount = round($taxable * ($this->tax_rate2 / 100), 2);
|
||||||
'name' => $this->tax_name,
|
$invoicePaidAmount = $this->amount && $invoiceTaxAmount ? ($paidAmount / $this->amount * $invoiceTaxAmount) : 0;
|
||||||
'rate' => $this->tax_rate+0,
|
$this->calculateTax($taxes, $this->tax_name2, $this->tax_rate2, $invoiceTaxAmount, $invoicePaidAmount);
|
||||||
'amount' => $taxAmount,
|
|
||||||
'paid' => round($this->getAmountPaid($calculatePaid) / $this->amount * $taxAmount, 2)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->invoice_items as $invoiceItem) {
|
foreach ($this->invoice_items as $invoiceItem) {
|
||||||
if ( ! $invoiceItem->tax_rate || ! $invoiceItem->tax_name) {
|
$itemTaxAmount = $this->getItemTaxable($invoiceItem, $taxable);
|
||||||
continue;
|
|
||||||
|
if ($invoiceItem->tax_name1) {
|
||||||
|
$itemTaxAmount = round($taxable * ($invoiceItem->tax_rate1 / 100), 2);
|
||||||
|
$itemPaidAmount = $this->amount && $itemTaxAmount ? ($paidAmount / $this->amount * $itemTaxAmount) : 0;
|
||||||
|
$this->calculateTax($taxes, $invoiceItem->tax_name1, $invoiceItem->tax_rate1, $itemTaxAmount, $itemPaidAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
$taxAmount = $this->getItemTaxable($invoiceItem, $taxable);
|
if ($invoiceItem->tax_name2) {
|
||||||
$taxAmount = $taxable * ($invoiceItem->tax_rate / 100);
|
$itemTaxAmount = round($taxable * ($invoiceItem->tax_rate2 / 100), 2);
|
||||||
$taxAmount = round($taxAmount, 2);
|
$itemPaidAmount = $this->amount && $itemTaxAmount ? ($paidAmount / $this->amount * $itemTaxAmount) : 0;
|
||||||
|
$this->calculateTax($taxes, $invoiceItem->tax_name2, $invoiceItem->tax_rate2, $itemTaxAmount, $itemPaidAmount);
|
||||||
if ($taxAmount) {
|
|
||||||
$key = $invoiceItem->tax_rate . ' ' . $invoiceItem->tax_name;
|
|
||||||
|
|
||||||
if ( ! isset($taxes[$key])) {
|
|
||||||
$taxes[$key] = [
|
|
||||||
'amount' => 0,
|
|
||||||
'paid' => 0
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$taxes[$key]['amount'] += $taxAmount;
|
|
||||||
$taxes[$key]['paid'] += $this->amount && $taxAmount ? round($this->getAmountPaid($calculatePaid) / $this->amount * $taxAmount, 2) : 0;
|
|
||||||
$taxes[$key]['name'] = $invoiceItem->tax_name;
|
|
||||||
$taxes[$key]['rate'] = $invoiceItem->tax_rate+0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $taxes;
|
return $taxes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function calculateTax(&$taxes, $name, $rate, $amount, $paid)
|
||||||
|
{
|
||||||
|
if ( ! $amount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = round($amount, 2);
|
||||||
|
$paid = round($paid, 2);
|
||||||
|
$key = $rate . ' ' . $name;
|
||||||
|
|
||||||
|
if ( ! isset($taxes[$key])) {
|
||||||
|
$taxes[$key] = [
|
||||||
|
'name' => $name,
|
||||||
|
'rate' => $rate+0,
|
||||||
|
'amount' => 0,
|
||||||
|
'paid' => 0
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$taxes[$key]['amount'] += $amount;
|
||||||
|
$taxes[$key]['paid'] += $paid;
|
||||||
|
}
|
||||||
|
|
||||||
public function hasDocuments(){
|
public function hasDocuments(){
|
||||||
if(count($this->documents))return true;
|
if(count($this->documents))return true;
|
||||||
return $this->hasExpenseDocuments();
|
return $this->hasExpenseDocuments();
|
||||||
|
@ -7,6 +7,13 @@ class InvoiceItem extends EntityModel
|
|||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['deleted_at'];
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'tax_name1',
|
||||||
|
'tax_rate1',
|
||||||
|
'tax_name2',
|
||||||
|
'tax_rate2',
|
||||||
|
];
|
||||||
|
|
||||||
public function invoice()
|
public function invoice()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\Invoice');
|
return $this->belongsTo('App\Models\Invoice');
|
||||||
|
@ -221,6 +221,8 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoice = Invoice::scope($publicId)->firstOrFail();
|
$invoice = Invoice::scope($publicId)->firstOrFail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$invoice->fill($data);
|
||||||
|
|
||||||
if ((isset($data['set_default_terms']) && $data['set_default_terms'])
|
if ((isset($data['set_default_terms']) && $data['set_default_terms'])
|
||||||
|| (isset($data['set_default_footer']) && $data['set_default_footer'])) {
|
|| (isset($data['set_default_footer']) && $data['set_default_footer'])) {
|
||||||
if (isset($data['set_default_terms']) && $data['set_default_terms']) {
|
if (isset($data['set_default_terms']) && $data['set_default_terms']) {
|
||||||
@ -297,12 +299,10 @@ class InvoiceRepository extends BaseRepository
|
|||||||
|
|
||||||
$invoice->invoice_design_id = isset($data['invoice_design_id']) ? $data['invoice_design_id'] : $account->invoice_design_id;
|
$invoice->invoice_design_id = isset($data['invoice_design_id']) ? $data['invoice_design_id'] : $account->invoice_design_id;
|
||||||
|
|
||||||
if (isset($data['tax_name']) && isset($data['tax_rate']) && $data['tax_name']) {
|
// provide backwards compatability
|
||||||
$invoice->tax_rate = Utils::parseFloat($data['tax_rate']);
|
if (isset($data['tax_name']) && isset($data['tax_rate'])) {
|
||||||
$invoice->tax_name = trim($data['tax_name']);
|
$data['tax_name1'] = $data['tax_name'];
|
||||||
} else {
|
$data['tax_rate1'] = $data['tax_rate'];
|
||||||
$invoice->tax_rate = 0;
|
|
||||||
$invoice->tax_name = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$total = 0;
|
$total = 0;
|
||||||
@ -323,20 +323,24 @@ class InvoiceRepository extends BaseRepository
|
|||||||
|
|
||||||
foreach ($data['invoice_items'] as $item) {
|
foreach ($data['invoice_items'] as $item) {
|
||||||
$item = (array) $item;
|
$item = (array) $item;
|
||||||
if (isset($item['tax_rate']) && Utils::parseFloat($item['tax_rate']) > 0) {
|
$invoiceItemCost = round(Utils::parseFloat($item['cost']), 2);
|
||||||
$invoiceItemCost = round(Utils::parseFloat($item['cost']), 2);
|
$invoiceItemQty = round(Utils::parseFloat($item['qty']), 2);
|
||||||
$invoiceItemQty = round(Utils::parseFloat($item['qty']), 2);
|
$lineTotal = $invoiceItemCost * $invoiceItemQty;
|
||||||
$invoiceItemTaxRate = Utils::parseFloat($item['tax_rate']);
|
|
||||||
$lineTotal = $invoiceItemCost * $invoiceItemQty;
|
|
||||||
|
|
||||||
if ($invoice->discount > 0) {
|
if ($invoice->discount > 0) {
|
||||||
if ($invoice->is_amount_discount) {
|
if ($invoice->is_amount_discount) {
|
||||||
$lineTotal -= round(($lineTotal/$total) * $invoice->discount, 2);
|
$lineTotal -= round(($lineTotal/$total) * $invoice->discount, 2);
|
||||||
} else {
|
} else {
|
||||||
$lineTotal -= round($lineTotal * ($invoice->discount/100), 2);
|
$lineTotal -= round($lineTotal * ($invoice->discount/100), 2);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($item['tax_rate1']) && Utils::parseFloat($item['tax_rate1']) > 0) {
|
||||||
|
$invoiceItemTaxRate = Utils::parseFloat($item['tax_rate1']);
|
||||||
|
$itemTax += round($lineTotal * $invoiceItemTaxRate / 100, 2);
|
||||||
|
}
|
||||||
|
if (isset($item['tax_rate2']) && Utils::parseFloat($item['tax_rate2']) > 0) {
|
||||||
|
$invoiceItemTaxRate = Utils::parseFloat($item['tax_rate2']);
|
||||||
$itemTax += round($lineTotal * $invoiceItemTaxRate / 100, 2);
|
$itemTax += round($lineTotal * $invoiceItemTaxRate / 100, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,8 +382,9 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$total += $invoice->custom_value2;
|
$total += $invoice->custom_value2;
|
||||||
}
|
}
|
||||||
|
|
||||||
$total += $total * $invoice->tax_rate / 100;
|
$taxAmount1 = round($total * $invoice->tax_rate1 / 100, 2);
|
||||||
$total = round($total, 2);
|
$taxAmount2 = round($total * $invoice->tax_rate2 / 100, 2);
|
||||||
|
$total = round($total + $taxAmount1 + $taxAmount2, 2);
|
||||||
$total += $itemTax;
|
$total += $itemTax;
|
||||||
|
|
||||||
// custom fields not charged taxes
|
// custom fields not charged taxes
|
||||||
@ -502,7 +507,7 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoiceItem->notes = trim($invoice->is_recurring ? $item['notes'] : Utils::processVariables($item['notes']));
|
$invoiceItem->notes = trim($invoice->is_recurring ? $item['notes'] : Utils::processVariables($item['notes']));
|
||||||
$invoiceItem->cost = Utils::parseFloat($item['cost']);
|
$invoiceItem->cost = Utils::parseFloat($item['cost']);
|
||||||
$invoiceItem->qty = Utils::parseFloat($item['qty']);
|
$invoiceItem->qty = Utils::parseFloat($item['qty']);
|
||||||
$invoiceItem->tax_rate = 0;
|
//$invoiceItem->tax_rate = 0;
|
||||||
|
|
||||||
if (isset($item['custom_value1'])) {
|
if (isset($item['custom_value1'])) {
|
||||||
$invoiceItem->custom_value1 = $item['custom_value1'];
|
$invoiceItem->custom_value1 = $item['custom_value1'];
|
||||||
@ -511,11 +516,14 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoiceItem->custom_value2 = $item['custom_value2'];
|
$invoiceItem->custom_value2 = $item['custom_value2'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($item['tax_rate']) && isset($item['tax_name']) && $item['tax_name']) {
|
// provide backwards compatability
|
||||||
$invoiceItem['tax_rate'] = Utils::parseFloat($item['tax_rate']);
|
if (isset($item['tax_name']) && isset($item['tax_rate'])) {
|
||||||
$invoiceItem['tax_name'] = trim($item['tax_name']);
|
$item['tax_name1'] = $item['tax_name'];
|
||||||
|
$item['tax_rate1'] = $item['tax_rate'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$invoiceItem->fill($item);
|
||||||
|
|
||||||
$invoice->invoice_items()->save($invoiceItem);
|
$invoice->invoice_items()->save($invoiceItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,8 +570,10 @@ class InvoiceRepository extends BaseRepository
|
|||||||
'invoice_footer',
|
'invoice_footer',
|
||||||
'public_notes',
|
'public_notes',
|
||||||
'invoice_design_id',
|
'invoice_design_id',
|
||||||
'tax_name',
|
'tax_name1',
|
||||||
'tax_rate',
|
'tax_rate1',
|
||||||
|
'tax_name2',
|
||||||
|
'tax_rate2',
|
||||||
'amount',
|
'amount',
|
||||||
'is_quote',
|
'is_quote',
|
||||||
'custom_value1',
|
'custom_value1',
|
||||||
@ -597,8 +607,11 @@ class InvoiceRepository extends BaseRepository
|
|||||||
'notes',
|
'notes',
|
||||||
'cost',
|
'cost',
|
||||||
'qty',
|
'qty',
|
||||||
'tax_name',
|
'tax_name1',
|
||||||
'tax_rate', ] as $field) {
|
'tax_rate1',
|
||||||
|
'tax_name2',
|
||||||
|
'tax_rate2',
|
||||||
|
] as $field) {
|
||||||
$cloneItem->$field = $item->$field;
|
$cloneItem->$field = $item->$field;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,8 +702,10 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoice->public_notes = Utils::processVariables($recurInvoice->public_notes);
|
$invoice->public_notes = Utils::processVariables($recurInvoice->public_notes);
|
||||||
$invoice->terms = Utils::processVariables($recurInvoice->terms);
|
$invoice->terms = Utils::processVariables($recurInvoice->terms);
|
||||||
$invoice->invoice_footer = Utils::processVariables($recurInvoice->invoice_footer);
|
$invoice->invoice_footer = Utils::processVariables($recurInvoice->invoice_footer);
|
||||||
$invoice->tax_name = $recurInvoice->tax_name;
|
$invoice->tax_name1 = $recurInvoice->tax_name1;
|
||||||
$invoice->tax_rate = $recurInvoice->tax_rate;
|
$invoice->tax_rate1 = $recurInvoice->tax_rate1;
|
||||||
|
$invoice->tax_name2 = $recurInvoice->tax_name2;
|
||||||
|
$invoice->tax_rate2 = $recurInvoice->tax_rate2;
|
||||||
$invoice->invoice_design_id = $recurInvoice->invoice_design_id;
|
$invoice->invoice_design_id = $recurInvoice->invoice_design_id;
|
||||||
$invoice->custom_value1 = $recurInvoice->custom_value1 ?: 0;
|
$invoice->custom_value1 = $recurInvoice->custom_value1 ?: 0;
|
||||||
$invoice->custom_value2 = $recurInvoice->custom_value2 ?: 0;
|
$invoice->custom_value2 = $recurInvoice->custom_value2 ?: 0;
|
||||||
@ -709,8 +724,10 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$item->cost = $recurItem->cost;
|
$item->cost = $recurItem->cost;
|
||||||
$item->notes = Utils::processVariables($recurItem->notes);
|
$item->notes = Utils::processVariables($recurItem->notes);
|
||||||
$item->product_key = Utils::processVariables($recurItem->product_key);
|
$item->product_key = Utils::processVariables($recurItem->product_key);
|
||||||
$item->tax_name = $recurItem->tax_name;
|
$item->tax_name1 = $recurItem->tax_name1;
|
||||||
$item->tax_rate = $recurItem->tax_rate;
|
$item->tax_rate1 = $recurItem->tax_rate1;
|
||||||
|
$item->tax_name2 = $recurItem->tax_name2;
|
||||||
|
$item->tax_rate2 = $recurItem->tax_rate2;
|
||||||
$invoice->invoice_items()->save($item);
|
$invoice->invoice_items()->save($item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,10 @@ class InvoiceItemTransformer extends EntityTransformer
|
|||||||
'notes' => $item->notes,
|
'notes' => $item->notes,
|
||||||
'cost' => (float) $item->cost,
|
'cost' => (float) $item->cost,
|
||||||
'qty' => (float) $item->qty,
|
'qty' => (float) $item->qty,
|
||||||
'tax_name' => $item->tax_name,
|
'tax_name1' => $item->tax_name1,
|
||||||
'tax_rate' => (float) $item->tax_rate
|
'tax_rate1' => (float) $item->tax_rate1,
|
||||||
|
'tax_name2' => $item->tax_name2,
|
||||||
|
'tax_rate2' => (float) $item->tax_rate2,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -87,8 +87,10 @@ class InvoiceTransformer extends EntityTransformer
|
|||||||
'end_date' => $invoice->end_date,
|
'end_date' => $invoice->end_date,
|
||||||
'last_sent_date' => $invoice->last_sent_date,
|
'last_sent_date' => $invoice->last_sent_date,
|
||||||
'recurring_invoice_id' => (int) $invoice->recurring_invoice_id,
|
'recurring_invoice_id' => (int) $invoice->recurring_invoice_id,
|
||||||
'tax_name' => $invoice->tax_name,
|
'tax_name1' => $invoice->tax_name1,
|
||||||
'tax_rate' => (float) $invoice->tax_rate,
|
'tax_rate1' => (float) $invoice->tax_rate1,
|
||||||
|
'tax_name2' => $invoice->tax_name2,
|
||||||
|
'tax_rate2' => (float) $invoice->tax_rate2,
|
||||||
'amount' => (float) $invoice->amount,
|
'amount' => (float) $invoice->amount,
|
||||||
'balance' => (float) $invoice->balance,
|
'balance' => (float) $invoice->balance,
|
||||||
'is_amount_discount' => (bool) $invoice->is_amount_discount,
|
'is_amount_discount' => (bool) $invoice->is_amount_discount,
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"turbo124/laravel-push-notification": "dev-laravel5",
|
"turbo124/laravel-push-notification": "dev-laravel5",
|
||||||
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
|
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
|
||||||
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
|
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
|
||||||
"omnipay/gocardless": "dev-master",
|
"omnipay/gocardless": "dev-master",
|
||||||
|
@ -14,10 +14,24 @@ class SupportMultipleTaxRates extends Migration
|
|||||||
{
|
{
|
||||||
Schema::table('invoices', function($table) {
|
Schema::table('invoices', function($table) {
|
||||||
$table->decimal('tax_rate', 13, 3)->change();
|
$table->decimal('tax_rate', 13, 3)->change();
|
||||||
});
|
});
|
||||||
|
|
||||||
Schema::table('invoice_items', function($table) {
|
Schema::table('invoice_items', function($table) {
|
||||||
$table->decimal('tax_rate', 13, 3)->change();
|
$table->decimal('tax_rate', 13, 3)->change();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('invoices', function($table) {
|
||||||
|
$table->renameColumn('tax_rate', 'tax_rate1');
|
||||||
|
$table->renameColumn('tax_name', 'tax_name1');
|
||||||
|
$table->string('tax_name2')->nullable();
|
||||||
|
$table->decimal('tax_rate2', 13, 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('invoice_items', function($table) {
|
||||||
|
$table->renameColumn('tax_rate', 'tax_rate1');
|
||||||
|
$table->renameColumn('tax_name', 'tax_name1');
|
||||||
|
$table->string('tax_name2')->nullable();
|
||||||
|
$table->decimal('tax_rate2', 13, 3);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -28,11 +42,19 @@ class SupportMultipleTaxRates extends Migration
|
|||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
Schema::table('invoices', function($table) {
|
Schema::table('invoices', function($table) {
|
||||||
$table->decimal('tax_rate', 13, 2)->change();
|
$table->decimal('tax_rate1', 13, 2)->change();
|
||||||
|
$table->renameColumn('tax_rate1', 'tax_rate');
|
||||||
|
$table->renameColumn('tax_name1', 'tax_name');
|
||||||
|
$table->dropColumn('tax_name2');
|
||||||
|
$table->dropColumn('tax_rate2');
|
||||||
});
|
});
|
||||||
|
|
||||||
Schema::table('invoice_items', function($table) {
|
Schema::table('invoice_items', function($table) {
|
||||||
$table->decimal('tax_rate', 13, 2)->change();
|
$table->decimal('tax_rate1', 13, 2)->change();
|
||||||
|
$table->renameColumn('tax_rate1', 'tax_rate');
|
||||||
|
$table->renameColumn('tax_name1', 'tax_name');
|
||||||
|
$table->dropColumn('tax_name2');
|
||||||
|
$table->dropColumn('tax_rate2');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -30497,8 +30497,10 @@ function calculateAmounts(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];
|
||||||
var taxRate = 0;
|
var taxRate1 = 0;
|
||||||
var taxName = '';
|
var taxName1 = '';
|
||||||
|
var taxRate2 = 0;
|
||||||
|
var taxName2 = '';
|
||||||
|
|
||||||
if (item.product_key) {
|
if (item.product_key) {
|
||||||
invoice.has_product_key = true;
|
invoice.has_product_key = true;
|
||||||
@ -30506,9 +30508,14 @@ function calculateAmounts(invoice) {
|
|||||||
invoice.has_product_key = true;
|
invoice.has_product_key = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.tax_rate && parseFloat(item.tax_rate)) {
|
if (item.tax_rate1 && parseFloat(item.tax_rate1)) {
|
||||||
taxRate = parseFloat(item.tax_rate);
|
taxRate1 = parseFloat(item.tax_rate1);
|
||||||
taxName = item.tax_name;
|
taxName1 = item.tax_name1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.tax_rate2 && parseFloat(item.tax_rate2)) {
|
||||||
|
taxRate2 = parseFloat(item.tax_rate2);
|
||||||
|
taxName2 = item.tax_name2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate line item tax
|
// calculate line item tax
|
||||||
@ -30520,18 +30527,28 @@ function calculateAmounts(invoice) {
|
|||||||
lineTotal -= roundToTwo(lineTotal * (invoice.discount/100));
|
lineTotal -= roundToTwo(lineTotal * (invoice.discount/100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var taxAmount = roundToTwo(lineTotal * taxRate / 100);
|
|
||||||
|
var taxAmount1 = roundToTwo(lineTotal * taxRate1 / 100);
|
||||||
if (taxAmount) {
|
if (taxAmount1) {
|
||||||
var key = taxName + taxRate;
|
var key = taxName1 + taxRate1;
|
||||||
if (taxes.hasOwnProperty(key)) {
|
if (taxes.hasOwnProperty(key)) {
|
||||||
taxes[key].amount += taxAmount;
|
taxes[key].amount += taxAmount1;
|
||||||
} else {
|
} else {
|
||||||
taxes[key] = {name: taxName, rate:taxRate, amount:taxAmount};
|
taxes[key] = {name: taxName1, rate:taxRate1, amount:taxAmount1};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.tax_name) {
|
var taxAmount2 = roundToTwo(lineTotal * taxRate2 / 100);
|
||||||
|
if (taxAmount2) {
|
||||||
|
var key = taxName2 + taxRate2;
|
||||||
|
if (taxes.hasOwnProperty(key)) {
|
||||||
|
taxes[key].amount += taxAmount2;
|
||||||
|
} else {
|
||||||
|
taxes[key] = {name: taxName2, rate:taxRate2, amount:taxAmount2};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.tax_name1 || item.tax_name2) {
|
||||||
hasTaxes = true;
|
hasTaxes = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30556,15 +30573,17 @@ function calculateAmounts(invoice) {
|
|||||||
total += roundToTwo(invoice.custom_value2);
|
total += roundToTwo(invoice.custom_value2);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tax = 0;
|
taxRate1 = 0;
|
||||||
if (invoice.tax_rate && parseFloat(invoice.tax_rate)) {
|
taxRate2 = 0;
|
||||||
tax = parseFloat(invoice.tax_rate);
|
if (invoice.tax_rate1 && parseFloat(invoice.tax_rate1)) {
|
||||||
|
taxRate1 = parseFloat(invoice.tax_rate1);
|
||||||
}
|
}
|
||||||
|
if (invoice.tax_rate2 && parseFloat(invoice.tax_rate2)) {
|
||||||
if (tax) {
|
taxRate2 = parseFloat(invoice.tax_rate2);
|
||||||
var tax = roundToTwo(total * (tax/100));
|
|
||||||
total = parseFloat(total) + parseFloat(tax);
|
|
||||||
}
|
}
|
||||||
|
taxAmount1 = roundToTwo(total * (taxRate1/100));
|
||||||
|
taxAmount2 = roundToTwo(total * (taxRate2/100));
|
||||||
|
total = total + taxAmount1 + taxAmount2;
|
||||||
|
|
||||||
for (var key in taxes) {
|
for (var key in taxes) {
|
||||||
if (taxes.hasOwnProperty(key)) {
|
if (taxes.hasOwnProperty(key)) {
|
||||||
@ -30582,7 +30601,8 @@ function calculateAmounts(invoice) {
|
|||||||
|
|
||||||
invoice.total_amount = roundToTwo(total) - (roundToTwo(invoice.amount) - roundToTwo(invoice.balance));
|
invoice.total_amount = roundToTwo(total) - (roundToTwo(invoice.amount) - roundToTwo(invoice.balance));
|
||||||
invoice.discount_amount = discount;
|
invoice.discount_amount = discount;
|
||||||
invoice.tax_amount = tax;
|
invoice.tax_amount1 = taxAmount1;
|
||||||
|
invoice.tax_amount2 = taxAmount2;
|
||||||
invoice.item_taxes = taxes;
|
invoice.item_taxes = taxes;
|
||||||
|
|
||||||
if (NINJA.parseFloat(invoice.partial)) {
|
if (NINJA.parseFloat(invoice.partial)) {
|
||||||
@ -30594,14 +30614,6 @@ function calculateAmounts(invoice) {
|
|||||||
return invoice;
|
return invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInvoiceTaxRate(invoice) {
|
|
||||||
var tax = 0;
|
|
||||||
if (invoice.tax_rate && parseFloat(invoice.tax_rate)) {
|
|
||||||
tax = parseFloat(invoice.tax_rate);
|
|
||||||
}
|
|
||||||
return tax;
|
|
||||||
}
|
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/11941876/correctly-suppressing-warnings-in-datatables
|
// http://stackoverflow.com/questions/11941876/correctly-suppressing-warnings-in-datatables
|
||||||
window.alert = (function() {
|
window.alert = (function() {
|
||||||
var nativeAlert = window.alert;
|
var nativeAlert = window.alert;
|
||||||
@ -31337,13 +31349,15 @@ NINJA.invoiceLines = function(invoice) {
|
|||||||
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
|
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
|
||||||
var notes = item.notes;
|
var notes = item.notes;
|
||||||
var productKey = item.product_key;
|
var productKey = item.product_key;
|
||||||
var tax = '';
|
var tax1 = '';
|
||||||
|
var tax2 = '';
|
||||||
|
|
||||||
if (showItemTaxes) {
|
if (showItemTaxes) {
|
||||||
if (item.tax && parseFloat(item.tax.rate)) {
|
if (item.tax_name1) {
|
||||||
tax = parseFloat(item.tax.rate);
|
tax1 = parseFloat(item.tax_rate1);
|
||||||
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
|
}
|
||||||
tax = parseFloat(item.tax_rate);
|
if (item.tax_name2) {
|
||||||
|
tax2 = parseFloat(item.tax_rate2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31380,7 +31394,14 @@ NINJA.invoiceLines = function(invoice) {
|
|||||||
row.push({style:["quantity", rowStyle], text:qty || ' '});
|
row.push({style:["quantity", rowStyle], text:qty || ' '});
|
||||||
}
|
}
|
||||||
if (showItemTaxes) {
|
if (showItemTaxes) {
|
||||||
row.push({style:["tax", rowStyle], text:tax ? (tax.toString() + '%') : ' '});
|
var str = '';
|
||||||
|
if (tax1) {
|
||||||
|
str += tax1.toString() + '% ';
|
||||||
|
}
|
||||||
|
if (tax2) {
|
||||||
|
str += tax2.toString() + '% ';
|
||||||
|
}
|
||||||
|
row.push({style:["tax", rowStyle], text:str});
|
||||||
}
|
}
|
||||||
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
|
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
|
||||||
|
|
||||||
@ -31452,9 +31473,13 @@ NINJA.subtotals = function(invoice, hideBalance)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invoice.tax_amount) {
|
if (invoice.tax_amount1) {
|
||||||
var taxStr = invoice.tax_name + ' ' + (invoice.tax_rate*1).toString() + '%';
|
var taxStr = invoice.tax_name1 + ' ' + (invoice.tax_rate1*1).toString() + '%';
|
||||||
data.push([{text: taxStr}, {text: formatMoneyInvoice(invoice.tax_amount, invoice)}]);
|
data.push([{text: taxStr}, {text: formatMoneyInvoice(invoice.tax_amount1, invoice)}]);
|
||||||
|
}
|
||||||
|
if (invoice.tax_amount2) {
|
||||||
|
var taxStr = invoice.tax_name2 + ' ' + (invoice.tax_rate2*1).toString() + '%';
|
||||||
|
data.push([{text: taxStr}, {text: formatMoneyInvoice(invoice.tax_amount2, invoice)}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') {
|
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') {
|
||||||
|
@ -350,13 +350,15 @@ NINJA.invoiceLines = function(invoice) {
|
|||||||
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
|
var qty = NINJA.parseFloat(item.qty) ? roundToTwo(NINJA.parseFloat(item.qty)) + '' : '';
|
||||||
var notes = item.notes;
|
var notes = item.notes;
|
||||||
var productKey = item.product_key;
|
var productKey = item.product_key;
|
||||||
var tax = '';
|
var tax1 = '';
|
||||||
|
var tax2 = '';
|
||||||
|
|
||||||
if (showItemTaxes) {
|
if (showItemTaxes) {
|
||||||
if (item.tax && parseFloat(item.tax.rate)) {
|
if (item.tax_name1) {
|
||||||
tax = parseFloat(item.tax.rate);
|
tax1 = parseFloat(item.tax_rate1);
|
||||||
} else if (item.tax_rate && parseFloat(item.tax_rate)) {
|
}
|
||||||
tax = parseFloat(item.tax_rate);
|
if (item.tax_name2) {
|
||||||
|
tax2 = parseFloat(item.tax_rate2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +395,14 @@ NINJA.invoiceLines = function(invoice) {
|
|||||||
row.push({style:["quantity", rowStyle], text:qty || ' '});
|
row.push({style:["quantity", rowStyle], text:qty || ' '});
|
||||||
}
|
}
|
||||||
if (showItemTaxes) {
|
if (showItemTaxes) {
|
||||||
row.push({style:["tax", rowStyle], text:tax ? (tax.toString() + '%') : ' '});
|
var str = '';
|
||||||
|
if (tax1) {
|
||||||
|
str += tax1.toString() + '% ';
|
||||||
|
}
|
||||||
|
if (tax2) {
|
||||||
|
str += tax2.toString() + '% ';
|
||||||
|
}
|
||||||
|
row.push({style:["tax", rowStyle], text:str});
|
||||||
}
|
}
|
||||||
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
|
row.push({style:["lineTotal", rowStyle], text:lineTotal || ' '});
|
||||||
|
|
||||||
@ -465,9 +474,13 @@ NINJA.subtotals = function(invoice, hideBalance)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invoice.tax_amount) {
|
if (invoice.tax_amount1) {
|
||||||
var taxStr = invoice.tax_name + ' ' + (invoice.tax_rate*1).toString() + '%';
|
var taxStr = invoice.tax_name1 + ' ' + (invoice.tax_rate1*1).toString() + '%';
|
||||||
data.push([{text: taxStr}, {text: formatMoneyInvoice(invoice.tax_amount, invoice)}]);
|
data.push([{text: taxStr}, {text: formatMoneyInvoice(invoice.tax_amount1, invoice)}]);
|
||||||
|
}
|
||||||
|
if (invoice.tax_amount2) {
|
||||||
|
var taxStr = invoice.tax_name2 + ' ' + (invoice.tax_rate2*1).toString() + '%';
|
||||||
|
data.push([{text: taxStr}, {text: formatMoneyInvoice(invoice.tax_amount2, invoice)}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') {
|
if (NINJA.parseFloat(invoice.custom_value1) && invoice.custom_taxes1 != '1') {
|
||||||
|
@ -603,8 +603,10 @@ function calculateAmounts(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];
|
||||||
var taxRate = 0;
|
var taxRate1 = 0;
|
||||||
var taxName = '';
|
var taxName1 = '';
|
||||||
|
var taxRate2 = 0;
|
||||||
|
var taxName2 = '';
|
||||||
|
|
||||||
if (item.product_key) {
|
if (item.product_key) {
|
||||||
invoice.has_product_key = true;
|
invoice.has_product_key = true;
|
||||||
@ -612,9 +614,14 @@ function calculateAmounts(invoice) {
|
|||||||
invoice.has_product_key = true;
|
invoice.has_product_key = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.tax_rate && parseFloat(item.tax_rate)) {
|
if (item.tax_rate1 && parseFloat(item.tax_rate1)) {
|
||||||
taxRate = parseFloat(item.tax_rate);
|
taxRate1 = parseFloat(item.tax_rate1);
|
||||||
taxName = item.tax_name;
|
taxName1 = item.tax_name1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.tax_rate2 && parseFloat(item.tax_rate2)) {
|
||||||
|
taxRate2 = parseFloat(item.tax_rate2);
|
||||||
|
taxName2 = item.tax_name2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate line item tax
|
// calculate line item tax
|
||||||
@ -626,18 +633,28 @@ function calculateAmounts(invoice) {
|
|||||||
lineTotal -= roundToTwo(lineTotal * (invoice.discount/100));
|
lineTotal -= roundToTwo(lineTotal * (invoice.discount/100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var taxAmount = roundToTwo(lineTotal * taxRate / 100);
|
|
||||||
|
var taxAmount1 = roundToTwo(lineTotal * taxRate1 / 100);
|
||||||
if (taxAmount) {
|
if (taxAmount1) {
|
||||||
var key = taxName + taxRate;
|
var key = taxName1 + taxRate1;
|
||||||
if (taxes.hasOwnProperty(key)) {
|
if (taxes.hasOwnProperty(key)) {
|
||||||
taxes[key].amount += taxAmount;
|
taxes[key].amount += taxAmount1;
|
||||||
} else {
|
} else {
|
||||||
taxes[key] = {name: taxName, rate:taxRate, amount:taxAmount};
|
taxes[key] = {name: taxName1, rate:taxRate1, amount:taxAmount1};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.tax_name) {
|
var taxAmount2 = roundToTwo(lineTotal * taxRate2 / 100);
|
||||||
|
if (taxAmount2) {
|
||||||
|
var key = taxName2 + taxRate2;
|
||||||
|
if (taxes.hasOwnProperty(key)) {
|
||||||
|
taxes[key].amount += taxAmount2;
|
||||||
|
} else {
|
||||||
|
taxes[key] = {name: taxName2, rate:taxRate2, amount:taxAmount2};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.tax_name1 || item.tax_name2) {
|
||||||
hasTaxes = true;
|
hasTaxes = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,15 +679,17 @@ function calculateAmounts(invoice) {
|
|||||||
total += roundToTwo(invoice.custom_value2);
|
total += roundToTwo(invoice.custom_value2);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tax = 0;
|
taxRate1 = 0;
|
||||||
if (invoice.tax_rate && parseFloat(invoice.tax_rate)) {
|
taxRate2 = 0;
|
||||||
tax = parseFloat(invoice.tax_rate);
|
if (invoice.tax_rate1 && parseFloat(invoice.tax_rate1)) {
|
||||||
|
taxRate1 = parseFloat(invoice.tax_rate1);
|
||||||
}
|
}
|
||||||
|
if (invoice.tax_rate2 && parseFloat(invoice.tax_rate2)) {
|
||||||
if (tax) {
|
taxRate2 = parseFloat(invoice.tax_rate2);
|
||||||
var tax = roundToTwo(total * (tax/100));
|
|
||||||
total = parseFloat(total) + parseFloat(tax);
|
|
||||||
}
|
}
|
||||||
|
taxAmount1 = roundToTwo(total * (taxRate1/100));
|
||||||
|
taxAmount2 = roundToTwo(total * (taxRate2/100));
|
||||||
|
total = total + taxAmount1 + taxAmount2;
|
||||||
|
|
||||||
for (var key in taxes) {
|
for (var key in taxes) {
|
||||||
if (taxes.hasOwnProperty(key)) {
|
if (taxes.hasOwnProperty(key)) {
|
||||||
@ -688,7 +707,8 @@ function calculateAmounts(invoice) {
|
|||||||
|
|
||||||
invoice.total_amount = roundToTwo(total) - (roundToTwo(invoice.amount) - roundToTwo(invoice.balance));
|
invoice.total_amount = roundToTwo(total) - (roundToTwo(invoice.amount) - roundToTwo(invoice.balance));
|
||||||
invoice.discount_amount = discount;
|
invoice.discount_amount = discount;
|
||||||
invoice.tax_amount = tax;
|
invoice.tax_amount1 = taxAmount1;
|
||||||
|
invoice.tax_amount2 = taxAmount2;
|
||||||
invoice.item_taxes = taxes;
|
invoice.item_taxes = taxes;
|
||||||
|
|
||||||
if (NINJA.parseFloat(invoice.partial)) {
|
if (NINJA.parseFloat(invoice.partial)) {
|
||||||
@ -700,14 +720,6 @@ function calculateAmounts(invoice) {
|
|||||||
return invoice;
|
return invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInvoiceTaxRate(invoice) {
|
|
||||||
var tax = 0;
|
|
||||||
if (invoice.tax_rate && parseFloat(invoice.tax_rate)) {
|
|
||||||
tax = parseFloat(invoice.tax_rate);
|
|
||||||
}
|
|
||||||
return tax;
|
|
||||||
}
|
|
||||||
|
|
||||||
// http://stackoverflow.com/questions/11941876/correctly-suppressing-warnings-in-datatables
|
// http://stackoverflow.com/questions/11941876/correctly-suppressing-warnings-in-datatables
|
||||||
window.alert = (function() {
|
window.alert = (function() {
|
||||||
var nativeAlert = window.alert;
|
var nativeAlert = window.alert;
|
||||||
|
@ -17,6 +17,11 @@
|
|||||||
label.control-label[for=invoice_number] {
|
label.control-label[for=invoice_number] {
|
||||||
font-weight: normal !important;
|
font-weight: normal !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select.tax-select {
|
||||||
|
width: 50%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
@ -204,7 +209,7 @@
|
|||||||
@endif
|
@endif
|
||||||
<th style="min-width:120px" data-bind="text: costLabel">{{ $invoiceLabels['unit_cost'] }}</th>
|
<th style="min-width:120px" data-bind="text: costLabel">{{ $invoiceLabels['unit_cost'] }}</th>
|
||||||
<th style="{{ $account->hide_quantity ? 'display:none' : 'min-width:120px' }}" data-bind="text: qtyLabel">{{ $invoiceLabels['quantity'] }}</th>
|
<th style="{{ $account->hide_quantity ? 'display:none' : 'min-width:120px' }}" data-bind="text: qtyLabel">{{ $invoiceLabels['quantity'] }}</th>
|
||||||
<th style="min-width:120px;display:none;" data-bind="visible: $root.invoice_item_taxes.show">{{ trans('texts.tax') }}</th>
|
<th style="min-width:180px;display:none;" data-bind="visible: $root.invoice_item_taxes.show">{{ trans('texts.tax') }}</th>
|
||||||
<th style="min-width:120px;">{{ trans('texts.line_total') }}</th>
|
<th style="min-width:120px;">{{ trans('texts.line_total') }}</th>
|
||||||
<th style="min-width:32px;" class="hide-border"></th>
|
<th style="min-width:32px;" class="hide-border"></th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -246,10 +251,19 @@
|
|||||||
{!! Former::select('')
|
{!! Former::select('')
|
||||||
->addOption('', '')
|
->addOption('', '')
|
||||||
->options($taxRateOptions)
|
->options($taxRateOptions)
|
||||||
->data_bind('value: tax')
|
->data_bind('value: tax1')
|
||||||
|
->addClass('tax-select')
|
||||||
->raw() !!}
|
->raw() !!}
|
||||||
<input type="text" data-bind="value: tax_name, attr: {name: 'invoice_items[' + $index() + '][tax_name]'}" style="display:none">
|
<input type="text" data-bind="value: tax_name1, attr: {name: 'invoice_items[' + $index() + '][tax_name1]'}" style="display:none">
|
||||||
<input type="text" data-bind="value: tax_rate, attr: {name: 'invoice_items[' + $index() + '][tax_rate]'}" style="display:none">
|
<input type="text" data-bind="value: tax_rate1, attr: {name: 'invoice_items[' + $index() + '][tax_rate1]'}" style="display:none">
|
||||||
|
{!! Former::select('')
|
||||||
|
->addOption('', '')
|
||||||
|
->options($taxRateOptions)
|
||||||
|
->data_bind('value: tax2')
|
||||||
|
->addClass('tax-select')
|
||||||
|
->raw() !!}
|
||||||
|
<input type="text" data-bind="value: tax_name2, attr: {name: 'invoice_items[' + $index() + '][tax_name2]'}" style="display:none">
|
||||||
|
<input type="text" data-bind="value: tax_rate2, attr: {name: 'invoice_items[' + $index() + '][tax_rate2]'}" style="display:none">
|
||||||
</td>
|
</td>
|
||||||
<td style="text-align:right;padding-top:9px !important" nowrap>
|
<td style="text-align:right;padding-top:9px !important" nowrap>
|
||||||
<div class="line-total" data-bind="text: totals.total"></div>
|
<div class="line-total" data-bind="text: totals.total"></div>
|
||||||
@ -387,10 +401,19 @@
|
|||||||
{!! Former::select('')
|
{!! Former::select('')
|
||||||
->addOption('', '')
|
->addOption('', '')
|
||||||
->options($taxRateOptions)
|
->options($taxRateOptions)
|
||||||
->data_bind('value: tax')
|
->addClass('tax-select')
|
||||||
|
->data_bind('value: tax1')
|
||||||
->raw() !!}
|
->raw() !!}
|
||||||
<input type="text" name="tax_name" data-bind="value: tax_name" style="display:none">
|
<input type="text" name="tax_name1" data-bind="value: tax_name1" style="display:none">
|
||||||
<input type="text" name="tax_rate" data-bind="value: tax_rate" style="display:none">
|
<input type="text" name="tax_rate1" data-bind="value: tax_rate1" style="display:none">
|
||||||
|
{!! Former::select('')
|
||||||
|
->addOption('', '')
|
||||||
|
->options($taxRateOptions)
|
||||||
|
->addClass('tax-select')
|
||||||
|
->data_bind('value: tax2')
|
||||||
|
->raw() !!}
|
||||||
|
<input type="text" name="tax_name2" data-bind="value: tax_name2" style="display:none">
|
||||||
|
<input type="text" name="tax_rate2" data-bind="value: tax_rate2" style="display:none">
|
||||||
</td>
|
</td>
|
||||||
<td style="text-align: right"><span data-bind="text: totals.taxAmount"/></td>
|
<td style="text-align: right"><span data-bind="text: totals.taxAmount"/></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -770,8 +793,8 @@
|
|||||||
// set the default account tax rate
|
// set the default account tax rate
|
||||||
@if ($account->invoice_taxes && ! empty($defaultTax))
|
@if ($account->invoice_taxes && ! empty($defaultTax))
|
||||||
var defaultTax = {!! $defaultTax !!};
|
var defaultTax = {!! $defaultTax !!};
|
||||||
model.invoice().tax_rate(defaultTax.rate);
|
model.invoice().tax_rate1(defaultTax.rate);
|
||||||
model.invoice().tax_name(defaultTax.name);
|
model.invoice().tax_name1(defaultTax.name);
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@ -52,10 +52,11 @@ function ViewModel(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.invoice_taxes.show = ko.computed(function() {
|
self.invoice_taxes.show = ko.computed(function() {
|
||||||
if (self.invoice_taxes()) {
|
if (self.invoice().tax_name1() || self.invoice().tax_name2()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
return self.invoice_taxes() && {{ count($taxRateOptions) ? 'true' : 'false' }};
|
||||||
});
|
});
|
||||||
|
|
||||||
self.invoice_item_taxes.show = ko.computed(function() {
|
self.invoice_item_taxes.show = ko.computed(function() {
|
||||||
@ -64,7 +65,7 @@ function ViewModel(data) {
|
|||||||
}
|
}
|
||||||
for (var i=0; i<self.invoice().invoice_items().length; i++) {
|
for (var i=0; i<self.invoice().invoice_items().length; i++) {
|
||||||
var item = self.invoice().invoice_items()[i];
|
var item = self.invoice().invoice_items()[i];
|
||||||
if (item.tax_rate() > 0) {
|
if (item.tax_name1() || item.tax_name2()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,8 +176,10 @@ function InvoiceModel(data) {
|
|||||||
self.start_date = ko.observable('');
|
self.start_date = ko.observable('');
|
||||||
self.end_date = ko.observable('');
|
self.end_date = ko.observable('');
|
||||||
self.last_sent_date = ko.observable('');
|
self.last_sent_date = ko.observable('');
|
||||||
self.tax_name = ko.observable();
|
self.tax_name1 = ko.observable();
|
||||||
self.tax_rate = ko.observable();
|
self.tax_rate1 = ko.observable();
|
||||||
|
self.tax_name2 = ko.observable();
|
||||||
|
self.tax_rate2 = ko.observable();
|
||||||
self.is_recurring = ko.observable(0);
|
self.is_recurring = ko.observable(0);
|
||||||
self.is_quote = ko.observable({{ $entityType == ENTITY_QUOTE ? '1' : '0' }});
|
self.is_quote = ko.observable({{ $entityType == ENTITY_QUOTE ? '1' : '0' }});
|
||||||
self.auto_bill = ko.observable();
|
self.auto_bill = ko.observable();
|
||||||
@ -258,15 +261,27 @@ function InvoiceModel(data) {
|
|||||||
return self.has_tasks() ? invoiceLabels['rate'] : invoiceLabels['unit_cost'];
|
return self.has_tasks() ? invoiceLabels['rate'] : invoiceLabels['unit_cost'];
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.tax = ko.computed({
|
this.tax1 = ko.computed({
|
||||||
read: function () {
|
read: function () {
|
||||||
return self.tax_rate() + ' ' + self.tax_name();
|
return self.tax_rate1() + ' ' + self.tax_name1();
|
||||||
},
|
},
|
||||||
write: function(value) {
|
write: function(value) {
|
||||||
var rate = value.substr(0, value.indexOf(' '));
|
var rate = value.substr(0, value.indexOf(' '));
|
||||||
var name = value.substr(value.indexOf(' ') + 1);
|
var name = value.substr(value.indexOf(' ') + 1);
|
||||||
self.tax_name(name);
|
self.tax_name1(name);
|
||||||
self.tax_rate(rate);
|
self.tax_rate1(rate);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.tax2 = ko.computed({
|
||||||
|
read: function () {
|
||||||
|
return self.tax_rate2() + ' ' + self.tax_name2();
|
||||||
|
},
|
||||||
|
write: function(value) {
|
||||||
|
var rate = value.substr(0, value.indexOf(' '));
|
||||||
|
var name = value.substr(value.indexOf(' ') + 1);
|
||||||
|
self.tax_name2(name);
|
||||||
|
self.tax_rate2(rate);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -359,15 +374,13 @@ function InvoiceModel(data) {
|
|||||||
total = NINJA.parseFloat(total) + customValue2;
|
total = NINJA.parseFloat(total) + customValue2;
|
||||||
}
|
}
|
||||||
|
|
||||||
var taxRate = parseFloat(self.tax_rate());
|
var taxRate1 = parseFloat(self.tax_rate1());
|
||||||
//if (taxRate > 0) {
|
var tax1 = roundToTwo(total * (taxRate1/100));
|
||||||
// var tax = roundToTwo(total * (taxRate/100));
|
|
||||||
// return self.formatMoney(tax);
|
var taxRate2 = parseFloat(self.tax_rate2());
|
||||||
//} else {
|
var tax2 = roundToTwo(total * (taxRate2/100));
|
||||||
// return self.formatMoney(0);
|
|
||||||
//}
|
return self.formatMoney(tax1 + tax2);
|
||||||
var tax = roundToTwo(total * (taxRate/100));
|
|
||||||
return self.formatMoney(tax);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.totals.itemTaxes = ko.computed(function() {
|
self.totals.itemTaxes = ko.computed(function() {
|
||||||
@ -383,13 +396,24 @@ function InvoiceModel(data) {
|
|||||||
lineTotal -= roundToTwo(lineTotal * (self.discount()/100));
|
lineTotal -= roundToTwo(lineTotal * (self.discount()/100));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var taxAmount = roundToTwo(lineTotal * item.tax_rate() / 100);
|
|
||||||
|
var taxAmount = roundToTwo(lineTotal * item.tax_rate1() / 100);
|
||||||
if (taxAmount) {
|
if (taxAmount) {
|
||||||
var key = item.tax_name() + item.tax_rate();
|
var key = item.tax_name1() + item.tax_rate1();
|
||||||
if (taxes.hasOwnProperty(key)) {
|
if (taxes.hasOwnProperty(key)) {
|
||||||
taxes[key].amount += taxAmount;
|
taxes[key].amount += taxAmount;
|
||||||
} else {
|
} else {
|
||||||
taxes[key] = {name:item.tax_name(), rate:item.tax_rate(), amount:taxAmount};
|
taxes[key] = {name:item.tax_name1(), rate:item.tax_rate1(), amount:taxAmount};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var taxAmount = roundToTwo(lineTotal * item.tax_rate2() / 100);
|
||||||
|
if (taxAmount) {
|
||||||
|
var key = item.tax_name2() + item.tax_rate2();
|
||||||
|
if (taxes.hasOwnProperty(key)) {
|
||||||
|
taxes[key].amount += taxAmount;
|
||||||
|
} else {
|
||||||
|
taxes[key] = {name:item.tax_name2(), rate:item.tax_rate2(), amount:taxAmount};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,8 +479,9 @@ function InvoiceModel(data) {
|
|||||||
total = NINJA.parseFloat(total) + customValue2;
|
total = NINJA.parseFloat(total) + customValue2;
|
||||||
}
|
}
|
||||||
|
|
||||||
var taxRate = parseFloat(self.tax_rate());
|
var taxAmount1 = roundToTwo(total * (parseFloat(self.tax_rate1())/100));
|
||||||
total = NINJA.parseFloat(total) + roundToTwo(total * (taxRate/100));
|
var taxAmount2 = roundToTwo(total * (parseFloat(self.tax_rate2())/100));
|
||||||
|
total = NINJA.parseFloat(total) + taxAmount1 + taxAmount2;
|
||||||
total = roundToTwo(total);
|
total = roundToTwo(total);
|
||||||
|
|
||||||
var taxes = self.totals.itemTaxes();
|
var taxes = self.totals.itemTaxes();
|
||||||
@ -641,21 +666,35 @@ function ItemModel(data) {
|
|||||||
self.qty = ko.observable(0);
|
self.qty = ko.observable(0);
|
||||||
self.custom_value1 = ko.observable('');
|
self.custom_value1 = ko.observable('');
|
||||||
self.custom_value2 = ko.observable('');
|
self.custom_value2 = ko.observable('');
|
||||||
self.tax_name = ko.observable('');
|
self.tax_name1 = ko.observable('');
|
||||||
self.tax_rate = ko.observable(0);
|
self.tax_rate1 = ko.observable(0);
|
||||||
|
self.tax_name2 = ko.observable('');
|
||||||
|
self.tax_rate2 = ko.observable(0);
|
||||||
self.task_public_id = ko.observable('');
|
self.task_public_id = ko.observable('');
|
||||||
self.expense_public_id = ko.observable('');
|
self.expense_public_id = ko.observable('');
|
||||||
self.actionsVisible = ko.observable(false);
|
self.actionsVisible = ko.observable(false);
|
||||||
|
|
||||||
this.tax = ko.computed({
|
this.tax1 = ko.computed({
|
||||||
read: function () {
|
read: function () {
|
||||||
return self.tax_rate() + ' ' + self.tax_name();
|
return self.tax_rate1() + ' ' + self.tax_name1();
|
||||||
},
|
},
|
||||||
write: function(value) {
|
write: function(value) {
|
||||||
var rate = value.substr(0, value.indexOf(' '));
|
var rate = value.substr(0, value.indexOf(' '));
|
||||||
var name = value.substr(value.indexOf(' ') + 1);
|
var name = value.substr(value.indexOf(' ') + 1);
|
||||||
self.tax_name(name);
|
self.tax_name1(name);
|
||||||
self.tax_rate(rate);
|
self.tax_rate1(rate);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.tax2 = ko.computed({
|
||||||
|
read: function () {
|
||||||
|
return self.tax_rate2() + ' ' + self.tax_name2();
|
||||||
|
},
|
||||||
|
write: function(value) {
|
||||||
|
var rate = value.substr(0, value.indexOf(' '));
|
||||||
|
var name = value.substr(value.indexOf(' ') + 1);
|
||||||
|
self.tax_name2(name);
|
||||||
|
self.tax_rate2(rate);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -794,9 +833,9 @@ ko.bindingHandlers.typeahead = {
|
|||||||
}
|
}
|
||||||
@if ($account->invoice_item_taxes)
|
@if ($account->invoice_item_taxes)
|
||||||
if (datum.default_tax_rate) {
|
if (datum.default_tax_rate) {
|
||||||
model.tax_rate(datum.default_tax_rate.rate);
|
model.tax_rate1(datum.default_tax_rate.rate);
|
||||||
model.tax_name(datum.default_tax_rate.name);
|
model.tax_name1(datum.default_tax_rate.name);
|
||||||
model.tax(datum.default_tax_rate.rate + ' ' + datum.default_tax_rate.name);
|
model.tax1(datum.default_tax_rate.rate + ' ' + datum.default_tax_rate.name);
|
||||||
}
|
}
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
|
Loading…
Reference in New Issue
Block a user