mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Per product Tax rate in invoice doesn't update product. #1108
This commit is contained in:
parent
22a1be4d9c
commit
0ed4250766
@ -82,7 +82,7 @@ class AccountApiController extends BaseAPIController
|
||||
$updatedAt = $request->updated_at ? date('Y-m-d H:i:s', $request->updated_at) : false;
|
||||
|
||||
$transformer = new AccountTransformer(null, $request->serializer);
|
||||
$account->load(array_merge($transformer->getDefaultIncludes(), ['projects.client', 'products.default_tax_rate']));
|
||||
$account->load(array_merge($transformer->getDefaultIncludes(), ['projects.client']));
|
||||
$account = $this->createItem($account, $transformer, 'account');
|
||||
|
||||
return $this->response($account);
|
||||
|
@ -487,7 +487,7 @@ class AccountController extends BaseController
|
||||
$data = [
|
||||
'account' => Auth::user()->account,
|
||||
'title' => trans('texts.tax_rates'),
|
||||
'taxRates' => TaxRate::scope()->whereIsInclusive(false)->get(['id', 'name', 'rate']),
|
||||
'taxRates' => TaxRate::scope()->whereIsInclusive(false)->get(),
|
||||
];
|
||||
|
||||
return View::make('accounts.tax_rates', $data);
|
||||
|
@ -302,9 +302,8 @@ class InvoiceController extends BaseController
|
||||
return [
|
||||
'data' => Input::old('data'),
|
||||
'account' => Auth::user()->account->load('country'),
|
||||
'products' => Product::scope()->with('default_tax_rate')->orderBy('product_key')->get(),
|
||||
'products' => Product::scope()->orderBy('product_key')->get(),
|
||||
'taxRateOptions' => $taxRateOptions,
|
||||
'defaultTax' => $account->default_tax_rate,
|
||||
'currencies' => Cache::get('currencies'),
|
||||
'sizes' => Cache::get('sizes'),
|
||||
'invoiceDesigns' => InvoiceDesign::getDesigns(),
|
||||
|
@ -346,8 +346,10 @@ class OnlinePaymentController extends BaseController
|
||||
'frequency_id' => Input::get('frequency_id'),
|
||||
'auto_bill_id' => Input::get('auto_bill_id'),
|
||||
'start_date' => Input::get('start_date', date('Y-m-d')),
|
||||
'tax_rate1' => $account->default_tax_rate ? $account->default_tax_rate->rate : 0,
|
||||
'tax_name1' => $account->default_tax_rate ? $account->default_tax_rate->name : '',
|
||||
'tax_rate1' => $account->tax_rate1,
|
||||
'tax_name1' => $account->tax_name1,
|
||||
'tax_rate2' => $account->tax_rate2,
|
||||
'tax_name2' => $account->tax_name2,
|
||||
'custom_text_value1' => Input::get('custom_invoice1'),
|
||||
'custom_text_value2' => Input::get('custom_invoice2'),
|
||||
'invoice_items' => [[
|
||||
@ -355,8 +357,10 @@ class OnlinePaymentController extends BaseController
|
||||
'notes' => $product->notes,
|
||||
'cost' => $product->cost,
|
||||
'qty' => 1,
|
||||
'tax_rate1' => $product->default_tax_rate ? $product->default_tax_rate->rate : 0,
|
||||
'tax_name1' => $product->default_tax_rate ? $product->default_tax_rate->name : '',
|
||||
'tax_rate1' => $account->tax_rate1,
|
||||
'tax_name1' => $account->tax_name1,
|
||||
'tax_rate2' => $account->tax_rate2,
|
||||
'tax_name2' => $account->tax_name2,
|
||||
'custom_value1' => Input::get('custom_product1') ?: $product->custom_value1,
|
||||
'custom_value2' => Input::get('custom_product2') ?: $product->custom_value2,
|
||||
]],
|
||||
|
@ -83,7 +83,7 @@ class ProductController extends BaseController
|
||||
|
||||
$data = [
|
||||
'account' => $account,
|
||||
'taxRates' => $account->invoice_item_taxes ? TaxRate::scope()->whereIsInclusive(false)->get(['id', 'name', 'rate']) : null,
|
||||
'taxRates' => $account->invoice_item_taxes ? TaxRate::scope()->whereIsInclusive(false)->get() : null,
|
||||
'product' => $product,
|
||||
'entity' => $product,
|
||||
'method' => 'PUT',
|
||||
|
@ -98,9 +98,8 @@ class QuoteController extends BaseController
|
||||
return [
|
||||
'entityType' => ENTITY_QUOTE,
|
||||
'account' => $account,
|
||||
'products' => Product::scope()->with('default_tax_rate')->orderBy('product_key')->get(),
|
||||
'products' => Product::scope()->orderBy('product_key')->get(),
|
||||
'taxRateOptions' => $account->present()->taxRateOptions,
|
||||
'defaultTax' => $account->default_tax_rate,
|
||||
'countries' => Cache::get('countries'),
|
||||
'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(),
|
||||
'taxRates' => TaxRate::scope()->orderBy('name')->get(),
|
||||
|
@ -110,7 +110,10 @@ class Account extends Eloquent
|
||||
'num_days_reminder3',
|
||||
'custom_invoice_text_label1',
|
||||
'custom_invoice_text_label2',
|
||||
'default_tax_rate_id',
|
||||
'tax_name1',
|
||||
'tax_rate1',
|
||||
'tax_name2',
|
||||
'tax_rate2',
|
||||
'recurring_hour',
|
||||
'invoice_number_pattern',
|
||||
'quote_number_pattern',
|
||||
@ -366,14 +369,6 @@ class Account extends Eloquent
|
||||
return $this->belongsTo('App\Models\Industry');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function default_tax_rate()
|
||||
{
|
||||
return $this->belongsTo('App\Models\TaxRate');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
|
@ -30,7 +30,10 @@ class Product extends EntityModel
|
||||
'notes',
|
||||
'cost',
|
||||
'qty',
|
||||
'default_tax_rate_id',
|
||||
'tax_name1',
|
||||
'tax_rate1',
|
||||
'tax_name2',
|
||||
'tax_rate2',
|
||||
'custom_value1',
|
||||
'custom_value2',
|
||||
];
|
||||
@ -84,12 +87,4 @@ class Product extends EntityModel
|
||||
{
|
||||
return $this->belongsTo('App\Models\User')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function default_tax_rate()
|
||||
{
|
||||
return $this->belongsTo('App\Models\TaxRate');
|
||||
}
|
||||
}
|
||||
|
@ -83,10 +83,12 @@ class InvoiceIntent extends BaseIntent
|
||||
$item['cost'] = $product->cost;
|
||||
$item['notes'] = $product->notes;
|
||||
|
||||
/*
|
||||
if ($taxRate = $product->default_tax_rate) {
|
||||
$item['tax_name1'] = $taxRate->name;
|
||||
$item['tax_rate1'] = $taxRate->rate;
|
||||
}
|
||||
*/
|
||||
|
||||
$invoiceItems[] = $item;
|
||||
}
|
||||
|
@ -655,6 +655,10 @@ class InvoiceRepository extends BaseRepository
|
||||
if ($product && (Auth::user()->can('edit', $product))) {
|
||||
$product->notes = ($task || $expense) ? '' : $item['notes'];
|
||||
$product->cost = $expense ? 0 : $item['cost'];
|
||||
$product->tax_name1 = $item['tax_name1'];
|
||||
$product->tax_rate1 = $item['tax_rate1'];
|
||||
$product->tax_name2 = $item['tax_name2'];
|
||||
$product->tax_rate2 = $item['tax_rate2'];
|
||||
$product->custom_value1 = isset($item['custom_value1']) ? $item['custom_value1'] : null;
|
||||
$product->custom_value2 = isset($item['custom_value2']) ? $item['custom_value2'] : null;
|
||||
$product->save();
|
||||
|
@ -23,18 +23,14 @@ class ProductRepository extends BaseRepository
|
||||
public function find($accountId, $filter = null)
|
||||
{
|
||||
$query = DB::table('products')
|
||||
->leftJoin('tax_rates', function ($join) {
|
||||
$join->on('tax_rates.id', '=', 'products.default_tax_rate_id')
|
||||
->whereNull('tax_rates.deleted_at');
|
||||
})
|
||||
->where('products.account_id', '=', $accountId)
|
||||
->select(
|
||||
'products.public_id',
|
||||
'products.product_key',
|
||||
'products.notes',
|
||||
'products.cost',
|
||||
'tax_rates.name as tax_name',
|
||||
'tax_rates.rate as tax_rate',
|
||||
'products.tax_name1 as tax_name',
|
||||
'products.tax_rate1 as tax_rate',
|
||||
'products.deleted_at',
|
||||
'products.is_deleted'
|
||||
);
|
||||
@ -82,9 +78,7 @@ class ProductRepository extends BaseRepository
|
||||
$max = SIMILAR_MIN_THRESHOLD;
|
||||
$productId = 0;
|
||||
|
||||
$products = Product::scope()
|
||||
->with('default_tax_rate')
|
||||
->get();
|
||||
$products = Product::scope()->get();
|
||||
|
||||
foreach ($products as $product) {
|
||||
if (! $product->product_key) {
|
||||
|
@ -213,7 +213,10 @@ class AccountTransformer extends EntityTransformer
|
||||
'num_days_reminder3' => $account->num_days_reminder3,
|
||||
'custom_invoice_text_label1' => $account->custom_invoice_text_label1,
|
||||
'custom_invoice_text_label2' => $account->custom_invoice_text_label2,
|
||||
'default_tax_rate_id' => $account->default_tax_rate_id ? $account->default_tax_rate->public_id : 0,
|
||||
'tax_name1' => $account->tax_name1 ?: '',
|
||||
'tax_rate1' => (float) $account->tax_rate1,
|
||||
'tax_name2' => $account->tax_name2 ?: '',
|
||||
'tax_rate2' => (float) $account->tax_rate2,
|
||||
'recurring_hour' => $account->recurring_hour,
|
||||
'invoice_number_pattern' => $account->invoice_number_pattern,
|
||||
'quote_number_pattern' => $account->quote_number_pattern,
|
||||
|
@ -15,7 +15,6 @@ class ProductTransformer extends EntityTransformer
|
||||
* @SWG\Property(property="notes", type="string", example="Notes...")
|
||||
* @SWG\Property(property="cost", type="number", format="float", example=10.00)
|
||||
* @SWG\Property(property="qty", type="number", format="float", example=1)
|
||||
* @SWG\Property(property="default_tax_rate_id", type="integer", example=1)
|
||||
* @SWG\Property(property="updated_at", type="integer", example=1451160233, readOnly=true)
|
||||
* @SWG\Property(property="archived_at", type="integer", example=1451160233, readOnly=true)
|
||||
*/
|
||||
@ -27,7 +26,10 @@ class ProductTransformer extends EntityTransformer
|
||||
'notes' => $product->notes,
|
||||
'cost' => $product->cost,
|
||||
'qty' => $product->qty,
|
||||
'default_tax_rate_id' => $product->default_tax_rate_id ? $product->default_tax_rate->public_id : 0,
|
||||
'tax_name1' => $product->tax_name1 ?: '',
|
||||
'tax_rate1' => (float) $product->tax_rate1,
|
||||
'tax_name2' => $product->tax_name2 ?: '',
|
||||
'tax_rate2' => (float) $product->tax_rate2,
|
||||
'updated_at' => $this->getTimestamp($product->updated_at),
|
||||
'archived_at' => $this->getTimestamp($product->deleted_at),
|
||||
]);
|
||||
|
@ -23,6 +23,41 @@ class AddDefaultNoteToClient extends Migration
|
||||
Schema::table('payments', function ($table) {
|
||||
$table->text('private_notes')->nullable();
|
||||
});
|
||||
|
||||
Schema::table('accounts', function ($table) {
|
||||
$table->string('tax_name1')->nullable();
|
||||
$table->decimal('tax_rate1', 13, 3);
|
||||
$table->string('tax_name2')->nullable();
|
||||
$table->decimal('tax_rate2', 13, 3);
|
||||
});
|
||||
|
||||
Schema::table('products', function ($table) {
|
||||
$table->string('tax_name1')->nullable();
|
||||
$table->decimal('tax_rate1', 13, 3);
|
||||
$table->string('tax_name2')->nullable();
|
||||
$table->decimal('tax_rate2', 13, 3);
|
||||
});
|
||||
|
||||
DB::statement('update products
|
||||
left join tax_rates on tax_rates.id = products.default_tax_rate_id
|
||||
set products.tax_name1 = tax_rates.name, products.tax_rate1 = tax_rates.rate');
|
||||
|
||||
DB::statement('update accounts
|
||||
left join tax_rates on tax_rates.id = accounts.default_tax_rate_id
|
||||
set accounts.tax_name1 = tax_rates.name, accounts.tax_rate1 = tax_rates.rate');
|
||||
|
||||
if (Schema::hasColumn('accounts', 'default_tax_rate_id')) {
|
||||
Schema::table('accounts', function ($table) {
|
||||
$table->dropColumn('default_tax_rate_id');
|
||||
}
|
||||
});
|
||||
|
||||
if (Schema::hasColumn('products', 'default_tax_rate_id')) {
|
||||
Schema::table('products', function ($table) {
|
||||
$table->dropColumn('default_tax_rate_id');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,5 +78,19 @@ class AddDefaultNoteToClient extends Migration
|
||||
Schema::table('payments', function ($table) {
|
||||
$table->dropColumn('private_notes');
|
||||
});
|
||||
|
||||
Schema::table('accounts', function ($table) {
|
||||
$table->dropColumn('tax_name1');
|
||||
$table->dropColumn('tax_rate1');
|
||||
$table->dropColumn('tax_name2');
|
||||
$table->dropColumn('tax_rate2');
|
||||
});
|
||||
|
||||
Schema::table('products', function ($table) {
|
||||
$table->dropColumn('tax_name1');
|
||||
$table->dropColumn('tax_rate1');
|
||||
$table->dropColumn('tax_name2');
|
||||
$table->dropColumn('tax_rate2');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -33,12 +33,7 @@
|
||||
|
||||
{!! Former::text('cost') !!}
|
||||
|
||||
@if ($account->invoice_item_taxes)
|
||||
{!! Former::select('default_tax_rate_id')
|
||||
->addOption('', '')
|
||||
->label(trans('texts.tax_rate'))
|
||||
->fromQuery($taxRates, function($model) { return $model->name . ': ' . $model->rate . '%'; }, 'id') !!}
|
||||
@endif
|
||||
@include('partials.tax_rates')
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -47,11 +47,7 @@
|
||||
|
||||
|
||||
|
||||
{!! Former::select('default_tax_rate_id')
|
||||
->style('max-width: 250px')
|
||||
->addOption('', '')
|
||||
->fromQuery($taxRates, function($model) { return $model->name . ': ' . $model->rate . '%'; }, 'id') !!}
|
||||
|
||||
@include('partials.tax_rates')
|
||||
|
||||
|
||||
{!! Former::actions( Button::success(trans('texts.save'))->submit()->appendIcon(Icon::create('floppy-disk')) ) !!}
|
||||
|
@ -152,35 +152,13 @@
|
||||
->label(' ')
|
||||
->value(1) !!}
|
||||
@endif
|
||||
|
||||
<div style="display:none" data-bind="visible: apply_taxes">
|
||||
<br/>
|
||||
{!! Former::select('tax_select1')
|
||||
->addOption('','')
|
||||
->label(trans('texts.tax_rate'))
|
||||
->onchange('taxSelectChange(event)')
|
||||
->fromQuery($taxRates) !!}
|
||||
|
||||
<div style="display:none">
|
||||
{!! Former::input('tax_rate1') !!}
|
||||
{!! Former::input('tax_name1') !!}
|
||||
</div>
|
||||
|
||||
<div style="display:{{ $account->enable_second_tax_rate ? 'block' : 'none' }}">
|
||||
{!! Former::select('tax_select2')
|
||||
->addOption('','')
|
||||
->label(trans('texts.tax_rate'))
|
||||
->onchange('taxSelectChange(event)')
|
||||
->fromQuery($taxRates) !!}
|
||||
|
||||
<div style="display:none">
|
||||
{!! Former::input('tax_rate2') !!}
|
||||
{!! Former::input('tax_name2') !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div style="display:none" data-bind="visible: apply_taxes">
|
||||
<br/>
|
||||
@include('partials.tax_rates')
|
||||
</div>
|
||||
|
||||
@if ($account->hasFeature(FEATURE_DOCUMENTS))
|
||||
{!! Former::checkbox('invoice_documents')
|
||||
->text(trans('texts.add_documents_to_invoice'))
|
||||
@ -259,7 +237,6 @@
|
||||
var vendors = {!! $vendors !!};
|
||||
var clients = {!! $clients !!};
|
||||
var categories = {!! $categories !!};
|
||||
var taxRates = {!! $taxRates !!};
|
||||
|
||||
var clientMap = {};
|
||||
var vendorMap = {};
|
||||
@ -355,9 +332,6 @@
|
||||
onClientChange();
|
||||
});
|
||||
|
||||
setTaxSelect(1);
|
||||
setTaxSelect(2);
|
||||
|
||||
@if ($data)
|
||||
// this means we failed so we'll reload the previous state
|
||||
window.model = new ViewModel({!! $data !!});
|
||||
@ -594,38 +568,6 @@
|
||||
window.countUploadingDocuments--;
|
||||
}
|
||||
|
||||
function taxSelectChange(event) {
|
||||
var $select = $(event.target);
|
||||
var tax = $select.find('option:selected').text();
|
||||
|
||||
var index = tax.lastIndexOf(': ');
|
||||
var taxName = tax.substring(0, index);
|
||||
var taxRate = tax.substring(index + 2, tax.length - 1);
|
||||
|
||||
var selectName = $select.attr('name');
|
||||
var instance = selectName.substring(selectName.length - 1);
|
||||
|
||||
$('#tax_name' + instance).val(taxName);
|
||||
$('#tax_rate' + instance).val(taxRate);
|
||||
}
|
||||
|
||||
function setTaxSelect(instance) {
|
||||
var $select = $('#tax_select' + instance);
|
||||
var taxName = $('#tax_name' + instance).val();
|
||||
var taxRate = $('#tax_rate' + instance).val();
|
||||
if (!taxRate || !taxName) {
|
||||
return;
|
||||
}
|
||||
var tax = _.findWhere(taxRates, {name:taxName, rate:taxRate});
|
||||
if (tax) {
|
||||
$select.val(tax.public_id);
|
||||
} else {
|
||||
var option = new Option(taxName + ': ' + taxRate + '%', '');
|
||||
option.selected = true;
|
||||
$select.append(option);
|
||||
}
|
||||
}
|
||||
|
||||
function onInvoiceDocumentsChange()
|
||||
{
|
||||
if (isStorageSupported()) {
|
||||
|
@ -908,10 +908,15 @@
|
||||
model.invoice().addItem(); // add blank item
|
||||
@else
|
||||
// set the default account tax rate
|
||||
@if ($account->invoice_taxes && ! empty($defaultTax))
|
||||
var defaultTax = {!! $defaultTax->toJson() !!};
|
||||
model.invoice().tax_rate1(defaultTax.rate);
|
||||
model.invoice().tax_name1(defaultTax.name);
|
||||
@if ($account->invoice_taxes)
|
||||
@if (! empty($account->tax_name1))
|
||||
model.invoice().tax_rate1("{{ $account->tax_rate1 }}");
|
||||
model.invoice().tax_name1("{{ $account->tax_name1 }}");
|
||||
@endif
|
||||
@if (! empty($account->tax_name2))
|
||||
model.invoice().tax_rate2("{{ $account->tax_rate2 }}");
|
||||
model.invoice().tax_name2("{{ $account->tax_name2 }}");
|
||||
@endif
|
||||
@endif
|
||||
@endif
|
||||
|
||||
|
@ -944,9 +944,13 @@ ko.bindingHandlers.productTypeahead = {
|
||||
model.qty(1);
|
||||
}
|
||||
@if ($account->invoice_item_taxes)
|
||||
if (datum.default_tax_rate) {
|
||||
if (datum.tax_name1) {
|
||||
var $select = $(this).parentsUntil('tbody').find('select').first();
|
||||
$select.val('0 ' + datum.default_tax_rate.rate + ' ' + datum.default_tax_rate.name).trigger('change');
|
||||
$select.val('0 ' + datum.tax_rate1 + ' ' + datum.tax_name1).trigger('change');
|
||||
}
|
||||
if (datum.tax_name2) {
|
||||
var $select = $(this).parentsUntil('tbody').find('select').last();
|
||||
$select.val('0 ' + datum.tax_rate2 + ' ' + datum.tax_name2).trigger('change');
|
||||
}
|
||||
@endif
|
||||
@if (Auth::user()->isPro() && $account->custom_invoice_item_label1)
|
||||
|
69
resources/views/partials/tax_rates.blade.php
Normal file
69
resources/views/partials/tax_rates.blade.php
Normal file
@ -0,0 +1,69 @@
|
||||
@if ($account->invoice_item_taxes)
|
||||
{!! Former::select('tax_select1')
|
||||
->addOption('','')
|
||||
->label(trans('texts.tax_rate'))
|
||||
->onchange('taxSelectChange(event)')
|
||||
->fromQuery($taxRates) !!}
|
||||
|
||||
<div style="display:none">
|
||||
{!! Former::input('tax_rate1') !!}
|
||||
{!! Former::input('tax_name1') !!}
|
||||
</div>
|
||||
|
||||
<div style="display:{{ $account->enable_second_tax_rate ? 'block' : 'none' }}">
|
||||
{!! Former::select('tax_select2')
|
||||
->addOption('','')
|
||||
->label(trans('texts.tax_rate'))
|
||||
->onchange('taxSelectChange(event)')
|
||||
->fromQuery($taxRates) !!}
|
||||
|
||||
<div style="display:none">
|
||||
{!! Former::input('tax_rate2') !!}
|
||||
{!! Former::input('tax_name2') !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var taxRates = {!! $taxRates !!};
|
||||
|
||||
function taxSelectChange(event) {
|
||||
var $select = $(event.target);
|
||||
var tax = $select.find('option:selected').text();
|
||||
|
||||
var index = tax.lastIndexOf(': ');
|
||||
var taxName = tax.substring(0, index);
|
||||
var taxRate = tax.substring(index + 2, tax.length - 1);
|
||||
|
||||
var selectName = $select.attr('name');
|
||||
var instance = selectName.substring(selectName.length - 1);
|
||||
|
||||
$('#tax_name' + instance).val(taxName);
|
||||
$('#tax_rate' + instance).val(taxRate);
|
||||
}
|
||||
|
||||
function setTaxSelect(instance) {
|
||||
var $select = $('#tax_select' + instance);
|
||||
var taxName = $('#tax_name' + instance).val();
|
||||
var taxRate = $('#tax_rate' + instance).val();
|
||||
if (!taxRate || !taxName) {
|
||||
return;
|
||||
}
|
||||
var tax = _.findWhere(taxRates, {name:taxName, rate:taxRate});
|
||||
if (tax) {
|
||||
$select.val(tax.public_id);
|
||||
} else {
|
||||
var option = new Option(taxName + ': ' + taxRate + '%', '');
|
||||
option.selected = true;
|
||||
$select.append(option);
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
setTaxSelect(1);
|
||||
setTaxSelect(2);
|
||||
});
|
||||
|
||||
</script>
|
Loading…
x
Reference in New Issue
Block a user