2019-10-16 11:28:52 +02:00
|
|
|
<?php
|
|
|
|
/**
|
2020-09-06 11:38:10 +02:00
|
|
|
* Invoice Ninja (https://invoiceninja.com).
|
2019-10-16 11:28:52 +02:00
|
|
|
*
|
|
|
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
|
|
*
|
2023-01-28 23:21:40 +01:00
|
|
|
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
2019-10-16 11:28:52 +02:00
|
|
|
*
|
2021-06-16 08:58:16 +02:00
|
|
|
* @license https://www.elastic.co/licensing/elastic-license
|
2019-10-16 11:28:52 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
namespace App\Helpers\Invoice;
|
|
|
|
|
2020-10-28 11:10:49 +01:00
|
|
|
use App\Models\Invoice;
|
2019-10-16 11:28:52 +02:00
|
|
|
use App\Utils\Traits\NumberFormatter;
|
|
|
|
use Illuminate\Support\Collection;
|
|
|
|
|
|
|
|
class InvoiceSum
|
|
|
|
{
|
2019-12-30 22:59:12 +01:00
|
|
|
use Taxer;
|
|
|
|
use Balancer;
|
|
|
|
use CustomValuer;
|
|
|
|
use Discounter;
|
|
|
|
use NumberFormatter;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
protected $invoice;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
public $tax_map;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
public $invoice_item;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2021-09-06 01:37:35 +02:00
|
|
|
public $total_taxes = 0;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private $total;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private $total_discount;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private $total_custom_values;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private $total_tax_map;
|
2019-10-17 00:51:05 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private $sub_total;
|
2020-09-06 11:38:10 +02:00
|
|
|
|
2021-09-15 01:02:25 +02:00
|
|
|
private $gross_sub_total;
|
|
|
|
|
2022-06-06 14:27:17 +02:00
|
|
|
private $precision;
|
|
|
|
|
2023-03-21 08:14:25 +01:00
|
|
|
public InvoiceItemSum $invoice_items;
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
/**
|
2020-09-06 11:38:10 +02:00
|
|
|
* Constructs the object with Invoice and Settings object.
|
2019-12-30 22:59:12 +01:00
|
|
|
*
|
2022-12-08 22:36:06 +01:00
|
|
|
* @param \App\Models\RecurringInvoice|\App\Models\Quote|\App\Models\Credit|\App\Models\PurchaseOrder|\App\Models\Invoice $invoice The entity
|
2019-12-30 22:59:12 +01:00
|
|
|
*/
|
|
|
|
public function __construct($invoice)
|
|
|
|
{
|
|
|
|
$this->invoice = $invoice;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2022-06-21 11:57:17 +02:00
|
|
|
if ($this->invoice->client) {
|
2022-06-06 14:27:17 +02:00
|
|
|
$this->precision = $this->invoice->client->currency()->precision;
|
2022-06-21 11:57:17 +02:00
|
|
|
} else {
|
2022-06-07 13:07:14 +02:00
|
|
|
$this->precision = $this->invoice->vendor->currency()->precision;
|
2022-06-21 11:57:17 +02:00
|
|
|
}
|
2021-10-13 06:47:56 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$this->tax_map = new Collection;
|
|
|
|
}
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
public function build()
|
|
|
|
{
|
|
|
|
$this->calculateLineItems()
|
|
|
|
->calculateDiscount()
|
|
|
|
->calculateInvoiceTaxes()
|
2021-02-21 10:36:34 +01:00
|
|
|
->calculateCustomValues()
|
2019-12-30 22:59:12 +01:00
|
|
|
->setTaxMap()
|
|
|
|
->calculateTotals()
|
|
|
|
->calculateBalance()
|
|
|
|
->calculatePartial();
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
return $this;
|
|
|
|
}
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private function calculateLineItems()
|
|
|
|
{
|
|
|
|
$this->invoice_items = new InvoiceItemSum($this->invoice);
|
|
|
|
$this->invoice_items->process();
|
|
|
|
$this->invoice->line_items = $this->invoice_items->getLineItems();
|
|
|
|
$this->total = $this->invoice_items->getSubTotal();
|
|
|
|
$this->setSubTotal($this->invoice_items->getSubTotal());
|
2021-09-15 01:02:25 +02:00
|
|
|
$this->setGrossSubTotal($this->invoice_items->getGrossSubTotal());
|
2022-06-21 11:57:17 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
return $this;
|
|
|
|
}
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private function calculateDiscount()
|
|
|
|
{
|
|
|
|
$this->total_discount = $this->discount($this->invoice_items->getSubTotal());
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$this->total -= $this->total_discount;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
return $this;
|
|
|
|
}
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private function calculateCustomValues()
|
|
|
|
{
|
2019-10-29 12:12:59 +01:00
|
|
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge1);
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-10-29 12:12:59 +01:00
|
|
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge2);
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-10-29 12:12:59 +01:00
|
|
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge3);
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-10-29 12:12:59 +01:00
|
|
|
$this->total_custom_values += $this->valuer($this->invoice->custom_surcharge4);
|
2019-10-16 11:28:52 +02:00
|
|
|
|
|
|
|
$this->total += $this->total_custom_values;
|
|
|
|
|
|
|
|
return $this;
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function calculateInvoiceTaxes()
|
|
|
|
{
|
2022-07-05 08:15:46 +02:00
|
|
|
if (is_string($this->invoice->tax_name1) && strlen($this->invoice->tax_name1) > 1) {
|
2019-12-30 22:59:12 +01:00
|
|
|
$tax = $this->taxer($this->total, $this->invoice->tax_rate1);
|
2021-04-10 01:59:19 +02:00
|
|
|
$tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name1, $this->invoice->tax_rate1);
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$this->total_taxes += $tax;
|
2021-01-06 23:43:08 +01:00
|
|
|
$this->total_tax_map[] = ['name' => $this->invoice->tax_name1.' '.floatval($this->invoice->tax_rate1).'%', 'total' => $tax];
|
2019-10-16 11:28:52 +02:00
|
|
|
}
|
|
|
|
|
2022-07-05 08:15:46 +02:00
|
|
|
if (is_string($this->invoice->tax_name2) && strlen($this->invoice->tax_name2) > 1) {
|
2019-12-30 22:59:12 +01:00
|
|
|
$tax = $this->taxer($this->total, $this->invoice->tax_rate2);
|
2021-04-10 01:59:19 +02:00
|
|
|
$tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name2, $this->invoice->tax_rate2);
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$this->total_taxes += $tax;
|
2021-01-06 23:43:08 +01:00
|
|
|
$this->total_tax_map[] = ['name' => $this->invoice->tax_name2.' '.floatval($this->invoice->tax_rate2).'%', 'total' => $tax];
|
2019-10-16 11:28:52 +02:00
|
|
|
}
|
|
|
|
|
2022-07-05 08:15:46 +02:00
|
|
|
if (is_string($this->invoice->tax_name3) && strlen($this->invoice->tax_name3) > 1) {
|
2019-12-30 22:59:12 +01:00
|
|
|
$tax = $this->taxer($this->total, $this->invoice->tax_rate3);
|
2021-04-10 01:59:19 +02:00
|
|
|
$tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name3, $this->invoice->tax_rate3);
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$this->total_taxes += $tax;
|
2021-01-06 23:43:08 +01:00
|
|
|
$this->total_tax_map[] = ['name' => $this->invoice->tax_name3.' '.floatval($this->invoice->tax_rate3).'%', 'total' => $tax];
|
2019-10-16 11:28:52 +02:00
|
|
|
}
|
2022-06-21 11:57:17 +02:00
|
|
|
|
2019-10-16 11:28:52 +02:00
|
|
|
return $this;
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculates the balance.
|
|
|
|
*
|
|
|
|
* @return self The balance.
|
|
|
|
*/
|
|
|
|
private function calculateBalance()
|
|
|
|
{
|
|
|
|
$this->setCalculatedAttributes();
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function calculatePartial()
|
|
|
|
{
|
2020-09-06 11:38:10 +02:00
|
|
|
if (! isset($this->invoice->id) && isset($this->invoice->partial)) {
|
2019-10-16 11:28:52 +02:00
|
|
|
$this->invoice->partial = max(0, min($this->formatValue($this->invoice->partial, 2), $this->invoice->balance));
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
private function calculateTotals()
|
|
|
|
{
|
|
|
|
$this->total += $this->total_taxes;
|
2019-10-16 11:28:52 +02:00
|
|
|
|
2019-10-17 02:25:57 +02:00
|
|
|
return $this;
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|
|
|
|
|
2021-04-28 03:18:27 +02:00
|
|
|
/**
|
|
|
|
* Allow us to get the entity without persisting it
|
|
|
|
* @return Invoice the temp
|
|
|
|
*/
|
|
|
|
public function getTempEntity()
|
|
|
|
{
|
|
|
|
$this->setCalculatedAttributes();
|
2022-06-21 11:57:17 +02:00
|
|
|
|
2021-04-28 03:18:27 +02:00
|
|
|
return $this->invoice;
|
|
|
|
}
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
public function getInvoice()
|
|
|
|
{
|
|
|
|
//Build invoice values here and return Invoice
|
|
|
|
$this->setCalculatedAttributes();
|
2021-10-14 08:54:38 +02:00
|
|
|
$this->invoice->saveQuietly();
|
2020-09-06 11:38:10 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
return $this->invoice;
|
|
|
|
}
|
|
|
|
|
2020-02-19 21:44:12 +01:00
|
|
|
public function getQuote()
|
|
|
|
{
|
|
|
|
$this->setCalculatedAttributes();
|
2021-10-14 08:54:38 +02:00
|
|
|
$this->invoice->saveQuietly();
|
2020-09-06 11:38:10 +02:00
|
|
|
|
2020-02-19 21:44:12 +01:00
|
|
|
return $this->invoice;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getCredit()
|
|
|
|
{
|
|
|
|
$this->setCalculatedAttributes();
|
2022-05-31 00:28:32 +02:00
|
|
|
$this->invoice->saveQuietly();
|
|
|
|
|
|
|
|
return $this->invoice;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPurchaseOrder()
|
|
|
|
{
|
|
|
|
$this->setCalculatedAttributes();
|
2021-10-14 08:54:38 +02:00
|
|
|
$this->invoice->saveQuietly();
|
2020-09-06 11:38:10 +02:00
|
|
|
|
2020-02-19 21:44:12 +01:00
|
|
|
return $this->invoice;
|
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
|
2020-10-20 03:30:55 +02:00
|
|
|
public function getRecurringInvoice()
|
|
|
|
{
|
2022-06-06 14:27:17 +02:00
|
|
|
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
|
2020-10-20 03:30:55 +02:00
|
|
|
$this->invoice->total_taxes = $this->getTotalTaxes();
|
2022-06-06 14:27:17 +02:00
|
|
|
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->precision);
|
2020-10-20 03:30:55 +02:00
|
|
|
|
2021-10-14 08:54:38 +02:00
|
|
|
$this->invoice->saveQuietly();
|
2020-10-20 03:30:55 +02:00
|
|
|
|
|
|
|
return $this->invoice;
|
|
|
|
}
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
/**
|
|
|
|
* 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 */
|
|
|
|
|
2020-11-25 11:30:00 +01:00
|
|
|
if ($this->invoice->status_id != Invoice::STATUS_DRAFT) {
|
2020-11-15 09:24:57 +01:00
|
|
|
if ($this->invoice->amount != $this->invoice->balance) {
|
|
|
|
$paid_to_date = $this->invoice->amount - $this->invoice->balance;
|
2019-12-30 22:59:12 +01:00
|
|
|
|
2022-06-06 14:27:17 +02:00
|
|
|
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->precision) - $paid_to_date;
|
2020-11-15 09:24:57 +01:00
|
|
|
} else {
|
2022-06-06 14:27:17 +02:00
|
|
|
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->precision);
|
2020-11-15 09:24:57 +01:00
|
|
|
}
|
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
/* Set new calculated total */
|
2022-06-06 14:27:17 +02:00
|
|
|
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
|
2019-12-30 22:59:12 +01:00
|
|
|
|
|
|
|
$this->invoice->total_taxes = $this->getTotalTaxes();
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getSubTotal()
|
|
|
|
{
|
|
|
|
return $this->sub_total;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setSubTotal($value)
|
|
|
|
{
|
|
|
|
$this->sub_total = $value;
|
2020-09-06 11:38:10 +02:00
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2021-09-15 01:02:25 +02:00
|
|
|
public function getGrossSubTotal()
|
|
|
|
{
|
|
|
|
return $this->gross_sub_total;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setGrossSubTotal($value)
|
|
|
|
{
|
|
|
|
$this->gross_sub_total = $value;
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
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();
|
2019-10-16 11:28:52 +02:00
|
|
|
|
|
|
|
$keys = $this->invoice_items->getGroupedTaxes()->pluck('key')->unique();
|
|
|
|
|
|
|
|
$values = $this->invoice_items->getGroupedTaxes();
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
foreach ($keys as $key) {
|
|
|
|
$tax_name = $values->filter(function ($value, $k) use ($key) {
|
2019-10-16 11:28:52 +02:00
|
|
|
return $value['key'] == $key;
|
|
|
|
})->pluck('tax_name')->first();
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
$total_line_tax = $values->filter(function ($value, $k) use ($key) {
|
2019-10-16 11:28:52 +02:00
|
|
|
return $value['key'] == $key;
|
|
|
|
})->sum('total');
|
|
|
|
|
2019-10-17 07:09:52 +02:00
|
|
|
//$total_line_tax -= $this->discount($total_line_tax);
|
2019-10-16 11:28:52 +02:00
|
|
|
|
|
|
|
$this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax];
|
|
|
|
|
|
|
|
$this->total_taxes += $total_line_tax;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|
2021-04-10 01:59:19 +02:00
|
|
|
|
|
|
|
private function getSurchargeTaxTotalForKey($key, $rate)
|
|
|
|
{
|
|
|
|
$tax_component = 0;
|
|
|
|
|
2022-06-21 11:57:17 +02:00
|
|
|
if ($this->invoice->custom_surcharge_tax1) {
|
2021-04-10 01:59:19 +02:00
|
|
|
$tax_component += round($this->invoice->custom_surcharge1 * ($rate / 100), 2);
|
|
|
|
}
|
|
|
|
|
2022-06-21 11:57:17 +02:00
|
|
|
if ($this->invoice->custom_surcharge_tax2) {
|
2021-04-10 01:59:19 +02:00
|
|
|
$tax_component += round($this->invoice->custom_surcharge2 * ($rate / 100), 2);
|
|
|
|
}
|
|
|
|
|
2022-06-21 11:57:17 +02:00
|
|
|
if ($this->invoice->custom_surcharge_tax3) {
|
2021-04-10 01:59:19 +02:00
|
|
|
$tax_component += round($this->invoice->custom_surcharge3 * ($rate / 100), 2);
|
|
|
|
}
|
|
|
|
|
2022-06-21 11:57:17 +02:00
|
|
|
if ($this->invoice->custom_surcharge_tax4) {
|
2021-04-10 01:59:19 +02:00
|
|
|
$tax_component += round($this->invoice->custom_surcharge4 * ($rate / 100), 2);
|
|
|
|
}
|
2022-06-21 11:57:17 +02:00
|
|
|
|
2021-04-10 01:59:19 +02:00
|
|
|
return $tax_component;
|
|
|
|
}
|
|
|
|
|
2019-12-30 22:59:12 +01:00
|
|
|
public function getTaxMap()
|
2022-06-21 11:57:17 +02:00
|
|
|
{
|
2019-12-30 22:59:12 +01:00
|
|
|
return $this->tax_map;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getBalance()
|
|
|
|
{
|
|
|
|
return $this->invoice->balance;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getItemTotalTaxes()
|
|
|
|
{
|
|
|
|
return $this->getTotalTaxes();
|
|
|
|
}
|
2020-10-10 12:57:28 +02:00
|
|
|
|
2020-10-15 11:41:59 +02:00
|
|
|
public function purgeTaxes()
|
|
|
|
{
|
|
|
|
$this->tax_rate1 = 0;
|
|
|
|
$this->tax_name1 = '';
|
|
|
|
|
|
|
|
$this->tax_rate2 = 0;
|
|
|
|
$this->tax_name2 = '';
|
|
|
|
|
|
|
|
$this->tax_rate3 = 0;
|
|
|
|
$this->tax_name3 = '';
|
|
|
|
|
|
|
|
$this->discount = 0;
|
|
|
|
|
|
|
|
$line_items = collect($this->invoice->line_items);
|
|
|
|
|
2020-11-25 11:30:00 +01:00
|
|
|
$items = $line_items->map(function ($item) {
|
2020-10-15 11:41:59 +02:00
|
|
|
$item->tax_rate1 = 0;
|
|
|
|
$item->tax_rate2 = 0;
|
|
|
|
$item->tax_rate3 = 0;
|
|
|
|
$item->tax_name1 = '';
|
|
|
|
$item->tax_name2 = '';
|
|
|
|
$item->tax_name3 = '';
|
|
|
|
$item->discount = 0;
|
|
|
|
|
|
|
|
return $item;
|
|
|
|
});
|
|
|
|
|
|
|
|
$this->invoice->line_items = $items->toArray();
|
|
|
|
|
|
|
|
$this->build();
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
2019-12-30 22:59:12 +01:00
|
|
|
}
|