From a1ccfc8b22752ce8d8fc34fd4c04349c5e641dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20=C3=87ak=C4=B1rel?= Date: Sat, 21 Mar 2020 04:42:45 +0300 Subject: [PATCH] Add discount per item for invoice --- app/Http/Controllers/Sales/Invoices.php | 19 +++- app/Http/Controllers/Settings/Defaults.php | 8 +- app/Jobs/Sale/CreateInvoiceItem.php | 3 +- app/Models/Sale/InvoiceItem.php | 29 ++++- app/Models/Sale/InvoiceItemDiscount.php | 42 ++++++++ .../2020_01_08_000000_core_v200.php | 5 + database/seeds/Settings.php | 1 + public/css/custom.css | 8 ++ resources/assets/js/views/sales/invoices.js | 20 ++-- resources/lang/en-GB/settings.php | 9 +- .../views/sales/invoices/create.blade.php | 100 ++++++++++-------- resources/views/sales/invoices/edit.blade.php | 6 +- resources/views/sales/invoices/item.blade.php | 31 ++++++ resources/views/sales/invoices/show.blade.php | 12 +++ .../views/settings/default/edit.blade.php | 2 + 15 files changed, 235 insertions(+), 60 deletions(-) create mode 100644 app/Models/Sale/InvoiceItemDiscount.php diff --git a/app/Http/Controllers/Sales/Invoices.php b/app/Http/Controllers/Sales/Invoices.php index 38a2d66e2..fd72a8f61 100644 --- a/app/Http/Controllers/Sales/Invoices.php +++ b/app/Http/Controllers/Sales/Invoices.php @@ -77,6 +77,8 @@ class Invoices extends Controller $date_format = $this->getCompanyDateFormat(); + $discount_location = $invoice->totals->contains($invoice->totals->where('code', 'discount')->first()) ? 'in_totals' : 'per_item'; + // Get Invoice Totals foreach ($invoice->totals as $invoice_total) { $invoice->{$invoice_total->code} = $invoice_total->amount; @@ -90,7 +92,22 @@ class Invoices extends Controller $invoice->grand_total = round($invoice->total - $invoice->paid, $currency->precision); } - return view('sales.invoices.show', compact('invoice', 'accounts', 'currencies', 'currency', 'account_currency_code', 'customers', 'categories', 'payment_methods', 'signed_url', 'date_format')); + return view( + 'sales.invoices.show', + compact( + 'invoice', + 'accounts', + 'currencies', + 'currency', + 'account_currency_code', + 'customers', + 'categories', + 'payment_methods', + 'signed_url', + 'date_format', + 'discount_location' + ) + ); } /** diff --git a/app/Http/Controllers/Settings/Defaults.php b/app/Http/Controllers/Settings/Defaults.php index 476c8a155..c9bf56608 100644 --- a/app/Http/Controllers/Settings/Defaults.php +++ b/app/Http/Controllers/Settings/Defaults.php @@ -27,12 +27,18 @@ class Defaults extends Controller $payment_methods = Modules::getPaymentMethods(); + $discount_locations = [ + 'in_totals' => trans('settings.default.discount_in_totals'), + 'per_item' => trans('settings.default.discount_per_item'), + ]; + return view('settings.default.edit', compact( 'setting', 'accounts', 'currencies', 'taxes', - 'payment_methods' + 'payment_methods', + 'discount_locations' )); } } diff --git a/app/Jobs/Sale/CreateInvoiceItem.php b/app/Jobs/Sale/CreateInvoiceItem.php index 5e78a0fea..fc6994dd2 100644 --- a/app/Jobs/Sale/CreateInvoiceItem.php +++ b/app/Jobs/Sale/CreateInvoiceItem.php @@ -40,7 +40,7 @@ class CreateInvoiceItem extends Job // Apply discount to amount if (!empty($this->request['discount'])) { - $item_discounted_amount = $item_amount - ($item_amount * ($this->request['discount'] / 100)); + $item_discounted_amount = $item_amount -= ($item_amount * ($this->request['discount'] / 100)); } $tax_amount = 0; @@ -138,6 +138,7 @@ class CreateInvoiceItem extends Job 'quantity' => (double) $this->request['quantity'], 'price' => (double) $this->request['price'], 'tax' => $item_tax_total, + 'discount_rate' => $this->request['discount'], 'total' => $item_amount, ]); diff --git a/app/Models/Sale/InvoiceItem.php b/app/Models/Sale/InvoiceItem.php index 692269912..e55577291 100644 --- a/app/Models/Sale/InvoiceItem.php +++ b/app/Models/Sale/InvoiceItem.php @@ -17,7 +17,18 @@ class InvoiceItem extends Model * * @var array */ - protected $fillable = ['company_id', 'invoice_id', 'item_id', 'name', 'quantity', 'price', 'total', 'tax']; + protected $fillable = [ + 'company_id', + 'invoice_id', + 'item_id', + 'name', + 'quantity', + 'price', + 'total', + 'tax', + 'discount_rate', + 'discount_type', + ]; /** * Clonable relationships. @@ -83,6 +94,22 @@ class InvoiceItem extends Model $this->attributes['tax'] = (double) $value; } + /** + * Get the formatted discount. + * + * @return string + */ + public function getDiscountRateAttribute($value) + { + if (setting('localisation.percent_position', 'after') === 'after') { + $text = ($this->discount_type === 'normal') ? $value . '%' : $value; + } else { + $text = ($this->discount_type === 'normal') ? '%' . $value : $value; + } + + return $text; + } + /** * Convert tax to Array. * diff --git a/app/Models/Sale/InvoiceItemDiscount.php b/app/Models/Sale/InvoiceItemDiscount.php new file mode 100644 index 000000000..2e4ffffbc --- /dev/null +++ b/app/Models/Sale/InvoiceItemDiscount.php @@ -0,0 +1,42 @@ +belongsTo('App\Models\Sale\Invoice'); + } + + public function item() + { + return $this->belongsToThrough('App\Models\Common\Item', 'App\Models\Sale\InvoiceItem', 'invoice_item_id')->withDefault(['name' => trans('general.na')]); + } + + /** + * Convert rate to double. + * + * @param string $value + * @return void + */ + public function setRateAttribute($value) + { + $this->attributes['rate'] = (double) $value; + } +} diff --git a/database/migrations/2020_01_08_000000_core_v200.php b/database/migrations/2020_01_08_000000_core_v200.php index 0735f5a66..cb6acab5a 100644 --- a/database/migrations/2020_01_08_000000_core_v200.php +++ b/database/migrations/2020_01_08_000000_core_v200.php @@ -240,6 +240,11 @@ class CoreV200 extends Migration Schema::table('users', function (Blueprint $table) { $table->string('landing_page', 70)->nullable()->default('dashboard'); }); + + Schema::table('invoice_items', function (Blueprint $table) { + $table->double('discount_rate', 15, 4)->default('0.0000'); + $table->string('discount_type')->default('normal'); + }); } /** diff --git a/database/seeds/Settings.php b/database/seeds/Settings.php index d12ef1230..386472d27 100644 --- a/database/seeds/Settings.php +++ b/database/seeds/Settings.php @@ -63,6 +63,7 @@ class Settings extends Seeder 'invoice.color' => '#55588b', 'default.payment_method' => 'offline-payments.cash.1', 'default.list_limit' => '25', + 'default.discount_location' => 'in_totals', 'default.use_gravatar' => '0', 'email.protocol' => 'mail', 'email.sendmail_path' => '/usr/sbin/sendmail -bs', diff --git a/public/css/custom.css b/public/css/custom.css index de7a60b65..0ea69d22c 100644 --- a/public/css/custom.css +++ b/public/css/custom.css @@ -740,6 +740,14 @@ table .align-items-center td span.badge /*--Quantity Width Finish--*/ +/*--Discount Width--*/ +.w-12 +{ + width: 12%; +} +/*--Discount Width Finish--*/ + + /*--------Responsive--------*/ /*--Xs Breakpoint--*/ @media (max-width: 575.98px) diff --git a/resources/assets/js/views/sales/invoices.js b/resources/assets/js/views/sales/invoices.js index c5e485fbb..0983b53da 100644 --- a/resources/assets/js/views/sales/invoices.js +++ b/resources/assets/js/views/sales/invoices.js @@ -75,6 +75,7 @@ const app = new Vue({ price: (item.price).toFixed(2), quantity: item.quantity, tax_id: item.tax_id, + discount: item.discount_rate, total: (item.total).toFixed(2) }); }); @@ -109,7 +110,8 @@ const app = new Vue({ let tax_total = 0; let grand_total = 0; let items = this.form.items; - let discount = this.form.discount; + let discount_in_totals = this.form.discount; + let discount = ''; if (items.length) { let index = 0; @@ -125,8 +127,14 @@ const app = new Vue({ // item discount calculate. let item_discounted_total = item_sub_total; - if (discount) { - item_discounted_total = item_sub_total - (item_sub_total * (discount / 100)); + if (discount_in_totals) { + item_discounted_total = item_sub_total - (item_sub_total * (discount_in_totals / 100)); + discount = discount_in_totals; + } + + if (item.discount) { + item_discounted_total = item_sub_total = item_sub_total - (item_sub_total * (item.discount / 100)); + discount = item.discount; } // item tax calculate. @@ -202,12 +210,12 @@ const app = new Vue({ this.totals.tax = tax_total; // Apply discount to total - if (discount) { - discount_total = sub_total * (discount / 100); + if (discount_in_totals) { + discount_total = sub_total * (discount_in_totals / 100); this.totals.discount = discount_total; - sub_total = sub_total - (sub_total * (discount / 100)); + sub_total = sub_total - (sub_total * (discount_in_totals / 100)); } // set all item grand total. diff --git a/resources/lang/en-GB/settings.php b/resources/lang/en-GB/settings.php index 044061471..c6228526d 100644 --- a/resources/lang/en-GB/settings.php +++ b/resources/lang/en-GB/settings.php @@ -59,9 +59,12 @@ return [ ], 'default' => [ - 'description' => 'Default account, currency, language of your company', - 'list_limit' => 'Records Per Page', - 'use_gravatar' => 'Use Gravatar', + 'description' => 'Default account, currency, language of your company', + 'list_limit' => 'Records Per Page', + 'use_gravatar' => 'Use Gravatar', + 'discount_location' => 'Discount', + 'discount_per_item' => 'Per Item', + 'discount_in_totals' => 'In Totals', ], 'email' => [ diff --git a/resources/views/sales/invoices/create.blade.php b/resources/views/sales/invoices/create.blade.php index 74415c55c..2fd310441 100644 --- a/resources/views/sales/invoices/create.blade.php +++ b/resources/views/sales/invoices/create.blade.php @@ -51,6 +51,12 @@ {{ trans($text_override['price']) }} @stack('price_th_end') + @stack('discount_th_start') + @if(setting('default.discount_location', 'in_totals') === 'per_item') + {{ trans('invoices.discount') }} + @endif + @stack('discount_th_end') + @stack('taxes_th_start') {{ trans_choice('general.taxes', 1) }} @stack('taxes_th_end') @@ -69,13 +75,13 @@ - + @stack('add_item_td_end') @stack('sub_total_td_start') - + {{ trans('invoices.sub_total') }} @@ -87,60 +93,62 @@ @stack('sub_total_td_end') @stack('add_discount_td_start') - - - -
-
-
-
-
-
- - - + @if(setting('default.discount_location', 'in_totals') === 'in_totals') + + + +
+
+
+
+
+
+ + + +
+ {!! Form::number('pre_discount', null, ['id' => 'pre-discount', 'class' => 'form-control']) !!} +
+
+
+
+ {{ trans('invoices.discount_desc') }}
- {!! Form::number('pre_discount', null, ['id' => 'pre-discount', 'class' => 'form-control']) !!}
-
-
- {{ trans('invoices.discount_desc') }} +
+
- -
- {{ trans('invoices.add_discount') }} - - - - - {{ Form::moneyGroup('discount_total', '', '', ['disabled' => true, 'required' => 'required', 'v-model' => 'totals.discount', 'currency' => $currency, 'masked' => 'true'], 0.00, 'text-right d-none') }} - - @money(0, $currency->code, true) - {!! Form::hidden('discount', null, ['id' => 'discount', 'class' => 'form-control text-right', 'v-model' => 'form.discount']) !!} - - + {{ trans('invoices.add_discount') }} + + + + + {{ Form::moneyGroup('discount_total', '', '', ['disabled' => true, 'required' => 'required', 'v-model' => 'totals.discount', 'currency' => $currency, 'masked' => 'true'], 0.00, 'text-right d-none') }} + + @money(0, $currency->code, true) + {!! Form::hidden('discount', null, ['id' => 'discount', 'class' => 'form-control text-right', 'v-model' => 'form.discount']) !!} + + + @endif @stack('add_discount_td_end') @stack('tax_total_td_start') - + {{ trans_choice('general.taxes', 1) }} @@ -153,7 +161,7 @@ @stack('grand_total_td_start') - + {{ trans('invoices.total') }} diff --git a/resources/views/sales/invoices/edit.blade.php b/resources/views/sales/invoices/edit.blade.php index 165f0e884..a26e97582 100644 --- a/resources/views/sales/invoices/edit.blade.php +++ b/resources/views/sales/invoices/edit.blade.php @@ -52,6 +52,10 @@ {{ trans($text_override['price']) }} @stack('price_th_end') + @stack('discount_th_start') + {{ trans('invoices.discount') }} + @stack('discount_th_end') + @stack('taxes_th_start') {{ trans_choice('general.taxes', 1) }} @stack('taxes_th_end') @@ -88,7 +92,7 @@ @stack('sub_total_td_end') @stack('add_discount_td_start') - + @stack('price_td_end') + @stack('discount_td_start') + + @stack('discount_input_start') +
+
+ + + +
+ + +
+
+
+ @stack('discount_input_end') + + @stack('discount_td_end') + @stack('taxes_td_start') diff --git a/resources/views/sales/invoices/show.blade.php b/resources/views/sales/invoices/show.blade.php index 6a207f4b4..360f2720c 100644 --- a/resources/views/sales/invoices/show.blade.php +++ b/resources/views/sales/invoices/show.blade.php @@ -356,6 +356,12 @@ {{ trans($text_override['price']) }} @stack('price_th_end') + @stack('discount_th_start') + @if($discount_location === 'per_item') + {{ trans('invoices.discount') }} + @endif + @stack('discount_th_end') + @stack('total_th_start') {{ trans('invoices.total') }} @stack('total_th_end') @@ -379,6 +385,12 @@ @money($invoice_item->price, $invoice->currency_code, true) @stack('price_td_end') + @stack('discount_td_start') + @if($discount_location === 'per_item') + {{ $invoice_item->discount_rate }} + @endif + @stack('discount_td_end') + @stack('total_td_start') @money($invoice_item->total, $invoice->currency_code, true) @stack('total_td_end') diff --git a/resources/views/settings/default/edit.blade.php b/resources/views/settings/default/edit.blade.php index 5c9595c1a..b58bb4816 100644 --- a/resources/views/settings/default/edit.blade.php +++ b/resources/views/settings/default/edit.blade.php @@ -30,6 +30,8 @@ {{ Form::selectGroup('list_limit', trans('settings.default.list_limit'), 'columns', ['10' => '10', '25' => '25', '50' => '50', '100' => '100'], !empty($setting['list_limit']) ? $setting['list_limit'] : null, []) }} + {{ Form::selectGroup('discount_location', trans('settings.default.discount_location'), 'percent', $discount_locations, !empty($setting['discount_location']) ? $setting['discount_location'] : 'in_totals', []) }} + {{ Form::radioGroup('use_gravatar', trans('settings.default.use_gravatar'), $setting->get('use_gravatar')) }}