diff --git a/app/Helpers/Invoice/Discounter.php b/app/Helpers/Invoice/Discounter.php index a0aa833603f4..792b20f192f2 100644 --- a/app/Helpers/Invoice/Discounter.php +++ b/app/Helpers/Invoice/Discounter.php @@ -29,9 +29,5 @@ trait Discounter } - // public function pro_rata_discount($amount) - // { - // return round(($this->invoice->discount/$this->getSubTotal() * $amount),2); - // } } diff --git a/app/Helpers/Invoice/InvoiceCalc.php b/app/Helpers/Invoice/InvoiceCalc.php deleted file mode 100644 index 939fa328c29c..000000000000 --- a/app/Helpers/Invoice/InvoiceCalc.php +++ /dev/null @@ -1,436 +0,0 @@ -invoice = $invoice; - - $this->settings = $settings; - - $this->tax_map = new Collection; - - } - - /** - * Builds the invoice values - */ - public function build() - { - - $this->calcLineItems() - ->calcDiscount() - ->calcCustomValues() - ->calcBalance() - ->calcPartial(); - - return $this; - } - - - /** - * Calculates the partial balance. - * - * @return self The partial. - */ - private function calcPartial() - { - if ( !isset($this->invoice->id) && isset($this->invoice->partial) ) { - $this->invoice->partial = max(0, min($this->formatValue($this->invoice->partial, 2), $this->invoice->balance)); - } - - return $this; - } - - - /** - * Calculates the discount. - * - * @return self The discount. - */ - private function calcDiscount() - { - - $this->setTotalDiscount($this->discount($this->getSubTotal(), $this->invoice->discount, $this->invoice->is_amount_discount)); - - $this->setTotal( $this->getTotal() - $this->getTotalDiscount() ); - - /* Reduce all taxes */ - - return $this; - } - - - /** - * Calculates the balance. - * - * @return self The balance. - */ - private function calcBalance() - { - - if(isset($this->invoice->id) && $this->invoice->id >= 1) - { - $this->balance = round($this->getTotal() - ($this->invoice->amount - $this->invoice->balance), 2); - } else { - $this->balance = $this->getTotal(); - } - - return $this; - - } - - - /** - * Calculates the custom values. - * - * @return self The custom values. - */ - private function calcCustomValues() - { - - // custom fields charged taxes - if (isset($this->invoice->custom_value1) && property_exists($this->settings, 'custom_invoice_taxes1') && $this->settings->custom_invoice_taxes1 === true ) { - $this->setTotal($this->getTotal() + $this->invoice->custom_value1); - } - if (isset($this->invoice->custom_value2) && property_exists($this->settings, 'custom_invoice_taxes1') && $this->settings->custom_invoice_taxes2 === true) { - $this->setTotal($this->getTotal() + $this->invoice->custom_value2); - } - - $this->calcTaxes(); - - // custom fields not charged taxes - if (isset($this->invoice->custom_value1) && property_exists($this->settings, 'custom_invoice_taxes1') && $this->settings->custom_invoice_taxes1 !== true) { - $this->setTotal($this->getTotal() + $this->invoice->custom_value1); - } - - if (isset($this->invoice->custom_value2) && property_exists($this->settings, 'custom_invoice_taxes1') && $this->settings->custom_invoice_taxes2 !== true) { - $this->setTotal($this->getTotal() + $this->invoice->custom_value2); - } - - - return $this; - } - - /** - * Calculates the Invoice Level taxes. - */ - private function calcTaxes() - { - - if (property_exists($this->settings, 'inclusive_taxes') && ! $this->settings->inclusive_taxes) { - - $taxAmount1 = round($this->getSubTotal() * (($this->invoice->tax_rate1 ? $this->invoice->tax_rate1 : 0) / 100), 2); - $taxAmount1 -= $this->discount($taxAmount1, $this->invoice->discount, $this->invoice->is_amount_discount); - - $tmp_array = []; - - if($taxAmount1 > 0) - $tmp_array[] = ['name' => $this->invoice->tax_name1 . ' ' . $this->invoice->tax_rate1.'%', 'total' => $taxAmount1]; - - $taxAmount2 = round($this->getSubTotal() * (($this->invoice->tax_rate2 ? $this->invoice->tax_rate2 : 0) / 100), 2); - $taxAmount2 -= $this->discount($taxAmount2, $this->invoice->discount, $this->invoice->is_amount_discount); - - if($taxAmount2 > 0) - $tmp_array[] = ['name' => $this->invoice->tax_name2 . ' ' . $this->invoice->tax_rate2.'%', 'total' => $taxAmount2]; - - $taxAmount3 = round($this->getSubTotal() * (($this->invoice->tax_rate3 ? $this->invoice->tax_rate3 : 0) / 100), 2); - $taxAmount3 -= $this->discount($taxAmount3, $this->invoice->discount, $this->invoice->is_amount_discount); - - if($taxAmount3 > 0) - $tmp_array[] = ['name' => $this->invoice->tax_name3 . ' ' . $this->invoice->tax_rate3.'%', 'total' => $taxAmount3]; - - - $this->setTotalTaxMap($tmp_array); - - $this->setItemTotalTaxes($this->getItemTotalTaxes() + $taxAmount1 + $taxAmount2 + $taxAmount3); - - $this->setTotal($this->getTotal() + $this->getItemTotalTaxes()); - } - - return $this; - } - - /** - * Calculates the line items. - * - * @return self The line items. - */ - private function calcLineItems() - { - //if(!$this->invoice->line_items || !property_exists($this->invoice, 'line_items') || count($this->invoice->line_items) == 0) - if(!$this->invoice->line_items || count($this->invoice->line_items) == 0) - return $this; - - $new_line_items = []; - - foreach($this->invoice->line_items as $item) { - - $item_calc = new InvoiceItemCalc($item, $this->settings, $this->invoice); - $item_calc->process(); - - $new_line_items[] = $item_calc->getLineItem(); - - //set collection of itemised taxes - $this->tax_map->push($item_calc->getGroupedTaxes()); - - //set running total of taxes - $this->total_item_taxes += $item_calc->getTotalTaxes(); - - $this->setItemTotalTaxes($this->getItemTotalTaxes() + ($item_calc->getTotalTaxes() - $this->discount($item_calc->getTotalTaxes(), $this->invoice->discount, $this->invoice->is_amount_discount))); - - //set running total of item discounts - $this->item_discount += $item_calc->getTotalDiscounts(); - - //set running subtotal - $this->setSubTotal($this->getSubTotal() + $item_calc->getLineTotal()); - - $this->setTotal($this->getTotal() + $item_calc->getLineTotal()); - - } - - $this->invoice->line_items = $new_line_items; - - return $this; - } - - - /** - * Getters and Setters - */ - - public function getSubTotal() - { - return $this->sub_total; - } - - public function setSubTotal($value) - { - $this->sub_total = $value; - - return $this; - } - - public function getTotalTaxMap() - { - return $this->total_tax_map; - } - - public function setTotalTaxMap($value) - { - $this->total_tax_map = $value; - - return $this; - } - - /** - * Sums and reduces the line item taxes - * - * @return array The array of tax names and tax totals - */ - public function getTaxMap() - { - - $keys = $this->tax_map->collapse()->pluck('key')->unique(); - - $values = $this->tax_map->collapse(); - - $tax_array = []; - - foreach($keys as $key) - { - - $tax_name = $values->filter(function ($value, $k) use($key){ - return $value['key'] == $key; - })->pluck('tax_name')->first(); - - $total_line_tax = $values->filter(function ($value, $k) use($key){ - return $value['key'] == $key; - })->sum('total'); - - $tax_array[] = ['name' => $tax_name, 'total' => $total_line_tax]; - - } - - return $tax_array; - - - } - - private function adjustTaxesWithDiscount($line_taxes) - { - return $line_taxes->transform(function($line_tax){ - - return $line_tax['total'] -= $this->discount($line_tax['total'], $this->invoice->discount, $this->invoice->is_amount_discount); - }); - } - - public function setTaxMap($value) - { - $htis->tax_map = $value; - - return $this; - } - - public function getTotalDiscount() - { - return $this->total_discount; - } - - public function setTotalDiscount($value) - { - $this->total_discount = $value; - - return $this; - } - - public function getItemTotalTaxes() - { - return $this->total_taxes; - } - - public function setItemTotalTaxes($value) - { - $this->total_taxes = $value; - - return $this; - } - - public function getTotalLineTaxes() - { - - } - - public function getTotal() - { - return $this->total; - } - - public function setTotal($value) - { - - $this->total = $value; - - return $this; - } - - public function getBalance() - { - return $this->balance; - } - - public function setBalance($value) - { - $this->balance = $value; - - return $this; - } - - public function getInvoice() - { - //Build invoice values here and return Invoice - $this->setCalculatedAttributes(); - - return $this->invoice; - } - - - /** - * Build $this->invoice variables after - * calculations have been performed. - */ - private function setCalculatedAttributes() - { - /* If amount != balance then some money has been paid on the invoice, need to subtract this difference from the total to set the new balance */ - if($this->invoice->amount != $this->invoice->balance) - { - $paid_to_date = $this->invoice->amount - $this->invoice->balance; - - $this->invoice->balance = $this->getTotal() - $paid_to_date; - } - else - $this->invoice->balance = $this->getTotal(); - - /* Set new calculated total */ - $this->invoice->amount = $this->getTotal(); - - } - -/* - private function setDiscount($amount, $discount, $is_amount_discount) - { - - if($is_amount_discount) - return $amount - $this->formatValue($discount); - else - return $amount - $this->formatValue($amount * $discount / 100); - - } - - - -*/ - - - - -} \ No newline at end of file diff --git a/app/Helpers/Invoice/InvoiceItemCalc.php b/app/Helpers/Invoice/InvoiceItemCalc.php deleted file mode 100644 index 0eb33a981c02..000000000000 --- a/app/Helpers/Invoice/InvoiceItemCalc.php +++ /dev/null @@ -1,215 +0,0 @@ -item = $item; - - $this->settings = $settings; - - $this->tax_collection = collect([]); - - $this->invoice = $invoice; - - $this->currency = $invoice->client->currency(); - } - - public function process() - { - - $this->setLineTotal($this->formatValue($this->item->cost, $this->currency->precision) * $this->formatValue($this->item->quantity, $this->currency->precision)); - - $this->setDiscount() - ->calcTaxes(); - - } - - private function setDiscount() - { - - if(!isset($this->item->is_amount_discount)) - return $this; - - if($this->item->is_amount_discount) - { - $discountedTotal = $this->getLineTotal() - $this->formatValue($this->item->discount, $this->currency->precision); - } - else - { - $discountedTotal = $this->getLineTotal() - $this->formatValue(round($this->getLineTotal() * ($this->item->discount / 100),2), $this->currency->precision); - } - - $this->setLineTotal($discountedTotal); - - $totalDiscount = $this->getTotalDiscounts() + $discountedTotal; - - $this->setTotalDiscounts($totalDiscount); - - return $this; - - } - - private function calcTaxes() - { - $item_tax = 0; - - if(isset($this->item->tax_rate1) && $this->item->tax_rate1 > 0) - { - $tax_rate1 = $this->formatValue($this->item->tax_rate1, $this->currency->precision); - - if($this->settings->inclusive_taxes) - $item_tax_rate1_total = $this->formatValue(($this->getLineTotal() - ($this->getLineTotal() / (1+$tax_rate1/100))) , $this->currency->precision); - else - $item_tax_rate1_total = $this->formatValue(($this->getLineTotal() * $tax_rate1/100), $this->currency->precision); - - $item_tax += $item_tax_rate1_total; - - $this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total); - } - - if(isset($this->item->tax_rate2) && $this->item->tax_rate2 > 0) - { - $tax_rate2 = $this->formatValue($this->item->tax_rate2, $this->currency->precision); - - if($this->settings->inclusive_taxes) - $item_tax_rate2_total = $this->formatValue(($this->getLineTotal() - ($this->getLineTotal() / (1+$tax_rate2/100))) , $this->currency->precision); - else - $item_tax_rate2_total = $this->formatValue(($this->getLineTotal() * $tax_rate2/100), $this->currency->precision); - - $item_tax += $item_tax_rate2_total; - - $this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total); - - } - - if(isset($this->item->tax_rate3) && $this->item->tax_rate3 > 0) - { - $tax_rate3 = $this->formatValue($this->item->tax_rate3, $this->currency->precision); - - if($this->settings->inclusive_taxes) - $item_tax_rate3_total = $this->formatValue(($this->getLineTotal() - ($this->getLineTotal() / (1+$tax_rate3/100))) , $this->currency->precision); - else - $item_tax_rate3_total = $this->formatValue(($this->getLineTotal() * $tax_rate3/100), $this->currency->precision); - - $item_tax += $item_tax_rate3_total; - - $this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total); - - } - - - $this->setTotalTaxes($item_tax); - - return $this; - } - - private function groupTax($tax_name, $tax_rate, $tax_total) - { - $group_tax = []; - - $key = str_replace(" ", "", $tax_name.$tax_rate); - - $group_tax = ['key' => $key, 'total' => $tax_total, 'tax_name' => $tax_name . ' ' . $tax_rate.'%']; - - $this->tax_collection->push(collect($group_tax)); - - } - - /**************** - * - * Getters and Setters - * - * - */ - public function getLineItem() - { - - return $this->item; - - } - - public function getLineTotal() - { - return $this->item->line_total; - } - - public function setLineTotal($total) - { - $this->item->line_total = $total; - - return $this; - } - - public function getTotalTaxes() - { - return $this->total_taxes; - } - - public function setTotalTaxes($total) - { - $this->total_taxes = $total; - - return $this; - } - - public function getTotalDiscounts() - { - return $this->total_discounts; - } - - public function setTotalDiscounts($total) - { - $this->total_discounts = $total; - - return $this; - } - - public function getGroupedTaxes() - { - return $this->tax_collection; - } - - public function setGroupedTaxes($group_taxes) - { - $this->tax_collection = $group_taxes; - - return $this; - } - - -} \ No newline at end of file diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index cec85c0ff875..63d9b20cc64b 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -55,13 +55,14 @@ class InvoiceItemSum $this->invoice = $invoice; - $this->currency = $invoice->client->currency(); + $this->currency = $this->invoice->client->currency(); $this->line_items = []; } public function process() { + if(!$this->invoice->line_items || count($this->invoice->line_items) == 0){ $this->items = []; return $this; diff --git a/app/Helpers/Invoice/InvoiceItemSumInclusive.php b/app/Helpers/Invoice/InvoiceItemSumInclusive.php new file mode 100644 index 000000000000..b393c2951bdf --- /dev/null +++ b/app/Helpers/Invoice/InvoiceItemSumInclusive.php @@ -0,0 +1,275 @@ +settings = $settings; + + $this->tax_collection = collect([]); + + $this->invoice = $invoice; + + $this->currency = $this->invoice->client->currency(); + + $this->line_items = []; + } + + public function process() + { + + if(!$this->invoice->line_items || count($this->invoice->line_items) == 0){ + $this->items = []; + return $this; + } + + $this->calcLineItems(); + + return $this; + } + + private function calcLineItems() + { + foreach($this->invoice->line_items as $this->item) + { + $this->sumLineItem() + ->setDiscount() + ->calcTaxes() + ->push(); + } + + return $this; + } + + private function push() + { + + $this->sub_total += $this->getLineTotal(); + + $this->line_items[] = $this->item; + + return $this; + } + + + private function sumLineItem() + { + $this->setLineTotal($this->formatValue($this->item->cost, $this->currency->precision) * $this->formatValue($this->item->quantity, $this->currency->precision)); + + return $this; + } + + private function setDiscount() + { + + if($this->invoice->is_amount_discount) + { + $this->setLineTotal($this->getLineTotal() - $this->formatValue($this->item->discount, $this->currency->precision)); + } + else + { + $this->setLineTotal($this->getLineTotal() - $this->formatValue(($this->item->line_total * ($this->item->discount / 100)), $this->currency->precision)); + } + + $this->item->is_amount_discount = $this->invoice->is_amount_discount; + + return $this; + + } + + /** + * Taxes effect the line totals and item costs. we decrement both on + * application of inclusive tax rates. + * + */ + private function calcTaxes() + { + + $item_tax = 0; + + $amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount/100)); + + $item_tax_rate1_total = $this->calcInclusiveLineTax($this->item->tax_rate1, $amount); + + $item_tax += $this->formatValue($item_tax_rate1_total, $this->currency->precision); + + if($item_tax_rate1_total > 0) + $this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total); + + $item_tax_rate2_total = $this->calcInclusiveLineTax($this->item->tax_rate2, $amount); + + $item_tax += $this->formatValue($item_tax_rate2_total, $this->currency->precision); + + if($item_tax_rate2_total > 0) + $this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total); + + $item_tax_rate3_total = $this->calcInclusiveLineTax($this->item->tax_rate3, $amount); + + $item_tax += $this->formatValue($item_tax_rate3_total, $this->currency->precision); + + if($item_tax_rate3_total > 0) + $this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total); + + $this->setTotalTaxes($this->formatValue($item_tax, $this->currency->precision)); + + return $this; + } + + private function groupTax($tax_name, $tax_rate, $tax_total) + { + $group_tax = []; + + $key = str_replace(" ", "", $tax_name.$tax_rate); + + $group_tax = ['key' => $key, 'total' => $tax_total, 'tax_name' => $tax_name . ' ' . $tax_rate.'%']; + + $this->tax_collection->push(collect($group_tax)); + + } + + public function getTotalTaxes() + { + return $this->total_taxes; + } + + public function setTotalTaxes($total) + { + $this->total_taxes = $total; + + return $this; + } + + public function setLineTotal($total) + { + $this->item->line_total = $total; + + return $this; + } + + public function getLineTotal() + { + return $this->item->line_total; + } + + public function getLineItems() + { + return $this->line_items; + } + + public function getGroupedTaxes() + { + return $this->tax_collection; + } + + public function setGroupedTaxes($group_taxes) + { + $this->tax_collection = $group_taxes; + + return $this; + } + + public function getSubTotal() + { + return $this->sub_total; + } + + public function setSubTotal($value) + { + $this->sub_total = $value; + return $this; + } + + /** + * Invoice Amount Discount + * + * The problem, when calculating invoice level discounts, + * the tax collected changes. + * + * We need to synthetically reduce the line_total amounts + * and recalculate the taxes and then pass back + * the updated map + */ + + public function calcTaxesWithAmountDiscount() + { + $this->setGroupedTaxes(collect([])); + + $item_tax = 0; + + foreach($this->line_items as $this->item) + { + + $amount = $this->item->line_total - ($this->item->line_total * ($this->invoice->discount/$this->sub_total)); + $item_tax_rate1_total = $this->calcInclusiveLineTax($this->item->tax_rate1, $amount); + + $item_tax += $item_tax_rate1_total; + + if($item_tax_rate1_total > 0) + $this->groupTax($this->item->tax_name1, $this->item->tax_rate1, $item_tax_rate1_total); + + $item_tax_rate2_total = $this->calcInclusiveLineTax($this->item->tax_rate2, $amount); + + $item_tax += $item_tax_rate2_total; + + if($item_tax_rate2_total > 0) + $this->groupTax($this->item->tax_name2, $this->item->tax_rate2, $item_tax_rate2_total); + + $item_tax_rate3_total = $this->calcInclusiveLineTax($this->item->tax_rate3, $amount); + + $item_tax += $item_tax_rate3_total; + + if($item_tax_rate3_total > 0) + $this->groupTax($this->item->tax_name3, $this->item->tax_rate3, $item_tax_rate3_total); + + + } + + $this->setTotalTaxes($item_tax); + + } +} \ No newline at end of file diff --git a/app/Helpers/Invoice/InvoiceSumInclusive.php b/app/Helpers/Invoice/InvoiceSumInclusive.php new file mode 100644 index 000000000000..ff2c64a9cfd7 --- /dev/null +++ b/app/Helpers/Invoice/InvoiceSumInclusive.php @@ -0,0 +1,296 @@ +invoice = $invoice; + + $this->settings = $settings; + + $this->tax_map = new Collection; + + } + + public function build() + { + $this->calculateLineItems() + ->calculateDiscount() + ->calculateCustomValues() + ->calculateInvoiceTaxes() + ->setTaxMap() +// ->calculateTotals() + ->calculateBalance() + ->calculatePartial(); + + return $this; + } + + private function calculateLineItems() + { + $this->invoice_items = new InvoiceItemSumInclusive($this->invoice, $this->settings); + $this->invoice_items->process(); + $this->invoice->line_items = $this->invoice_items->getLineItems(); + $this->total = $this->invoice_items->getSubTotal(); + $this->setSubTotal($this->invoice_items->getSubTotal()); + + return $this; + } + + private function calculateDiscount() + { + $this->total_discount = $this->discount($this->invoice_items->getSubTotal()); + + $this->total -= $this->total_discount; + + return $this; + } + + private function calculateCustomValues() + { + $this->total_taxes += $this->valuerTax($this->invoice->custom_value1, $this->settings->custom_invoice_taxes1); + $this->total_custom_values += $this->valuer($this->invoice->custom_value1); + + $this->total_taxes += $this->valuerTax($this->invoice->custom_value2, $this->settings->custom_invoice_taxes2); + $this->total_custom_values += $this->valuer($this->invoice->custom_value2); + + $this->total_taxes += $this->valuerTax($this->invoice->custom_value3, $this->settings->custom_invoice_taxes3); + $this->total_custom_values += $this->valuer($this->invoice->custom_value3); + + $this->total_taxes += $this->valuerTax($this->invoice->custom_value4, $this->settings->custom_invoice_taxes4); + $this->total_custom_values += $this->valuer($this->invoice->custom_value4); + + $this->total += $this->total_custom_values; + + return $this; + } + + private function calculateInvoiceTaxes() + { + $amount = $this->total; + + if($this->invoice->discount > 0 && $this->invoice->is_amount_discount) + $amount = $this->formatValue(($this->sub_total - $this->invoice->discount),2); + + if($this->invoice->discount > 0 && !$this->invoice->is_amount_discount) + $amount = $this->formatValue(($this->sub_total - ($this->sub_total * ($this->invoice->discount/100))),2); + + if($this->invoice->tax_rate1 > 0){ + $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate1, $amount); + $this->total_taxes += $tax; + + $this->total_tax_map[] = ['name' => $this->invoice->tax_name1 . ' ' . $this->invoice->tax_rate1.'%', 'total' => $tax]; + + } + + + if($this->invoice->tax_rate2 > 0){ + $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate2, $amount); + $this->total_taxes += $tax; + $this->total_tax_map[] = ['name' => $this->invoice->tax_name2. ' ' . $this->invoice->tax_rate2.'%', 'total' => $tax]; + + } + + if($this->invoice->tax_rate3 > 0){ + $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate3, $amount); + $this->total_taxes += $tax; + $this->total_tax_map[] = ['name' => $this->invoice->tax_name3 . ' ' . $this->invoice->tax_rate3.'%', 'total' => $tax]; + } + + return $this; + } + + /** + * Calculates the balance. + * + * @return self The balance. + */ + private function calculateBalance() + { + //$this->invoice->balance = $this->balance($this->getTotal(), $this->invoice); + $this->setCalculatedAttributes(); + + return $this; + } + + private function calculatePartial() + { + if ( !isset($this->invoice->id) && isset($this->invoice->partial) ) { + $this->invoice->partial = max(0, min($this->formatValue($this->invoice->partial, 2), $this->invoice->balance)); + } + + return $this; + } + + private function calculateTotals() + { + $this->total += $this->total_taxes; + + return $this; + } + + public function getInvoice() + { + //Build invoice values here and return Invoice + $this->setCalculatedAttributes(); + $this->invoice->save(); + + return $this->invoice; + } + + + /** + * Build $this->invoice variables after + * calculations have been performed. + */ + private function setCalculatedAttributes() + { + /* If amount != balance then some money has been paid on the invoice, need to subtract this difference from the total to set the new balance */ + if($this->invoice->amount != $this->invoice->balance) + { + $paid_to_date = $this->invoice->amount - $this->invoice->balance; + + $this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision) - $paid_to_date; + } + else + $this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision); + + /* Set new calculated total */ + $this->invoice->amount = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision); + + return $this; + } + + public function getSubTotal() + { + return $this->sub_total; + } + + public function setSubTotal($value) + { + $this->sub_total = $value; + return $this; + } + + public function getTotalDiscount() + { + return $this->total_discount; + } + + public function getTotalTaxes() + { + return $this->total_taxes; + } + + public function getTotalTaxMap() + { + return $this->total_tax_map; + } + + public function getTotal() + { + return $this->total; + } + + public function setTaxMap() + { + if($this->invoice->is_amount_discount == true) + $this->invoice_items->calcTaxesWithAmountDiscount(); + + $this->tax_map = collect(); + + $keys = $this->invoice_items->getGroupedTaxes()->pluck('key')->unique(); + + $values = $this->invoice_items->getGroupedTaxes(); + + foreach($keys as $key) + { + + $tax_name = $values->filter(function ($value, $k) use($key){ + return $value['key'] == $key; + })->pluck('tax_name')->first(); + + $total_line_tax = $values->filter(function ($value, $k) use($key){ + return $value['key'] == $key; + })->sum('total'); + + //$total_line_tax -= $this->discount($total_line_tax); + + $this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax]; + + $this->total_taxes += $total_line_tax; + } + + return $this; + + } + + public function getTaxMap() + { + return $this->tax_map; + } + + public function getBalance() + { + return $this->invoice->balance; + } + + public function getItemTotalTaxes() + { + return $this->getTotalTaxes(); + } + + +} \ No newline at end of file diff --git a/app/Helpers/Invoice/Taxer.php b/app/Helpers/Invoice/Taxer.php index a340d17c1e60..f95296318b81 100644 --- a/app/Helpers/Invoice/Taxer.php +++ b/app/Helpers/Invoice/Taxer.php @@ -24,7 +24,13 @@ trait Taxer public function calcAmountLineTax($tax_rate, $amount) { - return $this->formatValue(($amount * $tax_rate/100), 4); + return $this->formatValue(($amount * $tax_rate/100), 2); } + public function calcInclusiveLineTax($tax_rate, $amount) + { + return $this->formatValue($amount - ($amount / (1 + ($tax_rate/100))), 2); + } + + } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index db8792922bc4..7d42d058c2d8 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -12,6 +12,8 @@ namespace App\Models; use App\Events\Invoice\InvoiceWasUpdated; +use App\Helpers\Invoice\InvoiceSum; +use App\Helpers\Invoice\InvoiceSumInclusive; use App\Models\Currency; use App\Models\Filterable; use App\Models\PaymentTerm; @@ -19,7 +21,6 @@ use App\Utils\Number; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesInvoiceValues; use App\Utils\Traits\NumberFormatter; -use App\Helpers\Invoice\InvoiceSum; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Carbon; @@ -267,9 +268,12 @@ class Invoice extends BaseModel */ public function calc() { -//todo will need to switch between inclusive and exclusive implementations of InvoiceSum - - $invoice_calc = new InvoiceSum($this, $this->settings); + $invoice_calc = null; + + if($this->settings->inclusive_taxes) + $invoice_calc = new InvoiceSumInclusive($this, $this->settings); + else + $invoice_calc = new InvoiceSum($this, $this->settings); return $invoice_calc->build(); diff --git a/app/Repositories/InvoiceRepository.php b/app/Repositories/InvoiceRepository.php index 1286dab5ce83..68b7a795ac35 100644 --- a/app/Repositories/InvoiceRepository.php +++ b/app/Repositories/InvoiceRepository.php @@ -75,9 +75,11 @@ class InvoiceRepository extends BaseRepository event(new CreateInvoiceInvitation($invoice)); - $invoice_calc = new InvoiceSum($invoice, $invoice->settings); + $invoice = $invoice->calc()->getInvoice(); + + // $invoice_calc = new InvoiceSum($invoice, $invoice->settings); - $invoice = $invoice_calc->build()->getInvoice(); + // $invoice = $invoice_calc->build()->getInvoice(); $invoice->save(); diff --git a/app/Transformers/CompanyGatewayTransformer.php b/app/Transformers/CompanyGatewayTransformer.php index 91046958a1ea..6febbd40d4de 100644 --- a/app/Transformers/CompanyGatewayTransformer.php +++ b/app/Transformers/CompanyGatewayTransformer.php @@ -56,7 +56,7 @@ class CompanyGatewayTransformer extends EntityTransformer 'min_limit' => (float)$company_gateway->min_limit, 'max_limit' => (float)$company_gateway->max_limit, 'fee_amount' => (float) $company_gateway->fee_amount, - 'fee_percent' => (float)$company_gateway->fee_percent ?: '', + 'fee_percent' => (float)$company_gateway->fee_percent, 'fee_tax_name1' => (string)$company_gateway->fee_tax_name1 ?: '', 'fee_tax_name2' => (string) $company_gateway->fee_tax_name2 ?: '', 'fee_tax_name3' => (string) $company_gateway->fee_tax_name3 ?: '', diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index d7107c5d87ab..fa72f6e30c4c 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -369,10 +369,10 @@ class CreateUsersTable extends Migration $table->text('config'); $table->unsignedInteger('priority_id')->default(0); - $table->decimal('min_limit', 13, 2)->nullable(); - $table->decimal('max_limit', 13, 2)->nullable(); - $table->decimal('fee_amount', 13, 2)->nullable(); - $table->decimal('fee_percent', 13, 2)->nullable(); + $table->decimal('min_limit', 13, 2)->default(0); + $table->decimal('max_limit', 13, 2)->default(0); + $table->decimal('fee_amount', 13, 2)->default(0); + $table->decimal('fee_percent', 13, 2)->default(0); $table->string('fee_tax_name1')->nullable(); $table->string('fee_tax_name2')->nullable(); $table->string('fee_tax_name3')->nullable(); @@ -380,7 +380,7 @@ class CreateUsersTable extends Migration $table->decimal('fee_tax_rate2', 13, 2)->nullable(); $table->decimal('fee_tax_rate3', 13, 2)->nullable(); $table->unsignedInteger('fee_cap')->default(0); - $table->boolean('adjust_fee_percent'); + $table->boolean('adjust_fee_percent')->default(false); $table->timestamps(6); $table->softDeletes(); diff --git a/database/seeds/RandomDataSeeder.php b/database/seeds/RandomDataSeeder.php index 4adc3d81df02..1e8dcde76088 100644 --- a/database/seeds/RandomDataSeeder.php +++ b/database/seeds/RandomDataSeeder.php @@ -7,6 +7,7 @@ use App\Events\Invoice\InvoiceWasMarkedSent; use App\Events\Invoice\InvoiceWasUpdated; use App\Events\Payment\PaymentWasCreated; use App\Helpers\Invoice\InvoiceSum; +use App\Helpers\Invoice\InvoiceSumInclusive; use App\Jobs\Company\UpdateCompanyLedgerWithInvoice; use App\Jobs\Invoice\UpdateInvoicePayment; use App\Listeners\Invoice\CreateInvoiceInvitation; @@ -120,11 +121,17 @@ class RandomDataSeeder extends Seeder $invoices->each(function ($invoice) use($invoice_repo, $user, $company, $client){ - //$settings = $invoice->settings; + $settings = $invoice->settings; //$settings->inclusive_taxes = (bool)random_int(0, 1); - //$invoice->settings = $settings; + $settings->inclusive_taxes = true; + $invoice->settings = $settings; - $invoice_calc = new InvoiceSum($invoice, $invoice->settings); + $invoice_calc = null; + + if($settings->inclusive_taxes) + $invoice_calc = new InvoiceSumInclusive($invoice, $invoice->settings); + else + $invoice_calc = new InvoiceSum($invoice, $invoice->settings); $invoice = $invoice_calc->build()->getInvoice(); diff --git a/tests/Integration/MarkInvoicePaidTest.php b/tests/Integration/MarkInvoicePaidTest.php index d5e39a2ad560..d0688803935f 100644 --- a/tests/Integration/MarkInvoicePaidTest.php +++ b/tests/Integration/MarkInvoicePaidTest.php @@ -36,15 +36,11 @@ class MarkInvoicePaidTest extends TestCase public function testMarkInvoicePaidInvoice() { - \Log::error($this->invoice->amount); - \Log::error($this->invoice->balance); + MarkInvoicePaid::dispatchNow($this->invoice); $invoice = Invoice::find($this->invoice->id); - - \Log::error($invoice->amount); - \Log::error($invoice->balance); - + $this->assertEquals(0.00, $invoice->balance); $this->assertEquals(1, count($invoice->payments)); diff --git a/tests/MockAccountData.php b/tests/MockAccountData.php index 33216986464b..42c757ee9f40 100644 --- a/tests/MockAccountData.php +++ b/tests/MockAccountData.php @@ -31,7 +31,6 @@ use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\MakesHash; use App\Helpers\Invoice\InvoiceSum; use Illuminate\Support\Carbon; -use Illuminate\Support\Facades\Log; /** * Class MockAccountData @@ -99,9 +98,7 @@ trait MockAccountData $this->client->group_settings_id = $gs->id; $this->client->save(); - - - + $this->invoice = InvoiceFactory::create($this->company->id,$this->user->id);//stub the company and user_id $this->invoice->client_id = $this->client->id; @@ -115,6 +112,7 @@ trait MockAccountData $this->settings->precision = 2; $this->invoice->settings = $this->settings; + $this->invoice->save(); $this->invoice_calc = new InvoiceSum($this->invoice, $this->settings); $this->invoice_calc->build(); diff --git a/tests/Unit/InvoiceInclusiveTest.php b/tests/Unit/InvoiceInclusiveTest.php new file mode 100644 index 000000000000..2a0bc34f9f20 --- /dev/null +++ b/tests/Unit/InvoiceInclusiveTest.php @@ -0,0 +1,377 @@ +makeTestData(); + + $this->invoice->line_items = $this->buildLineItems(); + + $this->settings = $this->invoice->settings; + + $this->settings->inclusive_taxes = true; + $this->settings->precision = 2; + + $this->invoice_calc = new InvoiceSumInclusive($this->invoice, $this->settings); + + } + + private function buildLineItems() + { + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + + $line_items[] = $item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + + $line_items[] = $item; + + return $line_items; + + } + + public function testInvoiceTotals() + { + + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotal(), 20); + } + + public function testInvoiceTotalsWithDiscount() + { + $this->invoice->discount = 5; + + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotal(), 15); + $this->assertEquals($this->invoice_calc->getBalance(), 15); + } + + public function testInvoiceTotalsWithDiscountWithSurcharge() + { + $this->invoice->discount = 5; + $this->invoice->custom_value1 = 5; + + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotal(), 20); + $this->assertEquals($this->invoice_calc->getBalance(), 20); + } + + public function testInvoiceTotalsWithDiscountWithSurchargeWithInclusiveTax() + { + $this->invoice->discount = 5; + $this->invoice->custom_value1 = 5; + $this->invoice->tax_name1 = 'GST'; + $this->invoice->tax_rate1 = 10; + $this->invoice->is_amount_discount = true; + + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotalTaxes(), 1.36); + $this->assertEquals($this->invoice_calc->getTotal(), 20); + $this->assertEquals($this->invoice_calc->getBalance(), 20); + } + + public function testInvoiceTotalsWithPercentDiscountWithSurchargeWithInclusiveTax() + { + $this->invoice->discount = 5; + $this->invoice->custom_value1 = 5; + $this->invoice->tax_name1 = 'GST'; + $this->invoice->tax_rate1 = 10; + $this->invoice->is_amount_discount = false; + + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotalTaxes(), 1.73); + $this->assertEquals($this->invoice_calc->getTotal(), 24); + } + + public function testInvoiceTotalsWithDiscountWithSurchargeWithExclusiveTax() + { + + $this->invoice->discount = 5; + $this->invoice->custom_value1 = 5; + $this->invoice->tax_name1 = 'GST'; + $this->invoice->tax_rate1 = 10; + $this->settings->inclusive_taxes = true; + $this->invoice->is_amount_discount = true; + + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotal(), 20); + //$this->assertEquals($this->invoice_calc->getTotalTaxes(), 1.5); + } + + public function testInvoiceTotalsWithDiscountWithSurchargeWithDoubleExclusiveTax() + { + + $this->invoice->discount = 5; + $this->invoice->custom_value1 = 5; + $this->invoice->tax_name1 = 'GST'; + $this->invoice->tax_rate1 = 10; + $this->invoice->tax_name2 = 'GST'; + $this->invoice->tax_rate2 = 10; + $this->settings->inclusive_taxes = true; + $this->invoice->is_amount_discount = true; + + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotalTaxes(), 2.72); + } + + + public function testLineItemTaxRatesInclusiveTaxes() + { + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + + $line_items[] = $item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + + $line_items[] = $item; + + $this->invoice->line_items = $line_items; + + $this->settings->inclusive_taxes = true; + $this->invoice->discount = 0; + $this->invoice->custom_value1 = 0; + + $this->invoice_calc = new InvoiceSumInclusive($this->invoice, $this->settings); + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotalTaxes(), 1.82); + $this->assertEquals(count($this->invoice_calc->getTaxMap()), 1); + $this->assertEquals($this->invoice_calc->getTotal(), 20); + $this->assertEquals($this->invoice_calc->getBalance(), 20); + } + + public function testLineItemTaxRatesInclusiveTaxesWithInvoiceTaxes() + { + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + + $line_items[] = $item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + + $line_items[] = $item; + + $this->invoice->line_items = $line_items; + + $this->settings->inclusive_taxes = true; + $this->invoice->discount = 0; + $this->invoice->custom_value1 = 0; + + $this->invoice->tax_rate1 = 10; + $this->invoice->tax_rate2 = 10; + + $this->invoice_calc = new InvoiceSumInclusive($this->invoice, $this->settings); + $this->invoice_calc->build(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 20); + $this->assertEquals($this->invoice_calc->getTotalTaxes(), 5.46); + $this->assertEquals(count($this->invoice_calc->getTaxMap()), 1); + $this->assertEquals($this->invoice_calc->getTotal(), 20); + $this->assertEquals($this->invoice_calc->getBalance(), 20); + } + + public function testLineItemTaxRatesInclusiveTaxesWithInvoiceTaxesAndDiscounts() + { + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + $item->discount = 5; + + $line_items[] = $item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + $item->discount = 5; + + $line_items[] = $item; + + $this->invoice->line_items = $line_items; + + $this->settings->inclusive_taxes = true; + $this->invoice->discount = 5; + $this->invoice->is_amount_discount = false; + $this->invoice->custom_value1 = 0; + + $this->invoice->tax_rate1 = 10; + $this->invoice->tax_rate2 = 10; + + $this->invoice_calc = new InvoiceSumInclusive($this->invoice, $this->settings); + $this->invoice_calc->build(); + + $line_items = $this->invoice_calc->invoice_items->getLineItems(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 19); + $this->assertEquals($this->invoice_calc->getTotalDiscount(), 0.95); + $this->assertEquals($this->invoice_calc->getTotalTaxes(), 4.92); + $this->assertEquals(count($this->invoice_calc->getTaxMap()), 1); + $this->assertEquals($this->invoice_calc->getTotal(), 18.05); + $this->assertEquals($this->invoice_calc->getBalance(), 18.05); + } + + public function testLineItemTaxRatesInclusiveTaxesWithInvoiceTaxesAndAmountDiscounts() + { + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + $item->discount = 5; + + $line_items[] = $item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + $item->discount = 5; + + $line_items[] = $item; + + $this->invoice->line_items = $line_items; + + $this->settings->inclusive_taxes = true; + $this->invoice->discount = 5; + $this->invoice->is_amount_discount = true; + $this->invoice->custom_value1 = 0; + + $this->invoice->tax_rate1 = 10; + $this->invoice->tax_rate2 = 10; + + $this->invoice_calc = new InvoiceSumInclusive($this->invoice, $this->settings); + $this->invoice_calc->build(); + + $line_items = $this->invoice_calc->invoice_items->getLineItems(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 10); + $this->assertEquals($this->invoice_calc->getTotalDiscount(), 5); + $this->assertEquals($this->invoice_calc->getTotalTaxes(), 1.36); + $this->assertEquals(count($this->invoice_calc->getTaxMap()), 1); + $this->assertEquals($this->invoice_calc->getTotal(), 5); + $this->assertEquals($this->invoice_calc->getBalance(), 5); + } + + + public function testLineItemTaxRatesInclusiveTaxesWithInvoiceTaxesAndAmountDiscountsWithLargeCosts() + { + $line_items = []; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =100; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + $item->discount = 5; + + $line_items[] = $item; + + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =100; + $item->tax_rate1 = 10; + $item->tax_name1 = 10; + $item->discount = 5; + + $line_items[] = $item; + + $this->invoice->line_items = $line_items; + + $this->settings->inclusive_taxes = true; + $this->invoice->discount = 5; + $this->invoice->is_amount_discount = true; + $this->invoice->custom_value1 = 0; + + $this->invoice->tax_rate1 = 10; + $this->invoice->tax_rate2 = 10; + + $this->invoice_calc = new InvoiceSumInclusive($this->invoice, $this->settings); + $this->invoice_calc->build(); + + $line_items = $this->invoice_calc->invoice_items->getLineItems(); + + $this->assertEquals($this->invoice_calc->getSubTotal(), 190); + $this->assertEquals($this->invoice_calc->getTotalDiscount(), 5); + $this->assertEquals($this->invoice_calc->getTotalTaxes(), 50.46); + $this->assertEquals(count($this->invoice_calc->getTaxMap()), 1); + $this->assertEquals($this->invoice_calc->getTotal(), 185); + $this->assertEquals($this->invoice_calc->getBalance(), 185); + } +} \ No newline at end of file diff --git a/tests/Unit/InvoiceItemInclusiveTest.php b/tests/Unit/InvoiceItemInclusiveTest.php new file mode 100644 index 000000000000..ba6a02548bcb --- /dev/null +++ b/tests/Unit/InvoiceItemInclusiveTest.php @@ -0,0 +1,231 @@ +makeTestData(); + + } + + public function testInvoiceItemTotalSimpleX() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->is_amount_discount = true; + + $settings = new \stdClass; + $settings->inclusive_taxes = true; + $settings->precision = 2; + + $this->invoice->line_items = [$item]; + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getLineTotal(), 10); + } + + public function testInvoiceItemTotalSimpleWithDiscount() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->is_amount_discount = true; + $item->discount = 2; + + $this->invoice->line_items = [$item]; + + $settings = new \stdClass; + $settings->inclusive_taxes = true; + $settings->precision = 2; + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getLineTotal(), 8); + } + + public function testInvoiceItemTotalSimpleWithDiscountWithPrecision() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->is_amount_discount = true; + $item->discount = 2.521254522145214511; + + $this->invoice->line_items = [$item]; + + $settings = new \stdClass; + $settings->inclusive_taxes = true; + $settings->precision = 2; + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getLineTotal(), 7.48); + } + + public function testInvoiceItemTotalSimpleWithDiscountWithPrecisionWithSingleInclusiveTax() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->is_amount_discount = true; + $item->discount = 0; + $item->tax_rate1 = 10; + + $settings = new \stdClass; + $settings->inclusive_taxes = false; + $settings->precision = 2; + + $this->invoice->line_items = [$item]; + + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getTotalTaxes(), 0.91); + $this->assertEquals($item_calc->getSubTotal(), 10); + } + + public function testInvoiceItemTotalSimpleWithDiscountWithPrecisionWithSingleInclusiveTax2() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->is_amount_discount = true; + $item->discount = 2; + $item->tax_rate1 = 10; + + $settings = new \stdClass; + $settings->inclusive_taxes = false; + $settings->precision = 2; + + $this->invoice->line_items = [$item]; + + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getTotalTaxes(), 0.73); + $this->assertEquals($item_calc->getSubTotal(), 8); + } + + public function testInvoiceItemTotalSimpleWithDiscountWithPrecisionWithDoubleInclusiveTax() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost = 10; + $item->is_amount_discount = true; + $item->discount = 0; + $item->tax_rate1 = 10; + $item->tax_rate2 = 17.5; + + $this->invoice->line_items = [$item]; + + $settings = new \stdClass; + $settings->inclusive_taxes = true; + $settings->precision = 2; + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getTotalTaxes(), 2.4); + $this->assertEquals($item_calc->getSubTotal(), 10); + + } + + public function testInvoiceItemTotalSimpleWithDiscountWithDoubleInclusiveTax() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 1; + $item->cost =10; + $item->is_amount_discount = true; + $item->discount = 1; + $item->tax_rate1 = 10; + $item->tax_rate2 = 17.5; + + $this->invoice->line_items = [$item]; + + $settings = new \stdClass; + $settings->inclusive_taxes = false; + $settings->precision = 2; + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getSubTotal(), 9); + $this->assertEquals($item_calc->getTotalTaxes(), 2.16); + } + + public function testInvoiceItemTotalSimpleWithDiscountWithDoubleInclusiveTaxMultiQuantity() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 2; + $item->cost =10; + $item->is_amount_discount = true; + $item->discount = 1; + $item->tax_rate1 = 10; + $item->tax_rate2 = 17.5; + + $this->invoice->line_items = [$item]; + + $settings = new \stdClass; + $settings->inclusive_taxes = false; + $settings->precision = 2; + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getSubTotal(), 19); + $this->assertEquals($item_calc->getTotalTaxes(), 4.56); + } + + public function testInvoiceItemTotalSimpleWithPercentDiscountWithDoubleInclusiveTaxMultiQuantity() + { + $item = InvoiceItemFactory::create(); + $item->quantity = 2; + $item->cost =10; + $item->is_amount_discount = false; + $item->discount = 1; + $item->tax_rate1 = 10; + $item->tax_rate2 = 17.5; + + $this->invoice->line_items = [$item]; + $this->invoice->is_amount_discount = false; + + $settings = new \stdClass; + $settings->inclusive_taxes = false; + $settings->precision = 2; + + $item_calc = new InvoiceItemSumInclusive($this->invoice, $settings); + $item_calc->process(); + + $this->assertEquals($item_calc->getSubTotal(), 19.8); + $this->assertEquals($item_calc->getTotalTaxes(), 4.75); + } +} + + diff --git a/tests/Unit/InvoiceItemTest.php b/tests/Unit/InvoiceItemTest.php index 7a9aad569712..47f841f4dc79 100644 --- a/tests/Unit/InvoiceItemTest.php +++ b/tests/Unit/InvoiceItemTest.php @@ -3,14 +3,14 @@ namespace Tests\Unit; use App\Factory\InvoiceItemFactory; -use App\Helpers\Invoice\InvoiceItemCalc; +use App\Helpers\Invoice\InvoiceItemSum; use Illuminate\Foundation\Testing\DatabaseTransactions; use Tests\MockAccountData; use Tests\TestCase; /** * @test - * @covers App\Helpers\Invoice\InvoiceItemCalc + * @covers App\Helpers\Invoice\InvoiceItemSum */ class InvoiceItemTest extends TestCase { @@ -38,7 +38,9 @@ class InvoiceItemTest extends TestCase $settings->inclusive_taxes = true; $settings->precision = 2; - $item_calc = new InvoiceItemCalc($item, $settings, $this->invoice); + $this->invoice->line_items = [$item]; + + $item_calc = new InvoiceItemSum($this->invoice, $settings); $item_calc->process(); $this->assertEquals($item_calc->getLineTotal(), 10); @@ -52,10 +54,13 @@ class InvoiceItemTest extends TestCase $item->is_amount_discount = true; $item->discount = 2; + $this->invoice->line_items = [$item]; + $settings = new \stdClass; $settings->inclusive_taxes = true; $settings->precision = 2; - $item_calc = new InvoiceItemCalc($item, $settings, $this->invoice); + + $item_calc = new InvoiceItemSum($this->invoice, $settings); $item_calc->process(); $this->assertEquals($item_calc->getLineTotal(), 8); @@ -69,11 +74,13 @@ class InvoiceItemTest extends TestCase $item->is_amount_discount = true; $item->discount = 2.521254522145214511; + $this->invoice->line_items = [$item]; + $settings = new \stdClass; $settings->inclusive_taxes = true; $settings->precision = 2; - $item_calc = new InvoiceItemCalc($item, $settings, $this->invoice); + $item_calc = new InvoiceItemSum($this->invoice, $settings); $item_calc->process(); $this->assertEquals($item_calc->getLineTotal(), 7.48); @@ -85,17 +92,20 @@ class InvoiceItemTest extends TestCase $item->quantity = 1; $item->cost =10; $item->is_amount_discount = true; - $item->discount = 2.521254522145214511; + $item->discount = 2; $item->tax_rate1 = 10; $settings = new \stdClass; - $settings->inclusive_taxes = true; + $settings->inclusive_taxes = false; $settings->precision = 2; - $item_calc = new InvoiceItemCalc($item, $settings, $this->invoice); + $this->invoice->line_items = [$item]; + + + $item_calc = new InvoiceItemSum($this->invoice, $settings); $item_calc->process(); - $this->assertEquals($item_calc->getTotalTaxes(), 0.68); + $this->assertEquals($item_calc->getTotalTaxes(), 0.80); } public function testInvoiceItemTotalSimpleWithDiscountWithPrecisionWithSingleExclusiveTax() @@ -107,11 +117,14 @@ class InvoiceItemTest extends TestCase $item->discount = 2.521254522145214511; $item->tax_rate1 = 10; + $this->invoice->line_items = [$item]; + + $settings = new \stdClass; $settings->inclusive_taxes = false; $settings->precision = 2; - $item_calc = new InvoiceItemCalc($item, $settings, $this->invoice); + $item_calc = new InvoiceItemSum($this->invoice, $settings); $item_calc->process(); $this->assertEquals($item_calc->getTotalTaxes(), 0.75); @@ -127,14 +140,16 @@ class InvoiceItemTest extends TestCase $item->tax_rate1 = 10; $item->tax_rate2 = 17.5; + $this->invoice->line_items = [$item]; + $settings = new \stdClass; $settings->inclusive_taxes = true; $settings->precision = 2; - $item_calc = new InvoiceItemCalc($item, $settings, $this->invoice); + $item_calc = new InvoiceItemSum($this->invoice, $settings); $item_calc->process(); - $this->assertEquals($item_calc->getTotalTaxes(), 1.79); + $this->assertEquals($item_calc->getTotalTaxes(), 2.06); } public function testInvoiceItemTotalSimpleWithDiscountWithPrecisionWithDoubleExclusiveTax() @@ -147,11 +162,13 @@ class InvoiceItemTest extends TestCase $item->tax_rate1 = 10; $item->tax_rate2 = 17.5; + $this->invoice->line_items = [$item]; + $settings = new \stdClass; $settings->inclusive_taxes = false; $settings->precision = 2; - $item_calc = new InvoiceItemCalc($item, $settings, $this->invoice); + $item_calc = new InvoiceItemSum($this->invoice, $settings); $item_calc->process(); $this->assertEquals($item_calc->getTotalTaxes(), 2.06);