From 630fdb6e852a6113d1c4b6acf3fdcac035c2e772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Duli=C3=A7i?= Date: Mon, 6 Jul 2020 09:54:18 +0300 Subject: [PATCH] refactored calculations --- app/Abstracts/DocumentModel.php | 34 +-- app/Http/Controllers/Purchases/Bills.php | 2 +- .../Banking/CreateDocumentTransaction.php | 59 ++---- app/Jobs/Banking/CreateTransfer.php | 40 +--- app/Jobs/Banking/UpdateTransfer.php | 40 +--- app/Jobs/Purchase/CreateBill.php | 169 +-------------- app/Jobs/Purchase/CreateBillItem.php | 28 +-- .../Purchase/CreateBillItemsAndTotals.php | 199 ++++++++++++++++++ app/Jobs/Purchase/UpdateBill.php | 175 +-------------- app/Jobs/Sale/CreateInvoice.php | 167 +-------------- app/Jobs/Sale/CreateInvoiceItem.php | 28 +-- app/Jobs/Sale/CreateInvoiceItemsAndTotals.php | 198 +++++++++++++++++ app/Jobs/Sale/UpdateInvoice.php | 175 +-------------- app/Models/Banking/Transaction.php | 33 +-- app/Traits/Currencies.php | 35 ++- app/Utilities/Overrider.php | 6 +- app/Widgets/CashFlow.php | 6 + composer.json | 2 +- composer.lock | 22 +- .../banking/reconciliations/create.blade.php | 2 +- 20 files changed, 549 insertions(+), 871 deletions(-) create mode 100644 app/Jobs/Purchase/CreateBillItemsAndTotals.php create mode 100644 app/Jobs/Sale/CreateInvoiceItemsAndTotals.php diff --git a/app/Abstracts/DocumentModel.php b/app/Abstracts/DocumentModel.php index 8dd017c67..e95c1c258 100644 --- a/app/Abstracts/DocumentModel.php +++ b/app/Abstracts/DocumentModel.php @@ -87,35 +87,19 @@ abstract class DocumentModel extends Model return false; } - static $currencies; - $paid = 0; $reconciled = $reconciled_amount = 0; + $code = $this->currency_code; + $rate = config('money.' . $code . '.rate'); + $precision = config('money.' . $code . '.precision'); + if ($this->transactions->count()) { - if (empty($currencies)) { - $currencies = Currency::enabled()->pluck('rate', 'code')->toArray(); - } - foreach ($this->transactions as $item) { - if ($this->currency_code == $item->currency_code) { - $amount = (double) $item->amount; - } else { - $default_model = new Transaction(); - $default_model->default_currency_code = $this->currency_code; - $default_model->amount = $item->amount; - $default_model->currency_code = $item->currency_code; - $default_model->currency_rate = $currencies[$item->currency_code]; + $amount = $item->amount; - $default_amount = (double) $default_model->getAmountConvertedToDefault(); - - $convert_model = new Transaction(); - $convert_model->default_currency_code = $item->currency_code; - $convert_model->amount = $default_amount; - $convert_model->currency_code = $this->currency_code; - $convert_model->currency_rate = $currencies[$this->currency_code]; - - $amount = (double) $convert_model->getAmountConvertedFromDefault(); + if ($code != $item->currency_code) { + $amount = $this->convertBetween($amount, $item->currency_code, $item->currency_rate, $code, $rate); } $paid += $amount; @@ -126,13 +110,13 @@ abstract class DocumentModel extends Model } } - if ($this->amount == $reconciled_amount) { + if (bccomp(round($this->amount, $precision), round($reconciled_amount, $precision), $precision) === 0) { $reconciled = 1; } $this->setAttribute('reconciled', $reconciled); - return $paid; + return round($paid, $precision); } /** * Get the status label. diff --git a/app/Http/Controllers/Purchases/Bills.php b/app/Http/Controllers/Purchases/Bills.php index 43d1bda0e..0f2f8120b 100644 --- a/app/Http/Controllers/Purchases/Bills.php +++ b/app/Http/Controllers/Purchases/Bills.php @@ -83,7 +83,7 @@ class Bills extends Controller $bill->grand_total = money($total, $currency->code)->getAmount(); if (!empty($bill->paid)) { - $bill->grand_total = round($bill->total - $bill->paid, $currency->precision) ; + $bill->grand_total = round($bill->total - $bill->paid, $currency->precision); } return view('purchases.bills.show', compact('bill', 'accounts', 'currencies', 'currency', 'account_currency_code', 'vendors', 'categories', 'payment_methods', 'date_format')); diff --git a/app/Jobs/Banking/CreateDocumentTransaction.php b/app/Jobs/Banking/CreateDocumentTransaction.php index 93aca01e2..42675576f 100644 --- a/app/Jobs/Banking/CreateDocumentTransaction.php +++ b/app/Jobs/Banking/CreateDocumentTransaction.php @@ -8,11 +8,13 @@ use App\Jobs\Purchase\CreateBillHistory; use App\Jobs\Sale\CreateInvoiceHistory; use App\Models\Banking\Transaction; use App\Models\Sale\Invoice; -use App\Models\Setting\Currency; +use App\Traits\Currencies; use Date; class CreateDocumentTransaction extends Job { + use Currencies; + protected $model; protected $request; @@ -64,13 +66,10 @@ class CreateDocumentTransaction extends Job { $this->request['company_id'] = session('company_id'); $this->request['currency_code'] = isset($this->request['currency_code']) ? $this->request['currency_code'] : $this->model->currency_code; - - $this->currency = Currency::where('code', $this->request['currency_code'])->first(); - $this->request['type'] = ($this->model instanceof Invoice) ? 'income' : 'expense'; $this->request['paid_at'] = isset($this->request['paid_at']) ? $this->request['paid_at'] : Date::now()->format('Y-m-d'); $this->request['amount'] = isset($this->request['amount']) ? $this->request['amount'] : ($this->model->amount - $this->model->paid); - $this->request['currency_rate'] = $this->currency->rate; + $this->request['currency_rate'] = config('money.' . $this->request['currency_code'] . '.rate'); $this->request['account_id'] = isset($this->request['account_id']) ? $this->request['account_id'] : setting('default.account'); $this->request['document_id'] = isset($this->request['document_id']) ? $this->request['document_id'] : $this->model->id; $this->request['contact_id'] = isset($this->request['contact_id']) ? $this->request['contact_id'] : $this->model->contact_id; @@ -81,57 +80,33 @@ class CreateDocumentTransaction extends Job protected function checkAmount() { - $currencies = Currency::enabled()->pluck('rate', 'code')->toArray(); + $code = $this->request['currency_code']; + $rate = $this->request['currency_rate']; + $precision = config('money.' . $code . '.precision'); - $default_amount = (double) $this->request['amount']; + $amount = $this->request['amount'] = round($this->request['amount'], $precision); - if ($this->model->currency_code == $this->request['currency_code']) { - $amount = $default_amount; - } else { - $default_amount_model = new Transaction(); - $default_amount_model->default_currency_code = $this->model->currency_code; - $default_amount_model->amount = $default_amount; - $default_amount_model->currency_code = $this->request['currency_code']; - $default_amount_model->currency_rate = $currencies[$this->request['currency_code']]; + if ($this->model->currency_code != $code) { + $converted_amount = $this->convertBetween($amount, $code, $rate, $this->model->currency_code, $this->model->currency_rate); - $default_amount = (double) $default_amount_model->getAmountConvertedToDefault(); - - $convert_amount_model = new Transaction(); - $convert_amount_model->default_currency_code = $this->request['currency_code']; - $convert_amount_model->amount = $default_amount; - $convert_amount_model->currency_code = $this->model->currency_code; - $convert_amount_model->currency_rate = $currencies[$this->model->currency_code]; - - $amount = (double) $convert_amount_model->getAmountConvertedFromDefault(); + $amount = round($converted_amount, $precision); } - $total_amount = $this->model->amount - $this->model->paid; + $total_amount = round($this->model->amount - $this->model->paid, $precision); unset($this->model->reconciled); - $compare = bccomp($amount, $total_amount, $this->currency->precision); + $compare = bccomp($amount, $total_amount, $precision); if ($compare === 1) { $error_amount = $total_amount; - if ($this->model->currency_code != $this->request['currency_code']) { - $error_amount_model = new Transaction(); - $error_amount_model->default_currency_code = $this->request['currency_code']; - $error_amount_model->amount = $error_amount; - $error_amount_model->currency_code = $this->model->currency_code; - $error_amount_model->currency_rate = $currencies[$this->model->currency_code]; + if ($this->model->currency_code != $code) { + $converted_amount = $this->convertBetween($total_amount, $this->model->currency_code, $this->model->currency_rate, $code, $rate); - $error_amount = (double) $error_amount_model->getAmountConvertedToDefault(); - - $convert_amount_model = new Transaction(); - $convert_amount_model->default_currency_code = $this->model->currency_code; - $convert_amount_model->amount = $error_amount; - $convert_amount_model->currency_code = $this->request['currency_code']; - $convert_amount_model->currency_rate = $currencies[$this->request['currency_code']]; - - $error_amount = (double) $convert_amount_model->getAmountConvertedFromDefault(); + $error_amount = round($converted_amount, $precision); } - $message = trans('messages.error.over_payment', ['amount' => money($error_amount, $this->request['currency_code'], true)]); + $message = trans('messages.error.over_payment', ['amount' => money($error_amount, $code, true)]); throw new \Exception($message); } else { diff --git a/app/Jobs/Banking/CreateTransfer.php b/app/Jobs/Banking/CreateTransfer.php index 38b115199..301b09b7e 100644 --- a/app/Jobs/Banking/CreateTransfer.php +++ b/app/Jobs/Banking/CreateTransfer.php @@ -8,9 +8,12 @@ use App\Models\Banking\Transaction; use App\Models\Banking\Transfer; use App\Models\Setting\Category; use App\Models\Setting\Currency; +use App\Traits\Currencies; class CreateTransfer extends Job { + use Currencies; + protected $transfer; protected $request; @@ -33,18 +36,19 @@ class CreateTransfer extends Job public function handle() { \DB::transaction(function () { - $currencies = Currency::enabled()->pluck('rate', 'code')->toArray(); - $expense_currency_code = Account::where('id', $this->request->get('from_account_id'))->pluck('currency_code')->first(); $income_currency_code = Account::where('id', $this->request->get('to_account_id'))->pluck('currency_code')->first(); + $expense_currency_rate = config('money.' . $expense_currency_code . '.rate'); + $income_currency_rate = config('money.' . $income_currency_code . '.rate'); + $expense_transaction = Transaction::create([ 'company_id' => $this->request['company_id'], 'type' => 'expense', 'account_id' => $this->request->get('from_account_id'), 'paid_at' => $this->request->get('transferred_at'), 'currency_code' => $expense_currency_code, - 'currency_rate' => $currencies[$expense_currency_code], + 'currency_rate' => $expense_currency_rate, 'amount' => $this->request->get('amount'), 'contact_id' => 0, 'description' => $this->request->get('description'), @@ -53,33 +57,11 @@ class CreateTransfer extends Job 'reference' => $this->request->get('reference'), ]); + $amount = $this->request->get('amount'); + // Convert amount if not same currency if ($expense_currency_code != $income_currency_code) { - $default_currency = setting('default.currency', 'USD'); - - $default_amount = $this->request->get('amount'); - - if ($default_currency != $expense_currency_code) { - $default_amount_model = new Transfer(); - - $default_amount_model->default_currency_code = $default_currency; - $default_amount_model->amount = $this->request->get('amount'); - $default_amount_model->currency_code = $expense_currency_code; - $default_amount_model->currency_rate = $currencies[$expense_currency_code]; - - $default_amount = $default_amount_model->getAmountConvertedToDefault(); - } - - $transfer_amount = new Transfer(); - - $transfer_amount->default_currency_code = $expense_currency_code; - $transfer_amount->amount = $default_amount; - $transfer_amount->currency_code = $income_currency_code; - $transfer_amount->currency_rate = $currencies[$income_currency_code]; - - $amount = $transfer_amount->getAmountConvertedFromDefault(); - } else { - $amount = $this->request->get('amount'); + $amount = $this->convertBetween($amount, $expense_currency_code, $expense_currency_rate, $income_currency_code, $income_currency_rate); } $income_transaction = Transaction::create([ @@ -88,7 +70,7 @@ class CreateTransfer extends Job 'account_id' => $this->request->get('to_account_id'), 'paid_at' => $this->request->get('transferred_at'), 'currency_code' => $income_currency_code, - 'currency_rate' => $currencies[$income_currency_code], + 'currency_rate' => $income_currency_rate, 'amount' => $amount, 'contact_id' => 0, 'description' => $this->request->get('description'), diff --git a/app/Jobs/Banking/UpdateTransfer.php b/app/Jobs/Banking/UpdateTransfer.php index d9193a778..fcbc0a61d 100644 --- a/app/Jobs/Banking/UpdateTransfer.php +++ b/app/Jobs/Banking/UpdateTransfer.php @@ -8,9 +8,12 @@ use App\Models\Banking\Transaction; use App\Models\Banking\Transfer; use App\Models\Setting\Category; use App\Models\Setting\Currency; +use App\Traits\Currencies; class UpdateTransfer extends Job { + use Currencies; + protected $transfer; protected $request; @@ -35,11 +38,12 @@ class UpdateTransfer extends Job public function handle() { \DB::transaction(function () { - $currencies = Currency::enabled()->pluck('rate', 'code')->toArray(); - $expense_currency_code = Account::where('id', $this->request->get('from_account_id'))->pluck('currency_code')->first(); $income_currency_code = Account::where('id', $this->request->get('to_account_id'))->pluck('currency_code')->first(); + $expense_currency_rate = config('money.' . $expense_currency_code . '.rate'); + $income_currency_rate = config('money.' . $income_currency_code . '.rate'); + $expense_transaction = Transaction::findOrFail($this->transfer->expense_transaction_id); $income_transaction = Transaction::findOrFail($this->transfer->income_transaction_id); @@ -49,7 +53,7 @@ class UpdateTransfer extends Job 'account_id' => $this->request->get('from_account_id'), 'paid_at' => $this->request->get('transferred_at'), 'currency_code' => $expense_currency_code, - 'currency_rate' => $currencies[$expense_currency_code], + 'currency_rate' => $expense_currency_rate, 'amount' => $this->request->get('amount'), 'contact_id' => 0, 'description' => $this->request->get('description'), @@ -58,33 +62,11 @@ class UpdateTransfer extends Job 'reference' => $this->request->get('reference'), ]); + $amount = $this->request->get('amount'); + // Convert amount if not same currency if ($expense_currency_code != $income_currency_code) { - $default_currency = setting('default.currency', 'USD'); - - $default_amount = $this->request->get('amount'); - - if ($default_currency != $expense_currency_code) { - $default_amount_model = new Transfer(); - - $default_amount_model->default_currency_code = $default_currency; - $default_amount_model->amount = $this->request->get('amount'); - $default_amount_model->currency_code = $expense_currency_code; - $default_amount_model->currency_rate = $currencies[$expense_currency_code]; - - $default_amount = $default_amount_model->getAmountConvertedToDefault(); - } - - $transfer_amount = new Transfer(); - - $transfer_amount->default_currency_code = $expense_currency_code; - $transfer_amount->amount = $default_amount; - $transfer_amount->currency_code = $income_currency_code; - $transfer_amount->currency_rate = $currencies[$income_currency_code]; - - $amount = $transfer_amount->getAmountConvertedFromDefault(); - } else { - $amount = $this->request->get('amount'); + $amount = $this->convertBetween($amount, $expense_currency_code, $expense_currency_rate, $income_currency_code, $income_currency_rate); } $income_transaction->update([ @@ -93,7 +75,7 @@ class UpdateTransfer extends Job 'account_id' => $this->request->get('to_account_id'), 'paid_at' => $this->request->get('transferred_at'), 'currency_code' => $income_currency_code, - 'currency_rate' => $currencies[$income_currency_code], + 'currency_rate' => $income_currency_rate, 'amount' => $amount, 'contact_id' => 0, 'description' => $this->request->get('description'), diff --git a/app/Jobs/Purchase/CreateBill.php b/app/Jobs/Purchase/CreateBill.php index 12093253c..2ef85ec79 100644 --- a/app/Jobs/Purchase/CreateBill.php +++ b/app/Jobs/Purchase/CreateBill.php @@ -5,15 +5,11 @@ namespace App\Jobs\Purchase; use App\Abstracts\Job; use App\Events\Purchase\BillCreated; use App\Events\Purchase\BillCreating; +use App\Jobs\Purchase\CreateBillItemsAndTotals; use App\Models\Purchase\Bill; -use App\Models\Purchase\BillTotal; -use App\Traits\Currencies; -use App\Traits\DateTime; class CreateBill extends Job { - use Currencies, DateTime; - protected $bill; protected $request; @@ -51,9 +47,9 @@ class CreateBill extends Job $this->bill->attachMedia($media, 'attachment'); } - $this->createItemsAndTotals(); + $this->dispatch(new CreateBillItemsAndTotals($this->bill, $this->request)); - $this->bill->update($this->request->input()); + $this->bill->update($this->request->all()); $this->bill->createRecurring(); }); @@ -62,163 +58,4 @@ class CreateBill extends Job return $this->bill; } - - protected function createItemsAndTotals() - { - // Create items - list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); - - $sort_order = 1; - - // Add sub total - BillTotal::create([ - 'company_id' => $this->bill->company_id, - 'bill_id' => $this->bill->id, - 'code' => 'sub_total', - 'name' => 'bills.sub_total', - 'amount' => $sub_total, - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] += $sub_total; - - $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 - $discount_amount_total) * ($this->request['discount'] / 100); - - BillTotal::create([ - 'company_id' => $this->bill->company_id, - 'bill_id' => $this->bill->id, - 'code' => 'discount', - 'name' => 'bills.discount', - 'amount' => $discount_total, - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] -= $discount_total; - - $sort_order++; - } - - // Add taxes - if (!empty($taxes)) { - foreach ($taxes as $tax) { - BillTotal::create([ - 'company_id' => $this->bill->company_id, - 'bill_id' => $this->bill->id, - 'code' => 'tax', - 'name' => $tax['name'], - 'amount' => $tax['amount'], - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] += $tax['amount']; - - $sort_order++; - } - } - - // Add extra totals, i.e. shipping fee - if (!empty($this->request['totals'])) { - foreach ($this->request['totals'] as $total) { - $total['company_id'] = $this->bill->company_id; - $total['bill_id'] = $this->bill->id; - $total['sort_order'] = $sort_order; - - if (empty($total['code'])) { - $total['code'] = 'extra'; - } - - BillTotal::create($total); - - if (empty($total['operator']) || ($total['operator'] == 'addition')) { - $this->request['amount'] += $total['amount']; - } else { - // subtraction - $this->request['amount'] -= $total['amount']; - } - - $sort_order++; - } - } - - // Add total - BillTotal::create([ - 'company_id' => $this->bill->company_id, - 'bill_id' => $this->bill->id, - 'code' => 'total', - 'name' => 'bills.total', - 'amount' => $this->request['amount'], - 'sort_order' => $sort_order, - ]); - } - - protected function createItems() - { - $sub_total = $discount_amount = $discount_amount_total = 0; - - $taxes = []; - - if (empty($this->request['items'])) { - return [$sub_total, $discount_amount_total, $taxes]; - } - - foreach ((array) $this->request['items'] as $item) { - $item['global_discount'] = 0; - - if (!empty($this->request['discount'])) { - $item['global_discount'] = $this->request['discount']; - } - - $bill_item = $this->dispatch(new CreateBillItem($item, $this->bill)); - - $item_amount = (double) $item['price'] * (double) $item['quantity']; - - $discount_amount = 0; - - if (!empty($item['discount'])) { - $discount_amount = ($item_amount * ($item['discount'] / 100)); - } - - // Calculate totals - $sub_total += $bill_item->total + $discount_amount; - - $discount_amount_total += $discount_amount; - - if (!$bill_item->item_taxes) { - continue; - } - - // Set taxes - foreach ((array) $bill_item->item_taxes as $item_tax) { - if (array_key_exists($item_tax['tax_id'], $taxes)) { - $taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount']; - } else { - $taxes[$item_tax['tax_id']] = [ - 'name' => $item_tax['name'], - 'amount' => $item_tax['amount'] - ]; - } - } - } - - return [$sub_total, $discount_amount_total, $taxes]; - } } diff --git a/app/Jobs/Purchase/CreateBillItem.php b/app/Jobs/Purchase/CreateBillItem.php index 896cad11a..68c49e7b2 100644 --- a/app/Jobs/Purchase/CreateBillItem.php +++ b/app/Jobs/Purchase/CreateBillItem.php @@ -10,20 +10,20 @@ use Illuminate\Support\Str; class CreateBillItem extends Job { - protected $request; - protected $bill; + protected $request; + /** * Create a new job instance. * - * @param $request * @param $bill + * @param $request */ - public function __construct($request, $bill) + public function __construct($bill, $request) { - $this->request = $request; $this->bill = $bill; + $this->request = $request; } /** @@ -34,10 +34,11 @@ class CreateBillItem extends Job public function handle() { $item_id = !empty($this->request['item_id']) ? $this->request['item_id'] : 0; + $precision = config('money.' . $this->bill->currency_code . '.precision'); + $item_amount = (double) $this->request['price'] * (double) $this->request['quantity']; $discount = 0; - $item_discounted_amount = $item_amount; // Apply line discount to amount @@ -110,7 +111,7 @@ class CreateBillItem extends Job $item_base_rate = $item_amount / (1 + collect($inclusives)->sum('rate') / 100); foreach ($inclusives as $inclusive) { - $item_tax_total += $tax_amount = $item_base_rate * ($inclusive->rate / 100); + $tax_amount = $item_base_rate * ($inclusive->rate / 100); $item_taxes[] = [ 'company_id' => $this->bill->company_id, @@ -119,6 +120,8 @@ class CreateBillItem extends Job 'name' => $inclusive->name, 'amount' => $tax_amount, ]; + + $item_tax_total += $tax_amount; } $item_amount = ($item_amount - $item_tax_total) / (1 - $discount / 100); @@ -128,8 +131,6 @@ class CreateBillItem extends Job foreach ($compounds as $compound) { $tax_amount = (($item_discounted_amount + $item_tax_total) / 100) * $compound->rate; - $item_tax_total += $tax_amount; - $item_taxes[] = [ 'company_id' => $this->bill->company_id, 'bill_id' => $this->bill->id, @@ -137,6 +138,8 @@ class CreateBillItem extends Job 'name' => $compound->name, 'amount' => $tax_amount, ]; + + $item_tax_total += $tax_amount; } } } @@ -147,10 +150,10 @@ class CreateBillItem extends Job 'item_id' => $item_id, 'name' => Str::limit($this->request['name'], 180, ''), 'quantity' => (double) $this->request['quantity'], - 'price' => (double) $this->request['price'], - 'tax' => $item_tax_total, + 'price' => round($this->request['price'], $precision), + 'tax' => round($item_tax_total, $precision), 'discount_rate' => !empty($this->request['discount']) ? $this->request['discount'] : 0, - 'total' => $item_amount, + 'total' => round($item_amount, $precision), ]); $bill_item->item_taxes = false; @@ -164,6 +167,7 @@ class CreateBillItem extends Job foreach ($item_taxes as $item_tax) { $item_tax['bill_item_id'] = $bill_item->id; + $item_tax['amount'] = round($item_tax['amount'], $precision); BillItemTax::create($item_tax); } diff --git a/app/Jobs/Purchase/CreateBillItemsAndTotals.php b/app/Jobs/Purchase/CreateBillItemsAndTotals.php new file mode 100644 index 000000000..3335f7376 --- /dev/null +++ b/app/Jobs/Purchase/CreateBillItemsAndTotals.php @@ -0,0 +1,199 @@ +bill = $bill; + $this->request = $this->getRequestInstance($request); + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + $precision = config('money.' . $this->bill->currency_code . '.precision'); + + list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); + + $sort_order = 1; + + // Add sub total + BillTotal::create([ + 'company_id' => $this->bill->company_id, + 'bill_id' => $this->bill->id, + 'code' => 'sub_total', + 'name' => 'bills.sub_total', + 'amount' => round($sub_total, $precision), + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] += $sub_total; + + $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' => round($discount_amount_total, $precision), + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] -= $discount_amount_total; + + $sort_order++; + } + + if (!empty($this->request['discount'])) { + $discount_total = ($sub_total - $discount_amount_total) * ($this->request['discount'] / 100); + + BillTotal::create([ + 'company_id' => $this->bill->company_id, + 'bill_id' => $this->bill->id, + 'code' => 'discount', + 'name' => 'bills.discount', + 'amount' => round($discount_total, $precision), + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] -= $discount_total; + + $sort_order++; + } + + // Add taxes + if (!empty($taxes)) { + foreach ($taxes as $tax) { + BillTotal::create([ + 'company_id' => $this->bill->company_id, + 'bill_id' => $this->bill->id, + 'code' => 'tax', + 'name' => $tax['name'], + 'amount' => round($tax['amount'], $precision), + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] += $tax['amount']; + + $sort_order++; + } + } + + // Add extra totals, i.e. shipping fee + if (!empty($this->request['totals'])) { + foreach ($this->request['totals'] as $total) { + $total['company_id'] = $this->bill->company_id; + $total['bill_id'] = $this->bill->id; + $total['sort_order'] = $sort_order; + + if (empty($total['code'])) { + $total['code'] = 'extra'; + } + + $total['amount'] = round($total['amount'], $precision); + + BillTotal::create($total); + + if (empty($total['operator']) || ($total['operator'] == 'addition')) { + $this->request['amount'] += $total['amount']; + } else { + // subtraction + $this->request['amount'] -= $total['amount']; + } + + $sort_order++; + } + } + + $this->request['amount'] = round($this->request['amount'], $precision); + + // Add total + BillTotal::create([ + 'company_id' => $this->bill->company_id, + 'bill_id' => $this->bill->id, + 'code' => 'total', + 'name' => 'bills.total', + 'amount' => $this->request['amount'], + 'sort_order' => $sort_order, + ]); + } + + protected function createItems() + { + $sub_total = $discount_amount = $discount_amount_total = 0; + + $taxes = []; + + if (empty($this->request['items'])) { + return [$sub_total, $discount_amount_total, $taxes]; + } + + foreach ((array) $this->request['items'] as $item) { + $item['global_discount'] = 0; + + if (!empty($this->request['discount'])) { + $item['global_discount'] = $this->request['discount']; + } + + $bill_item = $this->dispatch(new CreateBillItem($this->bill, $item)); + + $item_amount = (double) $item['price'] * (double) $item['quantity']; + + $discount_amount = 0; + + if (!empty($item['discount'])) { + $discount_amount = ($item_amount * ($item['discount'] / 100)); + } + + // Calculate totals + $sub_total += $bill_item->total + $discount_amount; + + $discount_amount_total += $discount_amount; + + if (!$bill_item->item_taxes) { + continue; + } + + // Set taxes + foreach ((array) $bill_item->item_taxes as $item_tax) { + if (array_key_exists($item_tax['tax_id'], $taxes)) { + $taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount']; + } else { + $taxes[$item_tax['tax_id']] = [ + 'name' => $item_tax['name'], + 'amount' => $item_tax['amount'] + ]; + } + } + } + + return [$sub_total, $discount_amount_total, $taxes]; + } +} diff --git a/app/Jobs/Purchase/UpdateBill.php b/app/Jobs/Purchase/UpdateBill.php index 5d4563ea1..aa016dbfe 100644 --- a/app/Jobs/Purchase/UpdateBill.php +++ b/app/Jobs/Purchase/UpdateBill.php @@ -5,15 +5,13 @@ namespace App\Jobs\Purchase; use App\Abstracts\Job; use App\Events\Purchase\BillUpdated; use App\Events\Purchase\BillUpdating; +use App\Jobs\Purchase\CreateBillItemsAndTotals; use App\Models\Purchase\Bill; -use App\Models\Purchase\BillTotal; -use App\Traits\Currencies; -use App\Traits\DateTime; use App\Traits\Relationships; class UpdateBill extends Job { - use Currencies, DateTime, Relationships; + use Relationships; protected $bill; @@ -51,7 +49,9 @@ class UpdateBill extends Job $this->bill->attachMedia($media, 'attachment'); } - $this->createItemsAndTotals(); + $this->deleteRelationships($this->bill, ['items', 'item_taxes', 'totals']); + + $this->dispatch(new CreateBillItemsAndTotals($this->bill, $this->request)); $bill_paid = $this->bill->paid; @@ -70,169 +70,4 @@ class UpdateBill extends Job return $this->bill; } - - protected function createItemsAndTotals() - { - // Create items - list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); - - // Delete current totals - $this->deleteRelationships($this->bill, 'totals'); - - $sort_order = 1; - - // Add sub total - BillTotal::create([ - 'company_id' => $this->bill->company_id, - 'bill_id' => $this->bill->id, - 'code' => 'sub_total', - 'name' => 'bills.sub_total', - 'amount' => $sub_total, - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] += $sub_total; - - $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 - $discount_amount_total) * ($this->request['discount'] / 100); - - BillTotal::create([ - 'company_id' => $this->bill->company_id, - 'bill_id' => $this->bill->id, - 'code' => 'discount', - 'name' => 'bills.discount', - 'amount' => $discount_total, - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] -= $discount_total; - - $sort_order++; - } - - // Add taxes - if (!empty($taxes)) { - foreach ($taxes as $tax) { - BillTotal::create([ - 'company_id' => $this->bill->company_id, - 'bill_id' => $this->bill->id, - 'code' => 'tax', - 'name' => $tax['name'], - 'amount' => $tax['amount'], - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] += $tax['amount']; - - $sort_order++; - } - } - - // Add extra totals, i.e. shipping fee - if (!empty($this->request['totals'])) { - foreach ($this->request['totals'] as $total) { - $total['company_id'] = $this->bill->company_id; - $total['bill_id'] = $this->bill->id; - $total['sort_order'] = $sort_order; - - if (empty($total['code'])) { - $total['code'] = 'extra'; - } - - BillTotal::create($total); - - if (empty($total['operator']) || ($total['operator'] == 'addition')) { - $this->request['amount'] += $total['amount']; - } else { - // subtraction - $this->request['amount'] -= $total['amount']; - } - - $sort_order++; - } - } - - // Add total - BillTotal::create([ - 'company_id' => $this->bill->company_id, - 'bill_id' => $this->bill->id, - 'code' => 'total', - 'name' => 'bills.total', - 'amount' => $this->request['amount'], - 'sort_order' => $sort_order, - ]); - } - - protected function createItems() - { - $sub_total = $discount_amount = $discount_amount_total = 0; - - $taxes = []; - - if (empty($this->request['items'])) { - return [$sub_total, $discount_amount_total, $taxes]; - } - - // Delete current items - $this->deleteRelationships($this->bill, ['items', 'item_taxes']); - - foreach ((array) $this->request['items'] as $item) { - $item['global_discount'] = 0; - - if (!empty($this->request['discount'])) { - $item['global_discount'] = $this->request['discount']; - } - - $bill_item = $this->dispatch(new CreateBillItem($item, $this->bill)); - - $item_amount = (double) $item['price'] * (double) $item['quantity']; - - $discount_amount = 0; - - if (!empty($item['discount'])) { - $discount_amount = ($item_amount * ($item['discount'] / 100)); - } - - // Calculate totals - $sub_total += $bill_item->total + $discount_amount; - - $discount_amount_total += $discount_amount; - - if (!$bill_item->item_taxes) { - continue; - } - - // Set taxes - foreach ((array) $bill_item->item_taxes as $item_tax) { - if (array_key_exists($item_tax['tax_id'], $taxes)) { - $taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount']; - } else { - $taxes[$item_tax['tax_id']] = [ - 'name' => $item_tax['name'], - 'amount' => $item_tax['amount'] - ]; - } - } - } - - return [$sub_total, $discount_amount_total, $taxes]; - } } diff --git a/app/Jobs/Sale/CreateInvoice.php b/app/Jobs/Sale/CreateInvoice.php index 2bf832e9f..0f61a222a 100644 --- a/app/Jobs/Sale/CreateInvoice.php +++ b/app/Jobs/Sale/CreateInvoice.php @@ -5,15 +5,11 @@ namespace App\Jobs\Sale; use App\Abstracts\Job; use App\Events\Sale\InvoiceCreated; use App\Events\Sale\InvoiceCreating; +use App\Jobs\Sale\CreateInvoiceItemsAndTotals; use App\Models\Sale\Invoice; -use App\Models\Sale\InvoiceTotal; -use App\Traits\Currencies; -use App\Traits\DateTime; class CreateInvoice extends Job { - use Currencies, DateTime; - protected $invoice; protected $request; @@ -51,7 +47,7 @@ class CreateInvoice extends Job $this->invoice->attachMedia($media, 'attachment'); } - $this->createItemsAndTotals(); + $this->dispatch(new CreateInvoiceItemsAndTotals($this->invoice, $this->request)); $this->invoice->update($this->request->all()); @@ -62,163 +58,4 @@ class CreateInvoice extends Job return $this->invoice; } - - protected function createItemsAndTotals() - { - // Create items - list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); - - $sort_order = 1; - - // Add sub total - InvoiceTotal::create([ - 'company_id' => $this->invoice->company_id, - 'invoice_id' => $this->invoice->id, - 'code' => 'sub_total', - 'name' => 'invoices.sub_total', - 'amount' => $sub_total, - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] += $sub_total; - - $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 - $discount_amount_total) * ($this->request['discount'] / 100); - - InvoiceTotal::create([ - 'company_id' => $this->invoice->company_id, - 'invoice_id' => $this->invoice->id, - 'code' => 'discount', - 'name' => 'invoices.discount', - 'amount' => $discount_total, - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] -= $discount_total; - - $sort_order++; - } - - // Add taxes - if (!empty($taxes)) { - foreach ($taxes as $tax) { - InvoiceTotal::create([ - 'company_id' => $this->invoice->company_id, - 'invoice_id' => $this->invoice->id, - 'code' => 'tax', - 'name' => $tax['name'], - 'amount' => $tax['amount'], - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] += $tax['amount']; - - $sort_order++; - } - } - - // Add extra totals, i.e. shipping fee - if (!empty($this->request['totals'])) { - foreach ($this->request['totals'] as $total) { - $total['company_id'] = $this->invoice->company_id; - $total['invoice_id'] = $this->invoice->id; - $total['sort_order'] = $sort_order; - - if (empty($total['code'])) { - $total['code'] = 'extra'; - } - - InvoiceTotal::create($total); - - if (empty($total['operator']) || ($total['operator'] == 'addition')) { - $this->request['amount'] += $total['amount']; - } else { - // subtraction - $this->request['amount'] -= $total['amount']; - } - - $sort_order++; - } - } - - // Add total - InvoiceTotal::create([ - 'company_id' => $this->invoice->company_id, - 'invoice_id' => $this->invoice->id, - 'code' => 'total', - 'name' => 'invoices.total', - 'amount' => $this->request['amount'], - 'sort_order' => $sort_order, - ]); - } - - protected function createItems() - { - $sub_total = $discount_amount = $discount_amount_total = 0; - - $taxes = []; - - if (empty($this->request['items'])) { - return [$sub_total, $discount_amount_total, $taxes]; - } - - foreach ((array) $this->request['items'] as $item) { - $item['global_discount'] = 0; - - if (!empty($this->request['discount'])) { - $item['global_discount'] = $this->request['discount']; - } - - $invoice_item = $this->dispatch(new CreateInvoiceItem($item, $this->invoice)); - - $item_amount = (double) $item['price'] * (double) $item['quantity']; - - $discount_amount = 0; - - if (!empty($item['discount'])) { - $discount_amount = ($item_amount * ($item['discount'] / 100)); - } - - // Calculate totals - $sub_total += $invoice_item->total + $discount_amount; - - $discount_amount_total += $discount_amount; - - if (!$invoice_item->item_taxes) { - continue; - } - - // Set taxes - foreach ((array) $invoice_item->item_taxes as $item_tax) { - if (array_key_exists($item_tax['tax_id'], $taxes)) { - $taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount']; - } else { - $taxes[$item_tax['tax_id']] = [ - 'name' => $item_tax['name'], - 'amount' => $item_tax['amount'] - ]; - } - } - } - - return [$sub_total, $discount_amount_total, $taxes]; - } } diff --git a/app/Jobs/Sale/CreateInvoiceItem.php b/app/Jobs/Sale/CreateInvoiceItem.php index 8636df4d7..3fd032b20 100644 --- a/app/Jobs/Sale/CreateInvoiceItem.php +++ b/app/Jobs/Sale/CreateInvoiceItem.php @@ -10,20 +10,20 @@ use Illuminate\Support\Str; class CreateInvoiceItem extends Job { - protected $request; - protected $invoice; + protected $request; + /** * Create a new job instance. * - * @param $request * @param $invoice + * @param $request */ - public function __construct($request, $invoice) + public function __construct($invoice, $request) { - $this->request = $request; $this->invoice = $invoice; + $this->request = $request; } /** @@ -34,10 +34,11 @@ class CreateInvoiceItem extends Job public function handle() { $item_id = !empty($this->request['item_id']) ? $this->request['item_id'] : 0; + $precision = config('money.' . $this->invoice->currency_code . '.precision'); + $item_amount = (double) $this->request['price'] * (double) $this->request['quantity']; $discount = 0; - $item_discounted_amount = $item_amount; // Apply line discount to amount @@ -110,7 +111,7 @@ class CreateInvoiceItem extends Job $item_base_rate = $item_amount / (1 + collect($inclusives)->sum('rate') / 100); foreach ($inclusives as $inclusive) { - $item_tax_total += $tax_amount = $item_base_rate * ($inclusive->rate / 100); + $tax_amount = $item_base_rate * ($inclusive->rate / 100); $item_taxes[] = [ 'company_id' => $this->invoice->company_id, @@ -119,6 +120,8 @@ class CreateInvoiceItem extends Job 'name' => $inclusive->name, 'amount' => $tax_amount, ]; + + $item_tax_total += $tax_amount; } $item_amount = ($item_amount - $item_tax_total) / (1 - $discount / 100); @@ -128,8 +131,6 @@ class CreateInvoiceItem extends Job foreach ($compounds as $compound) { $tax_amount = (($item_discounted_amount + $item_tax_total) / 100) * $compound->rate; - $item_tax_total += $tax_amount; - $item_taxes[] = [ 'company_id' => $this->invoice->company_id, 'invoice_id' => $this->invoice->id, @@ -137,6 +138,8 @@ class CreateInvoiceItem extends Job 'name' => $compound->name, 'amount' => $tax_amount, ]; + + $item_tax_total += $tax_amount; } } } @@ -147,10 +150,10 @@ class CreateInvoiceItem extends Job 'item_id' => $item_id, 'name' => Str::limit($this->request['name'], 180, ''), 'quantity' => (double) $this->request['quantity'], - 'price' => (double) $this->request['price'], - 'tax' => $item_tax_total, + 'price' => round($this->request['price'], $precision), + 'tax' => round($item_tax_total, $precision), 'discount_rate' => !empty($this->request['discount']) ? $this->request['discount'] : 0, - 'total' => $item_amount, + 'total' => round($item_amount, $precision), ]); $invoice_item->item_taxes = false; @@ -164,6 +167,7 @@ class CreateInvoiceItem extends Job foreach ($item_taxes as $item_tax) { $item_tax['invoice_item_id'] = $invoice_item->id; + $item_tax['amount'] = round($item_tax['amount'], $precision); InvoiceItemTax::create($item_tax); } diff --git a/app/Jobs/Sale/CreateInvoiceItemsAndTotals.php b/app/Jobs/Sale/CreateInvoiceItemsAndTotals.php new file mode 100644 index 000000000..a9a42063e --- /dev/null +++ b/app/Jobs/Sale/CreateInvoiceItemsAndTotals.php @@ -0,0 +1,198 @@ +invoice = $invoice; + $this->request = $this->getRequestInstance($request); + } + + /** + * Execute the job. + * + * @return voide + */ + public function handle() + { + $precision = config('money.' . $this->invoice->currency_code . '.precision'); + + list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); + + $sort_order = 1; + + // Add sub total + InvoiceTotal::create([ + 'company_id' => $this->invoice->company_id, + 'invoice_id' => $this->invoice->id, + 'code' => 'sub_total', + 'name' => 'invoices.sub_total', + 'amount' => round($sub_total, $precision), + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] += $sub_total; + + $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' => round($discount_amount_total, $precision), + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] -= $discount_amount_total; + + $sort_order++; + } + + if (!empty($this->request['discount'])) { + $discount_total = ($sub_total - $discount_amount_total) * ($this->request['discount'] / 100); + + InvoiceTotal::create([ + 'company_id' => $this->invoice->company_id, + 'invoice_id' => $this->invoice->id, + 'code' => 'discount', + 'name' => 'invoices.discount', + 'amount' => round($discount_total, $precision), + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] -= $discount_total; + + $sort_order++; + } + + // Add taxes + if (!empty($taxes)) { + foreach ($taxes as $tax) { + InvoiceTotal::create([ + 'company_id' => $this->invoice->company_id, + 'invoice_id' => $this->invoice->id, + 'code' => 'tax', + 'name' => $tax['name'], + 'amount' => round($tax['amount'], $precision), + 'sort_order' => $sort_order, + ]); + + $this->request['amount'] += $tax['amount']; + + $sort_order++; + } + } + + // Add extra totals, i.e. shipping fee + if (!empty($this->request['totals'])) { + foreach ($this->request['totals'] as $total) { + $total['company_id'] = $this->invoice->company_id; + $total['invoice_id'] = $this->invoice->id; + $total['sort_order'] = $sort_order; + + if (empty($total['code'])) { + $total['code'] = 'extra'; + } + + $total['amount'] = round($total['amount'], $precision); + + InvoiceTotal::create($total); + + if (empty($total['operator']) || ($total['operator'] == 'addition')) { + $this->request['amount'] += $total['amount']; + } else { + // subtraction + $this->request['amount'] -= $total['amount']; + } + + $sort_order++; + } + } + + $this->request['amount'] = round($this->request['amount'], $precision); + + // Add total + InvoiceTotal::create([ + 'company_id' => $this->invoice->company_id, + 'invoice_id' => $this->invoice->id, + 'code' => 'total', + 'name' => 'invoices.total', + 'amount' => $this->request['amount'], + 'sort_order' => $sort_order, + ]); + } + + protected function createItems() + { + $sub_total = $discount_amount = $discount_amount_total = 0; + + $taxes = []; + + if (empty($this->request['items'])) { + return [$sub_total, $discount_amount_total, $taxes]; + } + + foreach ((array) $this->request['items'] as $item) { + $item['global_discount'] = 0; + + if (!empty($this->request['discount'])) { + $item['global_discount'] = $this->request['discount']; + } + + $invoice_item = $this->dispatch(new CreateInvoiceItem($this->invoice, $item)); + + $item_amount = (double) $item['price'] * (double) $item['quantity']; + + $discount_amount = 0; + + if (!empty($item['discount'])) { + $discount_amount = ($item_amount * ($item['discount'] / 100)); + } + + // Calculate totals + $sub_total += $invoice_item->total + $discount_amount; + + $discount_amount_total += $discount_amount; + + if (!$invoice_item->item_taxes) { + continue; + } + + // Set taxes + foreach ((array) $invoice_item->item_taxes as $item_tax) { + if (array_key_exists($item_tax['tax_id'], $taxes)) { + $taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount']; + } else { + $taxes[$item_tax['tax_id']] = [ + 'name' => $item_tax['name'], + 'amount' => $item_tax['amount'], + ]; + } + } + } + + return [$sub_total, $discount_amount_total, $taxes]; + } +} diff --git a/app/Jobs/Sale/UpdateInvoice.php b/app/Jobs/Sale/UpdateInvoice.php index 34f147fd6..bb41989bb 100644 --- a/app/Jobs/Sale/UpdateInvoice.php +++ b/app/Jobs/Sale/UpdateInvoice.php @@ -5,15 +5,13 @@ namespace App\Jobs\Sale; use App\Abstracts\Job; use App\Events\Sale\InvoiceUpdated; use App\Events\Sale\InvoiceUpdating; +use App\Jobs\Sale\CreateInvoiceItemsAndTotals; use App\Models\Sale\Invoice; -use App\Models\Sale\InvoiceTotal; -use App\Traits\Currencies; -use App\Traits\DateTime; use App\Traits\Relationships; class UpdateInvoice extends Job { - use Currencies, DateTime, Relationships; + use Relationships; protected $invoice; @@ -51,7 +49,9 @@ class UpdateInvoice extends Job $this->invoice->attachMedia($media, 'attachment'); } - $this->createItemsAndTotals(); + $this->deleteRelationships($this->invoice, ['items', 'item_taxes', 'totals']); + + $this->dispatch(new CreateInvoiceItemsAndTotals($this->invoice, $this->request)); $invoice_paid = $this->invoice->paid; @@ -70,169 +70,4 @@ class UpdateInvoice extends Job return $this->invoice; } - - protected function createItemsAndTotals() - { - // Create items - list($sub_total, $discount_amount_total, $taxes) = $this->createItems(); - - // Delete current totals - $this->deleteRelationships($this->invoice, 'totals'); - - $sort_order = 1; - - // Add sub total - InvoiceTotal::create([ - 'company_id' => $this->invoice->company_id, - 'invoice_id' => $this->invoice->id, - 'code' => 'sub_total', - 'name' => 'invoices.sub_total', - 'amount' => $sub_total, - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] += $sub_total; - - $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 - $discount_amount_total) * ($this->request['discount'] / 100); - - InvoiceTotal::create([ - 'company_id' => $this->invoice->company_id, - 'invoice_id' => $this->invoice->id, - 'code' => 'discount', - 'name' => 'invoices.discount', - 'amount' => $discount_total, - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] -= $discount_total; - - $sort_order++; - } - - // Add taxes - if (!empty($taxes)) { - foreach ($taxes as $tax) { - InvoiceTotal::create([ - 'company_id' => $this->invoice->company_id, - 'invoice_id' => $this->invoice->id, - 'code' => 'tax', - 'name' => $tax['name'], - 'amount' => $tax['amount'], - 'sort_order' => $sort_order, - ]); - - $this->request['amount'] += $tax['amount']; - - $sort_order++; - } - } - - // Add extra totals, i.e. shipping fee - if (!empty($this->request['totals'])) { - foreach ($this->request['totals'] as $total) { - $total['company_id'] = $this->invoice->company_id; - $total['invoice_id'] = $this->invoice->id; - $total['sort_order'] = $sort_order; - - if (empty($total['code'])) { - $total['code'] = 'extra'; - } - - InvoiceTotal::create($total); - - if (empty($total['operator']) || ($total['operator'] == 'addition')) { - $this->request['amount'] += $total['amount']; - } else { - // subtraction - $this->request['amount'] -= $total['amount']; - } - - $sort_order++; - } - } - - // Add total - InvoiceTotal::create([ - 'company_id' => $this->invoice->company_id, - 'invoice_id' => $this->invoice->id, - 'code' => 'total', - 'name' => 'invoices.total', - 'amount' => $this->request['amount'], - 'sort_order' => $sort_order, - ]); - } - - protected function createItems() - { - $sub_total = $discount_amount = $discount_amount_total = 0; - - $taxes = []; - - if (empty($this->request['items'])) { - return [$sub_total, $discount_amount_total, $taxes]; - } - - // Delete current items - $this->deleteRelationships($this->invoice, ['items', 'item_taxes']); - - foreach ((array) $this->request['items'] as $item) { - $item['global_discount'] = 0; - - if (!empty($this->request['discount'])) { - $item['global_discount'] = $this->request['discount']; - } - - $invoice_item = $this->dispatch(new CreateInvoiceItem($item, $this->invoice)); - - $item_amount = (double) $item['price'] * (double) $item['quantity']; - - $discount_amount = 0; - - if (!empty($item['discount'])) { - $discount_amount = ($item_amount * ($item['discount'] / 100)); - } - - // Calculate totals - $sub_total += $invoice_item->total + $discount_amount; - - $discount_amount_total += $discount_amount; - - if (!$invoice_item->item_taxes) { - continue; - } - - // Set taxes - foreach ((array) $invoice_item->item_taxes as $item_tax) { - if (array_key_exists($item_tax['tax_id'], $taxes)) { - $taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount']; - } else { - $taxes[$item_tax['tax_id']] = [ - 'name' => $item_tax['name'], - 'amount' => $item_tax['amount'] - ]; - } - } - } - - return [$sub_total, $discount_amount_total, $taxes]; - } } diff --git a/app/Models/Banking/Transaction.php b/app/Models/Banking/Transaction.php index a949878d4..7680e291c 100644 --- a/app/Models/Banking/Transaction.php +++ b/app/Models/Banking/Transaction.php @@ -250,41 +250,16 @@ class Transaction extends Model * * @return float */ - public function getPriceAttribute() + public function getAmountForAccountAttribute() { - static $currencies; - $amount = $this->amount; // Convert amount if not same currency if ($this->account->currency_code != $this->currency_code) { - if (empty($currencies)) { - $currencies = Currency::enabled()->pluck('rate', 'code')->toArray(); - } + $to_code = $this->account->currency_code; + $to_rate = config('money.' . $this->account->currency_code . '.rate'); - $default_currency = setting('default.currency', 'USD'); - - $default_amount = $this->amount; - - if ($default_currency != $this->currency_code) { - $default_amount_model = new Transaction(); - - $default_amount_model->default_currency_code = $default_currency; - $default_amount_model->amount = $this->amount; - $default_amount_model->currency_code = $this->currency_code; - $default_amount_model->currency_rate = $this->currency_rate; - - $default_amount = $default_amount_model->getAmountConvertedToDefault(); - } - - $transfer_amount = new Transaction(); - - $transfer_amount->default_currency_code = $this->currency_code; - $transfer_amount->amount = $default_amount; - $transfer_amount->currency_code = $this->account->currency_code; - $transfer_amount->currency_rate = $currencies[$this->account->currency_code]; - - $amount = $transfer_amount->getAmountConvertedFromDefault(); + $amount = $this->convertBetween($amount, $this->currency_code, $this->currency_rate, $to_code, $to_rate); } return $amount; diff --git a/app/Traits/Currencies.php b/app/Traits/Currencies.php index a3ea390e0..7fda86161 100644 --- a/app/Traits/Currencies.php +++ b/app/Traits/Currencies.php @@ -29,14 +29,31 @@ trait Currencies return $format ? $money->format() : $money->getAmount(); } - public function convertToDefault($amount, $from, $rate, $format = false) + public function convertToDefault($amount, $from, $rate, $format = false, $default = null) { - return $this->convert('divide', $amount, $from, $this->getDefaultCurrency(), $rate, $format); + $default_currency = $default ?? $this->getDefaultCurrency(); + + return $this->convert('divide', $amount, $from, $default_currency, $rate, $format); } - public function convertFromDefault($amount, $to, $rate, $format = false) + public function convertFromDefault($amount, $to, $rate, $format = false, $default = null) { - return $this->convert('multiply', $amount, $this->getDefaultCurrency(), $to, $rate, $format); + $default_currency = $default ?? $this->getDefaultCurrency(); + + return $this->convert('multiply', $amount, $default_currency, $to, $rate, $format); + } + + public function convertBetween($amount, $from_code, $from_rate, $to_code, $to_rate) + { + $default_amount = $amount; + + if ($from_code != setting('default.currency')) { + $default_amount = $this->convertToDefault($amount, $from_code, $from_rate); + } + + $converted_amount = $this->convertFromDefault($default_amount, $to_code, $to_rate, false, $from_code); + + return $converted_amount; } public function getAmountConvertedToDefault($format = false, $with_tax = true) @@ -58,4 +75,14 @@ trait Currencies { return !empty($this->default_currency_code) ? $this->default_currency_code : setting('default.currency', 'USD'); } + + public function setDefaultCurrency($code) + { + $this->default_currency_code = $code; + } + + public function unsetDefaultCurrency() + { + unset($this->default_currency_code); + } } diff --git a/app/Utilities/Overrider.php b/app/Utilities/Overrider.php index f0e6255e1..ef1fb8ec7 100644 --- a/app/Utilities/Overrider.php +++ b/app/Utilities/Overrider.php @@ -64,10 +64,8 @@ class Overrider $currencies = Currency::all(); foreach ($currencies as $currency) { - if (!isset($currency->precision)) { - continue; - } - + config(['money.' . $currency->code . '.name' => $currency->name]); + config(['money.' . $currency->code . '.rate' => $currency->rate]); config(['money.' . $currency->code . '.precision' => $currency->precision]); config(['money.' . $currency->code . '.symbol' => $currency->symbol]); config(['money.' . $currency->code . '.symbol_first' => $currency->symbol_first]); diff --git a/app/Widgets/CashFlow.php b/app/Widgets/CashFlow.php index fbc9b5ece..56b2639c4 100644 --- a/app/Widgets/CashFlow.php +++ b/app/Widgets/CashFlow.php @@ -160,6 +160,12 @@ class CashFlow extends Widget $totals[$i] += $item->getAmountConvertedToDefault(); } + + $precision = config('money.' . setting('default.currency') . '.precision'); + + foreach ($totals as $key => $value) { + $totals[$key] = round($value, $precision); + } } private function calculateProfit($incomes, $expenses) diff --git a/composer.json b/composer.json index f513a3bf0..80228c163 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "akaunting/language": "1.0.*", "akaunting/menu": "1.0.*", "akaunting/module": "1.0.*", - "akaunting/money": "1.1.*", + "akaunting/money": "1.2.*", "akaunting/setting": "1.1.*", "akaunting/version": "1.0.*", "barryvdh/laravel-debugbar": "3.3.*", diff --git a/composer.lock b/composer.lock index 82bf68891..d0e213afc 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f074eda231edc547ca4e5484b5b5132f", + "content-hash": "c44aedb0ed90d8deff47a73d86074257", "packages": [ { "name": "akaunting/firewall", @@ -262,16 +262,16 @@ }, { "name": "akaunting/money", - "version": "1.1.1", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/akaunting/money.git", - "reference": "1bab074aa71ed994eff140b26fb6ce9aecf82430" + "reference": "75f6d0d036cd1ca82c2926cfae5a7c2759445cfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/akaunting/money/zipball/1bab074aa71ed994eff140b26fb6ce9aecf82430", - "reference": "1bab074aa71ed994eff140b26fb6ce9aecf82430", + "url": "https://api.github.com/repos/akaunting/money/zipball/75f6d0d036cd1ca82c2926cfae5a7c2759445cfb", + "reference": "75f6d0d036cd1ca82c2926cfae5a7c2759445cfb", "shasum": "" }, "require": { @@ -319,7 +319,7 @@ "laravel", "money" ], - "time": "2020-03-09T15:01:03+00:00" + "time": "2020-07-06T06:21:54+00:00" }, { "name": "akaunting/setting", @@ -5390,16 +5390,16 @@ }, { "name": "nesbot/carbon", - "version": "2.36.0", + "version": "2.36.1", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "d0b65958d9942fd1b501fdb0800c67e8323aa08d" + "reference": "ee7378a36cc62952100e718bcc58be4c7210e55f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d0b65958d9942fd1b501fdb0800c67e8323aa08d", - "reference": "d0b65958d9942fd1b501fdb0800c67e8323aa08d", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/ee7378a36cc62952100e718bcc58be4c7210e55f", + "reference": "ee7378a36cc62952100e718bcc58be4c7210e55f", "shasum": "" }, "require": { @@ -5475,7 +5475,7 @@ "type": "tidelift" } ], - "time": "2020-06-25T20:20:01+00:00" + "time": "2020-07-04T12:29:56+00:00" }, { "name": "nikic/php-parser", diff --git a/resources/views/banking/reconciliations/create.blade.php b/resources/views/banking/reconciliations/create.blade.php index 4bed571c3..a26a76c54 100644 --- a/resources/views/banking/reconciliations/create.blade.php +++ b/resources/views/banking/reconciliations/create.blade.php @@ -83,7 +83,7 @@ @endif
- {{ Form::checkbox($item->type . '_' . $item->id, $item->price, $item->reconciled, [ + {{ Form::checkbox($item->type . '_' . $item->id, $item->amount_for_account, $item->reconciled, [ 'data-field' => 'transactions', 'v-model' => 'form.transactions.' . $item->type . '_' . $item->id, 'id' => 'transaction-' . $item->id . '-'. $item->type,