mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 12:42:36 +01: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_pattern',
|
||||
'task_rate',
|
||||
'inclusive_taxes',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -987,6 +987,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
||||
'include_item_taxes_inline',
|
||||
'invoice_fields',
|
||||
'show_currency_code',
|
||||
'inclusive_taxes',
|
||||
]);
|
||||
|
||||
foreach ($this->invoice_items as $invoiceItem) {
|
||||
@ -1344,17 +1345,26 @@ class Invoice extends EntityModel implements BalanceAffecting
|
||||
public function getTaxes($calculatePaid = false)
|
||||
{
|
||||
$taxes = [];
|
||||
$account = $this->account;
|
||||
$taxable = $this->getTaxable();
|
||||
$paidAmount = $this->getAmountPaid($calculatePaid);
|
||||
|
||||
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;
|
||||
$this->calculateTax($taxes, $this->tax_name1, $this->tax_rate1, $invoiceTaxAmount, $invoicePaidAmount);
|
||||
}
|
||||
|
||||
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;
|
||||
$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);
|
||||
|
||||
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;
|
||||
$this->calculateTax($taxes, $invoiceItem->tax_name1, $invoiceItem->tax_rate1, $itemTaxAmount, $itemPaidAmount);
|
||||
}
|
||||
|
||||
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;
|
||||
$this->calculateTax($taxes, $invoiceItem->tax_name2, $invoiceItem->tax_rate2, $itemTaxAmount, $itemPaidAmount);
|
||||
}
|
||||
|
@ -26,7 +26,11 @@ class TaxRateDatatable extends EntityDatatable
|
||||
[
|
||||
'type',
|
||||
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;
|
||||
}
|
||||
|
||||
$taxAmount1 = round($total * ($invoice->tax_rate1 ? $invoice->tax_rate1 : 0) / 100, 2);
|
||||
$taxAmount2 = round($total * ($invoice->tax_rate2 ? $invoice->tax_rate2 : 0) / 100, 2);
|
||||
$total = round($total + $taxAmount1 + $taxAmount2, 2);
|
||||
$total += $itemTax;
|
||||
if (! $account->inclusive_taxes) {
|
||||
$taxAmount1 = round($total * ($invoice->tax_rate1 ? $invoice->tax_rate1 : 0) / 100, 2);
|
||||
$taxAmount2 = round($total * ($invoice->tax_rate2 ? $invoice->tax_rate2 : 0) / 100, 2);
|
||||
$total = round($total + $taxAmount1 + $taxAmount2, 2);
|
||||
$total += $itemTax;
|
||||
}
|
||||
|
||||
// custom fields not charged taxes
|
||||
if ($invoice->custom_value1 && ! $invoice->custom_taxes1) {
|
||||
|
@ -275,6 +275,7 @@ class AccountTransformer extends EntityTransformer
|
||||
'custom_contact_label1' => $account->custom_contact_label1,
|
||||
'custom_contact_label2' => $account->custom_contact_label2,
|
||||
'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']);
|
||||
});
|
||||
|
||||
Schema::table('accounts', function ($table) {
|
||||
$table->boolean('inclusive_taxes')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,5 +140,9 @@ class AddSubdomainToLookups extends Migration
|
||||
$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) {
|
||||
hasTaxes = true;
|
||||
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) {
|
||||
hasTaxes = true;
|
||||
var key = taxName2 + taxRate2;
|
||||
@ -683,14 +691,20 @@ function calculateAmounts(invoice) {
|
||||
if (parseFloat(invoice.tax_rate2 || 0) != 0) {
|
||||
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 (taxes.hasOwnProperty(key)) {
|
||||
total += taxes[key].amount;
|
||||
}
|
||||
if (invoice.account.inclusive_taxes != '1') {
|
||||
taxAmount1 = roundToTwo(total * taxRate1 / 100);
|
||||
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
|
||||
|
@ -2604,6 +2604,9 @@ $LANG = array(
|
||||
'processing_request' => 'Processing request',
|
||||
'mcrypt_warning' => 'Warning: Mcrypt is deprecated, run <code>php artisan ninja:update-key --legacy=true</code> to update your cipher.',
|
||||
'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('rate')->label('texts.rate')->append('%') !!}
|
||||
|
||||
{!! Former::radios('is_inclusive')->radios([
|
||||
trans('texts.exclusive') . ': 100 + 10% = 100 + 10' => array('name' => 'is_inclusive', 'value' => 0),
|
||||
trans('texts.inclusive') . ': 100 + 10% = 90.91 + 9.09' => array('name' => 'is_inclusive', 'value' => 1),
|
||||
])->check(0)
|
||||
->label('type')
|
||||
->help('tax_rate_type_help') !!}
|
||||
|
||||
@if (! auth()->user()->account->inclusive_taxes)
|
||||
{!! Former::radios('is_inclusive')->radios([
|
||||
trans('texts.exclusive') . ': 100 + 10% = 100 + 10' => array('name' => 'is_inclusive', 'value' => 0),
|
||||
trans('texts.inclusive') . ': 100 + 10% = 90.91 + 9.09' => array('name' => 'is_inclusive', 'value' => 1),
|
||||
])->check(0)
|
||||
->label('type')
|
||||
->help('tax_rate_type_help') !!}
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,6 +11,7 @@
|
||||
{{ Former::populateField('invoice_item_taxes', intval($account->invoice_item_taxes)) }}
|
||||
{{ 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('inclusive_taxes', intval($account->inclusive_taxes)) }}
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
@ -29,13 +30,19 @@
|
||||
->label(' ')
|
||||
->value(1) !!}
|
||||
|
||||
{!! Former::checkbox('include_item_taxes_inline')
|
||||
->text(trans('texts.include_item_taxes_inline'))
|
||||
{!! Former::checkbox('enable_second_tax_rate')
|
||||
->text(trans('texts.enable_second_tax_rate'))
|
||||
->label(' ')
|
||||
->value(1) !!}
|
||||
|
||||
{!! Former::checkbox('enable_second_tax_rate')
|
||||
->text(trans('texts.enable_second_tax_rate'))
|
||||
{!! Former::checkbox('inclusive_taxes')
|
||||
->text(trans('texts.inclusive_taxes_help'))
|
||||
->label(' ')
|
||||
->value(1) !!}
|
||||
|
||||
|
||||
{!! Former::checkbox('include_item_taxes_inline')
|
||||
->text(trans('texts.include_item_taxes_inline'))
|
||||
->label(' ')
|
||||
->value(1) !!}
|
||||
|
||||
@ -75,4 +82,14 @@
|
||||
</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
|
||||
|
@ -425,10 +425,18 @@ function InvoiceModel(data) {
|
||||
}
|
||||
|
||||
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 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);
|
||||
});
|
||||
@ -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) {
|
||||
var key = item.tax_name1() + item.tax_rate1();
|
||||
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) {
|
||||
var key = item.tax_name2() + item.tax_rate2();
|
||||
if (taxes.hasOwnProperty(key)) {
|
||||
@ -529,19 +545,21 @@ function InvoiceModel(data) {
|
||||
total = NINJA.parseFloat(total) + customValue2;
|
||||
}
|
||||
|
||||
var taxAmount1 = roundToTwo(total * parseFloat(self.tax_rate1()) / 100);
|
||||
var taxAmount2 = roundToTwo(total * parseFloat(self.tax_rate2()) / 100);
|
||||
@if (! $account->inclusive_taxes)
|
||||
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 = roundToTwo(total);
|
||||
total = NINJA.parseFloat(total) + taxAmount1 + taxAmount2;
|
||||
total = roundToTwo(total);
|
||||
|
||||
var taxes = self.totals.itemTaxes();
|
||||
for (var key in taxes) {
|
||||
if (taxes.hasOwnProperty(key)) {
|
||||
total += taxes[key].amount;
|
||||
total = roundToTwo(total);
|
||||
var taxes = self.totals.itemTaxes();
|
||||
for (var key in taxes) {
|
||||
if (taxes.hasOwnProperty(key)) {
|
||||
total += taxes[key].amount;
|
||||
total = roundToTwo(total);
|
||||
}
|
||||
}
|
||||
}
|
||||
@endif
|
||||
|
||||
if (customValue1 && !customTaxes1) {
|
||||
total = NINJA.parseFloat(total) + customValue1;
|
||||
|
Loading…
Reference in New Issue
Block a user