diff --git a/app/Jobs/Purchase/CreateBill.php b/app/Jobs/Purchase/CreateBill.php index 531091095..c87539e10 100644 --- a/app/Jobs/Purchase/CreateBill.php +++ b/app/Jobs/Purchase/CreateBill.php @@ -64,7 +64,7 @@ class CreateBill extends Job protected function createItemsAndTotals() { // Create items - list($sub_total, $taxes) = $this->createItems(); + list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); $sort_order = 1; @@ -83,8 +83,23 @@ class CreateBill extends Job $sort_order++; // Add discount + if ($discount_amount_total > 0) { + BillTotal::create([ + 'company_id' => $this->bill->company_id, + 'bill_id' => $this->bill->id, + 'code' => 'item_discount', + 'name' => 'bills.item_discount', + 'amount' => $discount_amount_total, + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] -= $discount_amount_total; + + $sort_order++; + } + if (!empty($this->request['discount'])) { - $discount_total = $sub_total * ($this->request['discount'] / 100); + $discount_total = ($sub_total - $discount_amount_total) * ($this->request['discount'] / 100); BillTotal::create([ 'company_id' => $this->bill->company_id, @@ -155,7 +170,7 @@ class CreateBill extends Job protected function createItems() { - $sub_total = 0; + $sub_total = $discount_amount = $discount_amount_total = 0; $taxes = []; @@ -170,8 +185,14 @@ class CreateBill extends Job $bill_item = $this->dispatch(new CreateBillItem($item, $this->bill)); + $item_amount = (double) $item['price'] * (double) $item['quantity']; + + $discount_amount = ($item_amount * ($item['discount'] / 100)); + // Calculate totals - $sub_total += $bill_item->total; + $sub_total += $bill_item->total + $discount_amount; + + $discount_amount_total += $discount_amount; if (!$bill_item->item_taxes) { continue; @@ -190,6 +211,6 @@ class CreateBill extends Job } } - return [$sub_total, $taxes]; + return [$sub_total, $discount_amount_total, $taxes]; } } diff --git a/app/Jobs/Purchase/CreateBillItem.php b/app/Jobs/Purchase/CreateBillItem.php index 37f19b3d7..99307d45f 100644 --- a/app/Jobs/Purchase/CreateBillItem.php +++ b/app/Jobs/Purchase/CreateBillItem.php @@ -40,7 +40,7 @@ class CreateBillItem 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 CreateBillItem 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/Jobs/Purchase/UpdateBill.php b/app/Jobs/Purchase/UpdateBill.php index 6b673d723..4e8420eff 100644 --- a/app/Jobs/Purchase/UpdateBill.php +++ b/app/Jobs/Purchase/UpdateBill.php @@ -72,7 +72,7 @@ class UpdateBill extends Job protected function createItemsAndTotals() { // Create items - list($sub_total, $taxes) = $this->createItems(); + list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); // Delete current totals $this->deleteRelationships($this->bill, 'totals'); @@ -94,8 +94,23 @@ class UpdateBill extends Job $sort_order++; // Add discount + if ($discount_amount_total > 0) { + BillTotal::create([ + 'company_id' => $this->bill->company_id, + 'bill_id' => $this->bill->id, + 'code' => 'item_discount', + 'name' => 'bills.item_discount', + 'amount' => $discount_amount_total, + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] -= $discount_amount_total; + + $sort_order++; + } + if (!empty($this->request['discount'])) { - $discount_total = $sub_total * ($this->request['discount'] / 100); + $discount_total = ($sub_total - $discount_amount_total) * ($this->request['discount'] / 100); BillTotal::create([ 'company_id' => $this->bill->company_id, @@ -166,7 +181,7 @@ class UpdateBill extends Job protected function createItems() { - $sub_total = 0; + $sub_total = $discount_amount = $discount_amount_total = 0; $taxes = []; @@ -184,8 +199,14 @@ class UpdateBill extends Job $bill_item = $this->dispatch(new CreateBillItem($item, $this->bill)); + $item_amount = (double) $item['price'] * (double) $item['quantity']; + + $discount_amount = ($item_amount * ($item['discount'] / 100)); + // Calculate totals - $sub_total += $bill_item->total; + $sub_total += $bill_item->total + $discount_amount; + + $discount_amount_total += $discount_amount; if (!$bill_item->item_taxes) { continue; @@ -204,6 +225,6 @@ class UpdateBill extends Job } } - return [$sub_total, $taxes]; + return [$sub_total, $discount_amount_total, $taxes]; } } diff --git a/app/Jobs/Sale/CreateInvoice.php b/app/Jobs/Sale/CreateInvoice.php index 6ac4c4df1..7ade6315f 100644 --- a/app/Jobs/Sale/CreateInvoice.php +++ b/app/Jobs/Sale/CreateInvoice.php @@ -64,7 +64,7 @@ class CreateInvoice extends Job protected function createItemsAndTotals() { // Create items - list($sub_total, $taxes) = $this->createItems(); + list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); $sort_order = 1; @@ -83,8 +83,23 @@ class CreateInvoice extends Job $sort_order++; // Add discount + if ($discount_amount_total > 0) { + InvoiceTotal::create([ + 'company_id' => $this->invoice->company_id, + 'invoice_id' => $this->invoice->id, + 'code' => 'item_discount', + 'name' => 'invoices.item_discount', + 'amount' => $discount_amount_total, + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] -= $discount_amount_total; + + $sort_order++; + } + if (!empty($this->request['discount'])) { - $discount_total = $sub_total * ($this->request['discount'] / 100); + $discount_total = ($sub_total - $discount_amount_total) * ($this->request['discount'] / 100); InvoiceTotal::create([ 'company_id' => $this->invoice->company_id, @@ -155,7 +170,7 @@ class CreateInvoice extends Job protected function createItems() { - $sub_total = 0; + $sub_total = $discount_amount = $discount_amount_total = 0; $taxes = []; @@ -170,8 +185,14 @@ class CreateInvoice extends Job $invoice_item = $this->dispatch(new CreateInvoiceItem($item, $this->invoice)); + $item_amount = (double) $item['price'] * (double) $item['quantity']; + + $discount_amount = ($item_amount * ($item['discount'] / 100)); + // Calculate totals - $sub_total += $invoice_item->total; + $sub_total += $invoice_item->total + $discount_amount; + + $discount_amount_total += $discount_amount; if (!$invoice_item->item_taxes) { continue; @@ -190,6 +211,6 @@ class CreateInvoice extends Job } } - return [$sub_total, $taxes]; + return [$sub_total, $discount_amount_total, $taxes]; } } 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/Jobs/Sale/UpdateInvoice.php b/app/Jobs/Sale/UpdateInvoice.php index 344534d2c..85c15c1c4 100644 --- a/app/Jobs/Sale/UpdateInvoice.php +++ b/app/Jobs/Sale/UpdateInvoice.php @@ -72,7 +72,7 @@ class UpdateInvoice extends Job protected function createItemsAndTotals() { // Create items - list($sub_total, $taxes) = $this->createItems(); + list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); // Delete current totals $this->deleteRelationships($this->invoice, 'totals'); @@ -94,8 +94,23 @@ class UpdateInvoice extends Job $sort_order++; // Add discount + if ($discount_amount_total > 0) { + InvoiceTotal::create([ + 'company_id' => $this->invoice->company_id, + 'invoice_id' => $this->invoice->id, + 'code' => 'item_discount', + 'name' => 'invoices.item_discount', + 'amount' => $discount_amount_total, + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] -= $discount_amount_total; + + $sort_order++; + } + if (!empty($this->request['discount'])) { - $discount_total = $sub_total * ($this->request['discount'] / 100); + $discount_total = ($sub_total - $discount_amount_total) * ($this->request['discount'] / 100); InvoiceTotal::create([ 'company_id' => $this->invoice->company_id, @@ -166,7 +181,7 @@ class UpdateInvoice extends Job protected function createItems() { - $sub_total = 0; + $sub_total = $discount_amount = $discount_amount_total = 0; $taxes = []; @@ -184,8 +199,14 @@ class UpdateInvoice extends Job $invoice_item = $this->dispatch(new CreateInvoiceItem($item, $this->invoice)); + $item_amount = (double) $item['price'] * (double) $item['quantity']; + + $discount_amount = ($item_amount * ($item['discount'] / 100)); + // Calculate totals - $sub_total += $invoice_item->total; + $sub_total += $invoice_item->total + $discount_amount; + + $discount_amount_total += $discount_amount; if (!$invoice_item->item_taxes) { continue; @@ -204,6 +225,6 @@ class UpdateInvoice extends Job } } - return [$sub_total, $taxes]; + return [$sub_total, $discount_amount_total, $taxes]; } } diff --git a/app/Models/Purchase/BillItem.php b/app/Models/Purchase/BillItem.php index b56c5af6f..942454b40 100644 --- a/app/Models/Purchase/BillItem.php +++ b/app/Models/Purchase/BillItem.php @@ -18,7 +18,18 @@ class BillItem extends Model * * @var array */ - protected $fillable = ['company_id', 'bill_id', 'item_id', 'name', 'quantity', 'price', 'total', 'tax']; + protected $fillable = [ + 'company_id', + 'bill_id', + 'item_id', + 'name', + 'quantity', + 'price', + 'total', + 'tax', + 'discount_rate', + 'discount_type', + ]; /** * Clonable relationships. @@ -84,6 +95,22 @@ class BillItem 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/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/database/migrations/2020_03_20_183732_core_v208.php b/database/migrations/2020_03_20_183732_core_v208.php new file mode 100644 index 000000000..896df429d --- /dev/null +++ b/database/migrations/2020_03_20_183732_core_v208.php @@ -0,0 +1,54 @@ +double('discount_rate', 15, 4)->default('0.0000')->after('tax'); + $table->string('discount_type')->default('normal')->after('discount_rate'); + } + ); + + Schema::table( + 'bill_items', + function (Blueprint $table) { + $table->double('discount_rate', 15, 4)->default('0.0000')->after('tax'); + $table->string('discount_type')->default('normal')->after('discount_rate'); + } + ); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table( + 'invoice_items', + function (Blueprint $table) { + $table->dropColumn(['discount_rate', 'discount_type']); + } + ); + + Schema::table( + 'bill_items', + function (Blueprint $table) { + $table->dropColumn(['discount_rate', 'discount_type']); + } + ); + } +} 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/purchases/bills.js b/resources/assets/js/views/purchases/bills.js index 9397710ab..67bf7e086 100644 --- a/resources/assets/js/views/purchases/bills.js +++ b/resources/assets/js/views/purchases/bills.js @@ -32,6 +32,7 @@ const app = new Vue({ bulk_action: new BulkAction('bills'), totals: { sub: 0, + item_discount: '', discount: '', discount_text: false, tax: 0, @@ -50,7 +51,7 @@ const app = new Vue({ items: '', discount: false, taxes: null, - colspan: 5, + colspan: 6, } }, @@ -75,6 +76,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) }); }); @@ -106,10 +108,12 @@ const app = new Vue({ onCalculateTotal() { let sub_total = 0; let discount_total = 0; + let item_discount_total = 0; 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; @@ -120,13 +124,22 @@ const app = new Vue({ let item = items[index]; // item sub total calcute. - let item_sub_total = item.price * item.quantity; + let item_total = item.price * item.quantity; // item discount calculate. - let item_discounted_total = item_sub_total; + let item_discounted_total = item_total; - if (discount) { - item_discounted_total = item_sub_total - (item_sub_total * (discount / 100)); + if (discount_in_totals) { + item_discounted_total = item_total - (item_total * (discount_in_totals / 100)); + discount = discount_in_totals; + } + + let discount_amount = 0; + + if (item.discount) { + discount_amount = item_total * (item.discount / 100); + item_discounted_total = item_total - discount_amount; + discount = item.discount; } // item tax calculate. @@ -178,7 +191,7 @@ const app = new Vue({ item_tax_total = item_sub_and_tax_total - item_base_rate; - item_sub_total = item_base_rate + discount; + item_total = item_base_rate + discount; } if (compounds.length) { @@ -189,10 +202,15 @@ const app = new Vue({ } // set item total - items[index].total = item_sub_total; + if (item.discount) { + items[index].total = item_discounted_total; + } else { + items[index].total = item_total; + } // calculate sub, tax, discount all items. - sub_total += item_sub_total; + item_discount_total += discount_amount; + sub_total += item_total; tax_total += item_tax_total; } } @@ -200,14 +218,17 @@ const app = new Vue({ // set global total variable. this.totals.sub = sub_total; this.totals.tax = tax_total; + this.totals.item_discount = item_discount_total; + + sub_total -= item_discount_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/assets/js/views/sales/invoices.js b/resources/assets/js/views/sales/invoices.js index c5e485fbb..961f59d40 100644 --- a/resources/assets/js/views/sales/invoices.js +++ b/resources/assets/js/views/sales/invoices.js @@ -32,6 +32,7 @@ const app = new Vue({ bulk_action: new BulkAction('invoices'), totals: { sub: 0, + item_discount: '', discount: '', discount_text: false, tax: 0, @@ -50,7 +51,7 @@ const app = new Vue({ items: '', discount: false, taxes: null, - colspan: 5, + colspan: 6, } }, @@ -75,6 +76,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) }); }); @@ -106,10 +108,12 @@ const app = new Vue({ onCalculateTotal() { let sub_total = 0; let discount_total = 0; + let item_discount_total = 0; 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; @@ -120,13 +124,22 @@ const app = new Vue({ let item = items[index]; // item sub total calcute. - let item_sub_total = item.price * item.quantity; + let item_total = item.price * item.quantity; // item discount calculate. - let item_discounted_total = item_sub_total; + let item_discounted_total = item_total; - if (discount) { - item_discounted_total = item_sub_total - (item_sub_total * (discount / 100)); + if (discount_in_totals) { + item_discounted_total = item_total - (item_total * (discount_in_totals / 100)); + discount = discount_in_totals; + } + + let discount_amount = 0; + + if (item.discount) { + discount_amount = item_total * (item.discount / 100); + item_discounted_total = item_total - discount_amount; + discount = item.discount; } // item tax calculate. @@ -178,7 +191,7 @@ const app = new Vue({ item_tax_total = item_sub_and_tax_total - item_base_rate; - item_sub_total = item_base_rate + discount; + item_total = item_base_rate + discount; } if (compounds.length) { @@ -189,10 +202,15 @@ const app = new Vue({ } // set item total - items[index].total = item_sub_total; + if (item.discount) { + items[index].total = item_discounted_total; + } else { + items[index].total = item_total; + } // calculate sub, tax, discount all items. - sub_total += item_sub_total; + item_discount_total += discount_amount; + sub_total += item_total; tax_total += item_tax_total; } } @@ -200,14 +218,17 @@ const app = new Vue({ // set global total variable. this.totals.sub = sub_total; this.totals.tax = tax_total; + this.totals.item_discount = item_discount_total; + + sub_total -= item_discount_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/bills.php b/resources/lang/en-GB/bills.php index 834694d52..5914cf59b 100644 --- a/resources/lang/en-GB/bills.php +++ b/resources/lang/en-GB/bills.php @@ -13,6 +13,7 @@ return [ 'price' => 'Price', 'sub_total' => 'Subtotal', 'discount' => 'Discount', + 'item_discount' => 'Item Discount', 'tax_total' => 'Tax Total', 'total' => 'Total', diff --git a/resources/lang/en-GB/invoices.php b/resources/lang/en-GB/invoices.php index 10e56bca3..e06ce9a68 100644 --- a/resources/lang/en-GB/invoices.php +++ b/resources/lang/en-GB/invoices.php @@ -13,6 +13,7 @@ return [ 'price' => 'Price', 'sub_total' => 'Subtotal', 'discount' => 'Discount', + 'item_discount' => 'Item Discount', 'tax_total' => 'Tax Total', 'total' => 'Total', diff --git a/resources/views/purchases/bills/create.blade.php b/resources/views/purchases/bills/create.blade.php index 10dcc00a5..f344556cb 100644 --- a/resources/views/purchases/bills/create.blade.php +++ b/resources/views/purchases/bills/create.blade.php @@ -51,6 +51,10 @@