mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Improved inclusive tax rates
This commit is contained in:
parent
8d110c2a4b
commit
a99f45c628
@ -177,6 +177,7 @@ class Account extends Eloquent
|
|||||||
'credit_number_prefix',
|
'credit_number_prefix',
|
||||||
'credit_number_pattern',
|
'credit_number_pattern',
|
||||||
'task_rate',
|
'task_rate',
|
||||||
|
'inclusive_taxes',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -987,6 +987,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
'include_item_taxes_inline',
|
'include_item_taxes_inline',
|
||||||
'invoice_fields',
|
'invoice_fields',
|
||||||
'show_currency_code',
|
'show_currency_code',
|
||||||
|
'inclusive_taxes',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
foreach ($this->invoice_items as $invoiceItem) {
|
foreach ($this->invoice_items as $invoiceItem) {
|
||||||
@ -1344,17 +1345,26 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
public function getTaxes($calculatePaid = false)
|
public function getTaxes($calculatePaid = false)
|
||||||
{
|
{
|
||||||
$taxes = [];
|
$taxes = [];
|
||||||
|
$account = $this->account;
|
||||||
$taxable = $this->getTaxable();
|
$taxable = $this->getTaxable();
|
||||||
$paidAmount = $this->getAmountPaid($calculatePaid);
|
$paidAmount = $this->getAmountPaid($calculatePaid);
|
||||||
|
|
||||||
if ($this->tax_name1) {
|
if ($this->tax_name1) {
|
||||||
$invoiceTaxAmount = round($taxable * ($this->tax_rate1 / 100), 2);
|
if ($account->inclusive_taxes) {
|
||||||
|
$invoiceTaxAmount = round(($taxable * 100) / (100 + ($this->tax_rate1 * 100)), 2);
|
||||||
|
} else {
|
||||||
|
$invoiceTaxAmount = round($taxable * ($this->tax_rate1 / 100), 2);
|
||||||
|
}
|
||||||
$invoicePaidAmount = floatval($this->amount) && $invoiceTaxAmount ? ($paidAmount / $this->amount * $invoiceTaxAmount) : 0;
|
$invoicePaidAmount = floatval($this->amount) && $invoiceTaxAmount ? ($paidAmount / $this->amount * $invoiceTaxAmount) : 0;
|
||||||
$this->calculateTax($taxes, $this->tax_name1, $this->tax_rate1, $invoiceTaxAmount, $invoicePaidAmount);
|
$this->calculateTax($taxes, $this->tax_name1, $this->tax_rate1, $invoiceTaxAmount, $invoicePaidAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->tax_name2) {
|
if ($this->tax_name2) {
|
||||||
$invoiceTaxAmount = round($taxable * ($this->tax_rate2 / 100), 2);
|
if ($account->inclusive_taxes) {
|
||||||
|
$invoiceTaxAmount = round(($taxable * 100) / (100 + ($this->tax_rate2 * 100)), 2);
|
||||||
|
} else {
|
||||||
|
$invoiceTaxAmount = round($taxable * ($this->tax_rate2 / 100), 2);
|
||||||
|
}
|
||||||
$invoicePaidAmount = floatval($this->amount) && $invoiceTaxAmount ? ($paidAmount / $this->amount * $invoiceTaxAmount) : 0;
|
$invoicePaidAmount = floatval($this->amount) && $invoiceTaxAmount ? ($paidAmount / $this->amount * $invoiceTaxAmount) : 0;
|
||||||
$this->calculateTax($taxes, $this->tax_name2, $this->tax_rate2, $invoiceTaxAmount, $invoicePaidAmount);
|
$this->calculateTax($taxes, $this->tax_name2, $this->tax_rate2, $invoiceTaxAmount, $invoicePaidAmount);
|
||||||
}
|
}
|
||||||
@ -1363,13 +1373,21 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
$itemTaxable = $this->getItemTaxable($invoiceItem, $taxable);
|
$itemTaxable = $this->getItemTaxable($invoiceItem, $taxable);
|
||||||
|
|
||||||
if ($invoiceItem->tax_name1) {
|
if ($invoiceItem->tax_name1) {
|
||||||
$itemTaxAmount = round($itemTaxable * ($invoiceItem->tax_rate1 / 100), 2);
|
if ($account->inclusive_taxes) {
|
||||||
|
$itemTaxAmount = round(($itemTaxable * 100) / (100 + ($invoiceItem->tax_rate1 * 100)), 2);
|
||||||
|
} else {
|
||||||
|
$itemTaxAmount = round($itemTaxable * ($invoiceItem->tax_rate1 / 100), 2);
|
||||||
|
}
|
||||||
$itemPaidAmount = floatval($this->amount) && $itemTaxAmount ? ($paidAmount / $this->amount * $itemTaxAmount) : 0;
|
$itemPaidAmount = floatval($this->amount) && $itemTaxAmount ? ($paidAmount / $this->amount * $itemTaxAmount) : 0;
|
||||||
$this->calculateTax($taxes, $invoiceItem->tax_name1, $invoiceItem->tax_rate1, $itemTaxAmount, $itemPaidAmount);
|
$this->calculateTax($taxes, $invoiceItem->tax_name1, $invoiceItem->tax_rate1, $itemTaxAmount, $itemPaidAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($invoiceItem->tax_name2) {
|
if ($invoiceItem->tax_name2) {
|
||||||
$itemTaxAmount = round($itemTaxable * ($invoiceItem->tax_rate2 / 100), 2);
|
if ($account->inclusive_taxes) {
|
||||||
|
$itemTaxAmount = round(($itemTaxable * 100) / (100 + ($invoiceItem->tax_rate2 * 100)), 2);
|
||||||
|
} else {
|
||||||
|
$itemTaxAmount = round($itemTaxable * ($invoiceItem->tax_rate2 / 100), 2);
|
||||||
|
}
|
||||||
$itemPaidAmount = floatval($this->amount) && $itemTaxAmount ? ($paidAmount / $this->amount * $itemTaxAmount) : 0;
|
$itemPaidAmount = floatval($this->amount) && $itemTaxAmount ? ($paidAmount / $this->amount * $itemTaxAmount) : 0;
|
||||||
$this->calculateTax($taxes, $invoiceItem->tax_name2, $invoiceItem->tax_rate2, $itemTaxAmount, $itemPaidAmount);
|
$this->calculateTax($taxes, $invoiceItem->tax_name2, $invoiceItem->tax_rate2, $itemTaxAmount, $itemPaidAmount);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,11 @@ class TaxRateDatatable extends EntityDatatable
|
|||||||
[
|
[
|
||||||
'type',
|
'type',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return $model->is_inclusive ? trans('texts.inclusive') : trans('texts.exclusive');
|
if (auth()->user()->account->inclusive_taxes) {
|
||||||
|
return trans('texts.standard');
|
||||||
|
} else {
|
||||||
|
return $model->is_inclusive ? trans('texts.inclusive') : trans('texts.exclusive');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -607,10 +607,12 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$total += $invoice->custom_value2;
|
$total += $invoice->custom_value2;
|
||||||
}
|
}
|
||||||
|
|
||||||
$taxAmount1 = round($total * ($invoice->tax_rate1 ? $invoice->tax_rate1 : 0) / 100, 2);
|
if (! $account->inclusive_taxes) {
|
||||||
$taxAmount2 = round($total * ($invoice->tax_rate2 ? $invoice->tax_rate2 : 0) / 100, 2);
|
$taxAmount1 = round($total * ($invoice->tax_rate1 ? $invoice->tax_rate1 : 0) / 100, 2);
|
||||||
$total = round($total + $taxAmount1 + $taxAmount2, 2);
|
$taxAmount2 = round($total * ($invoice->tax_rate2 ? $invoice->tax_rate2 : 0) / 100, 2);
|
||||||
$total += $itemTax;
|
$total = round($total + $taxAmount1 + $taxAmount2, 2);
|
||||||
|
$total += $itemTax;
|
||||||
|
}
|
||||||
|
|
||||||
// custom fields not charged taxes
|
// custom fields not charged taxes
|
||||||
if ($invoice->custom_value1 && ! $invoice->custom_taxes1) {
|
if ($invoice->custom_value1 && ! $invoice->custom_taxes1) {
|
||||||
|
@ -275,6 +275,7 @@ class AccountTransformer extends EntityTransformer
|
|||||||
'custom_contact_label1' => $account->custom_contact_label1,
|
'custom_contact_label1' => $account->custom_contact_label1,
|
||||||
'custom_contact_label2' => $account->custom_contact_label2,
|
'custom_contact_label2' => $account->custom_contact_label2,
|
||||||
'task_rate' => (float) $account->task_rate,
|
'task_rate' => (float) $account->task_rate,
|
||||||
|
'inclusive_taxes' => (bool) $account->inclusive_taxes,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,9 @@ class AddSubdomainToLookups extends Migration
|
|||||||
$table->unique(['account_id', 'public_id']);
|
$table->unique(['account_id', 'public_id']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Schema::table('accounts', function ($table) {
|
||||||
|
$table->boolean('inclusive_taxes')->default(0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,5 +140,9 @@ class AddSubdomainToLookups extends Migration
|
|||||||
$table->dropColumn('user_id');
|
$table->dropColumn('user_id');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Schema::table('accounts', function ($table) {
|
||||||
|
$table->dropColumn('inclusive_taxes');
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -631,7 +631,11 @@ function calculateAmounts(invoice) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var taxAmount1 = roundToTwo(lineTotal * taxRate1 / 100);
|
if (invoice.account.inclusive_taxes != '1') {
|
||||||
|
var taxAmount1 = roundToTwo(lineTotal * taxRate1 / 100);
|
||||||
|
} else {
|
||||||
|
var taxAmount1 = roundToTwo((lineTotal * 100) / (100 + (taxRate1 * 100)));
|
||||||
|
}
|
||||||
if (taxAmount1 != 0 || taxName1) {
|
if (taxAmount1 != 0 || taxName1) {
|
||||||
hasTaxes = true;
|
hasTaxes = true;
|
||||||
var key = taxName1 + taxRate1;
|
var key = taxName1 + taxRate1;
|
||||||
@ -642,7 +646,11 @@ function calculateAmounts(invoice) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var taxAmount2 = roundToTwo(lineTotal * taxRate2 / 100);
|
if (invoice.account.inclusive_taxes != '1') {
|
||||||
|
var taxAmount2 = roundToTwo(lineTotal * taxRate2 / 100);
|
||||||
|
} else {
|
||||||
|
var taxAmount2 = roundToTwo((lineTotal * 100) / (100 + (taxRate2 * 100)));
|
||||||
|
}
|
||||||
if (taxAmount2 != 0 || taxName2) {
|
if (taxAmount2 != 0 || taxName2) {
|
||||||
hasTaxes = true;
|
hasTaxes = true;
|
||||||
var key = taxName2 + taxRate2;
|
var key = taxName2 + taxRate2;
|
||||||
@ -683,14 +691,20 @@ function calculateAmounts(invoice) {
|
|||||||
if (parseFloat(invoice.tax_rate2 || 0) != 0) {
|
if (parseFloat(invoice.tax_rate2 || 0) != 0) {
|
||||||
taxRate2 = parseFloat(invoice.tax_rate2);
|
taxRate2 = parseFloat(invoice.tax_rate2);
|
||||||
}
|
}
|
||||||
taxAmount1 = roundToTwo(total * taxRate1 / 100);
|
|
||||||
taxAmount2 = roundToTwo(total * taxRate2 / 100);
|
|
||||||
total = total + taxAmount1 + taxAmount2;
|
|
||||||
|
|
||||||
for (var key in taxes) {
|
if (invoice.account.inclusive_taxes != '1') {
|
||||||
if (taxes.hasOwnProperty(key)) {
|
taxAmount1 = roundToTwo(total * taxRate1 / 100);
|
||||||
total += taxes[key].amount;
|
taxAmount2 = roundToTwo(total * taxRate2 / 100);
|
||||||
}
|
total = total + taxAmount1 + taxAmount2;
|
||||||
|
|
||||||
|
for (var key in taxes) {
|
||||||
|
if (taxes.hasOwnProperty(key)) {
|
||||||
|
total += taxes[key].amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
taxAmount1 = roundToTwo((total * 100) / (100 + (taxRate1 * 100)));
|
||||||
|
taxAmount2 = roundToTwo((total * 100) / (100 + (taxRate2 * 100)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// custom fields w/o with taxes
|
// custom fields w/o with taxes
|
||||||
|
@ -2604,6 +2604,9 @@ $LANG = array(
|
|||||||
'processing_request' => 'Processing request',
|
'processing_request' => 'Processing request',
|
||||||
'mcrypt_warning' => 'Warning: Mcrypt is deprecated, run <code>php artisan ninja:update-key --legacy=true</code> to update your cipher.',
|
'mcrypt_warning' => 'Warning: Mcrypt is deprecated, run <code>php artisan ninja:update-key --legacy=true</code> to update your cipher.',
|
||||||
'edit_times' => 'Edit Times',
|
'edit_times' => 'Edit Times',
|
||||||
|
'inclusive_taxes_help' => 'Include <b>taxes in the cost</b>',
|
||||||
|
'inclusive_taxes_warning' => 'Warning: existing invoices will need to be resaved',
|
||||||
|
'standard' => 'Standard',
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -28,13 +28,14 @@
|
|||||||
{!! Former::text('name')->label('texts.name') !!}
|
{!! Former::text('name')->label('texts.name') !!}
|
||||||
{!! Former::text('rate')->label('texts.rate')->append('%') !!}
|
{!! Former::text('rate')->label('texts.rate')->append('%') !!}
|
||||||
|
|
||||||
{!! Former::radios('is_inclusive')->radios([
|
@if (! auth()->user()->account->inclusive_taxes)
|
||||||
trans('texts.exclusive') . ': 100 + 10% = 100 + 10' => array('name' => 'is_inclusive', 'value' => 0),
|
{!! Former::radios('is_inclusive')->radios([
|
||||||
trans('texts.inclusive') . ': 100 + 10% = 90.91 + 9.09' => array('name' => 'is_inclusive', 'value' => 1),
|
trans('texts.exclusive') . ': 100 + 10% = 100 + 10' => array('name' => 'is_inclusive', 'value' => 0),
|
||||||
])->check(0)
|
trans('texts.inclusive') . ': 100 + 10% = 90.91 + 9.09' => array('name' => 'is_inclusive', 'value' => 1),
|
||||||
->label('type')
|
])->check(0)
|
||||||
->help('tax_rate_type_help') !!}
|
->label('type')
|
||||||
|
->help('tax_rate_type_help') !!}
|
||||||
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
{{ Former::populateField('invoice_item_taxes', intval($account->invoice_item_taxes)) }}
|
{{ Former::populateField('invoice_item_taxes', intval($account->invoice_item_taxes)) }}
|
||||||
{{ Former::populateField('enable_second_tax_rate', intval($account->enable_second_tax_rate)) }}
|
{{ Former::populateField('enable_second_tax_rate', intval($account->enable_second_tax_rate)) }}
|
||||||
{{ Former::populateField('include_item_taxes_inline', intval($account->include_item_taxes_inline)) }}
|
{{ Former::populateField('include_item_taxes_inline', intval($account->include_item_taxes_inline)) }}
|
||||||
|
{{ Former::populateField('inclusive_taxes', intval($account->inclusive_taxes)) }}
|
||||||
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
@ -29,13 +30,19 @@
|
|||||||
->label(' ')
|
->label(' ')
|
||||||
->value(1) !!}
|
->value(1) !!}
|
||||||
|
|
||||||
{!! Former::checkbox('include_item_taxes_inline')
|
{!! Former::checkbox('enable_second_tax_rate')
|
||||||
->text(trans('texts.include_item_taxes_inline'))
|
->text(trans('texts.enable_second_tax_rate'))
|
||||||
->label(' ')
|
->label(' ')
|
||||||
->value(1) !!}
|
->value(1) !!}
|
||||||
|
|
||||||
{!! Former::checkbox('enable_second_tax_rate')
|
{!! Former::checkbox('inclusive_taxes')
|
||||||
->text(trans('texts.enable_second_tax_rate'))
|
->text(trans('texts.inclusive_taxes_help'))
|
||||||
|
->label(' ')
|
||||||
|
->value(1) !!}
|
||||||
|
|
||||||
|
|
||||||
|
{!! Former::checkbox('include_item_taxes_inline')
|
||||||
|
->text(trans('texts.include_item_taxes_inline'))
|
||||||
->label(' ')
|
->label(' ')
|
||||||
->value(1) !!}
|
->value(1) !!}
|
||||||
|
|
||||||
@ -75,4 +82,14 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function() {
|
||||||
|
@if (App\Models\Invoice::scope()->withTrashed()->count())
|
||||||
|
$('#inclusive_taxes').change(function() {
|
||||||
|
swal("{{ trans('texts.inclusive_taxes_warning') }}");
|
||||||
|
})
|
||||||
|
@endif
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
@stop
|
@stop
|
||||||
|
@ -425,10 +425,18 @@ function InvoiceModel(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var taxRate1 = parseFloat(self.tax_rate1());
|
var taxRate1 = parseFloat(self.tax_rate1());
|
||||||
var tax1 = roundToTwo(total * (taxRate1/100));
|
@if ($account->inclusive_taxes)
|
||||||
|
var tax1 = roundToTwo((total * 100) / (100 + (taxRate1 * 100)));
|
||||||
|
@else
|
||||||
|
var tax1 = roundToTwo(total * (taxRate1/100));
|
||||||
|
@endif
|
||||||
|
|
||||||
var taxRate2 = parseFloat(self.tax_rate2());
|
var taxRate2 = parseFloat(self.tax_rate2());
|
||||||
var tax2 = roundToTwo(total * (taxRate2/100));
|
@if ($account->inclusive_taxes)
|
||||||
|
var tax2 = roundToTwo((total * 100) / (100 + (taxRate2 * 100)));
|
||||||
|
@else
|
||||||
|
var tax2 = roundToTwo(total * (taxRate2/100));
|
||||||
|
@endif
|
||||||
|
|
||||||
return self.formatMoney(tax1 + tax2);
|
return self.formatMoney(tax1 + tax2);
|
||||||
});
|
});
|
||||||
@ -447,7 +455,11 @@ function InvoiceModel(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var taxAmount = roundToTwo(lineTotal * item.tax_rate1() / 100);
|
@if ($account->inclusive_taxes)
|
||||||
|
var taxAmount = roundToTwo((lineTotal * 100) / (100 + (item.tax_rate1() * 100)));
|
||||||
|
@else
|
||||||
|
var taxAmount = roundToTwo(lineTotal * item.tax_rate1() / 100);
|
||||||
|
@endif
|
||||||
if (taxAmount) {
|
if (taxAmount) {
|
||||||
var key = item.tax_name1() + item.tax_rate1();
|
var key = item.tax_name1() + item.tax_rate1();
|
||||||
if (taxes.hasOwnProperty(key)) {
|
if (taxes.hasOwnProperty(key)) {
|
||||||
@ -457,7 +469,11 @@ function InvoiceModel(data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var taxAmount = roundToTwo(lineTotal * item.tax_rate2() / 100);
|
@if ($account->inclusive_taxes)
|
||||||
|
var taxAmount = roundToTwo((lineTotal * 100) / (100 + (item.tax_rate2() * 100)));
|
||||||
|
@else
|
||||||
|
var taxAmount = roundToTwo(lineTotal * item.tax_rate2() / 100);
|
||||||
|
@endif
|
||||||
if (taxAmount) {
|
if (taxAmount) {
|
||||||
var key = item.tax_name2() + item.tax_rate2();
|
var key = item.tax_name2() + item.tax_rate2();
|
||||||
if (taxes.hasOwnProperty(key)) {
|
if (taxes.hasOwnProperty(key)) {
|
||||||
@ -529,19 +545,21 @@ function InvoiceModel(data) {
|
|||||||
total = NINJA.parseFloat(total) + customValue2;
|
total = NINJA.parseFloat(total) + customValue2;
|
||||||
}
|
}
|
||||||
|
|
||||||
var taxAmount1 = roundToTwo(total * parseFloat(self.tax_rate1()) / 100);
|
@if (! $account->inclusive_taxes)
|
||||||
var taxAmount2 = roundToTwo(total * parseFloat(self.tax_rate2()) / 100);
|
var taxAmount1 = roundToTwo(total * parseFloat(self.tax_rate1()) / 100);
|
||||||
|
var taxAmount2 = roundToTwo(total * parseFloat(self.tax_rate2()) / 100);
|
||||||
|
|
||||||
total = NINJA.parseFloat(total) + taxAmount1 + taxAmount2;
|
total = NINJA.parseFloat(total) + taxAmount1 + taxAmount2;
|
||||||
total = roundToTwo(total);
|
total = roundToTwo(total);
|
||||||
|
|
||||||
var taxes = self.totals.itemTaxes();
|
var taxes = self.totals.itemTaxes();
|
||||||
for (var key in taxes) {
|
for (var key in taxes) {
|
||||||
if (taxes.hasOwnProperty(key)) {
|
if (taxes.hasOwnProperty(key)) {
|
||||||
total += taxes[key].amount;
|
total += taxes[key].amount;
|
||||||
total = roundToTwo(total);
|
total = roundToTwo(total);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
@endif
|
||||||
|
|
||||||
if (customValue1 && !customTaxes1) {
|
if (customValue1 && !customTaxes1) {
|
||||||
total = NINJA.parseFloat(total) + customValue1;
|
total = NINJA.parseFloat(total) + customValue1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user