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 ;
2023-04-26 11:25:33 +02:00
use App\Models\Credit ;
2020-10-28 11:10:49 +01:00
use App\Models\Invoice ;
2023-04-26 11:25:33 +02:00
use App\Models\PurchaseOrder ;
2023-10-26 04:57:44 +02:00
use App\Models\Quote ;
2023-04-26 11:25:33 +02:00
use App\Models\RecurringInvoice ;
2023-10-26 04:57:44 +02:00
use App\Models\RecurringQuote ;
use App\Utils\Number ;
2023-04-26 11:25:33 +02:00
use App\Utils\Traits\NumberFormatter ;
2023-10-26 04:57:44 +02:00
use Illuminate\Support\Collection ;
2019-10-16 11:28:52 +02:00
class InvoiceSum
{
2019-12-30 22:59:12 +01:00
use Taxer ;
use CustomValuer ;
use Discounter ;
use NumberFormatter ;
2019-10-16 11:28:52 +02:00
2023-04-26 12:24:10 +02:00
protected RecurringInvoice | Invoice | Quote | Credit | PurchaseOrder | RecurringQuote $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 ;
2024-01-14 05:05:00 +01:00
2024-03-16 02:36:40 +01:00
private $rappen_rounding = false ;
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
*
2023-04-26 13:18:01 +02:00
* @ param RecurringInvoice | Invoice | Quote | Credit | PurchaseOrder | RecurringQuote $invoice ;
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 ;
2024-03-16 02:36:40 +01:00
$this -> rappen_rounding = $this -> invoice -> client -> getSetting ( 'enable_rappen_rounding' );
2022-06-21 11:57:17 +02:00
} else {
2022-06-07 13:07:14 +02:00
$this -> precision = $this -> invoice -> vendor -> currency () -> precision ;
2024-03-16 02:36:40 +01:00
$this -> rappen_rounding = $this -> invoice -> vendor -> getSetting ( 'enable_rappen_rounding' );
2022-06-21 11:57:17 +02:00
}
2021-10-13 06:47:56 +02:00
2024-01-14 05:05:00 +01:00
$this -> tax_map = new Collection ();
2019-12-30 22:59:12 +01:00
}
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
2023-04-26 11:25:33 +02:00
private function calculateLineItems () : self
2019-12-30 22:59:12 +01:00
{
$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
2023-04-26 11:25:33 +02:00
private function calculateDiscount () : self
2019-12-30 22:59:12 +01:00
{
$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
2023-04-26 11:25:33 +02:00
private function calculateCustomValues () : self
2019-12-30 22:59:12 +01:00
{
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
}
2023-04-26 11:25:33 +02:00
private function calculateInvoiceTaxes () : self
2019-12-30 22:59:12 +01:00
{
2024-03-02 00:14:36 +01:00
if ( is_string ( $this -> invoice -> tax_name1 ) && strlen ( $this -> invoice -> tax_name1 ) >= 2 ) {
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
}
2024-03-02 00:14:36 +01:00
if ( is_string ( $this -> invoice -> tax_name2 ) && strlen ( $this -> invoice -> tax_name2 ) >= 2 ) {
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
}
2024-03-02 00:14:36 +01:00
if ( is_string ( $this -> invoice -> tax_name3 ) && strlen ( $this -> invoice -> tax_name3 ) >= 2 ) {
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 .
*/
2023-04-26 11:25:33 +02:00
private function calculateBalance () : self
2019-12-30 22:59:12 +01:00
{
$this -> setCalculatedAttributes ();
return $this ;
}
2023-04-26 11:25:33 +02:00
private function calculatePartial () : self
2019-12-30 22:59:12 +01:00
{
2020-09-06 11:38:10 +02:00
if ( ! isset ( $this -> invoice -> id ) && isset ( $this -> invoice -> partial )) {
2023-04-26 11:25:33 +02:00
$this -> invoice -> partial = max ( 0 , min ( Number :: roundValue ( $this -> invoice -> partial , 2 ), $this -> invoice -> balance ));
2019-10-16 11:28:52 +02:00
}
return $this ;
2019-12-30 22:59:12 +01:00
}
2019-10-16 11:28:52 +02:00
2023-04-26 11:25:33 +02:00
private function calculateTotals () : self
2019-12-30 22:59:12 +01:00
{
$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 .
*/
2023-04-26 11:25:33 +02:00
private function setCalculatedAttributes () : self
2019-12-30 22:59:12 +01:00
{
/* 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 ) {
2024-02-20 22:46:52 +01:00
// $paid_to_date = $this->invoice->amount - $this->invoice->balance;
2019-12-30 22:59:12 +01:00
2024-02-21 21:45:06 +01:00
$this -> invoice -> balance = Number :: roundValue ( $this -> getTotal (), $this -> precision ) - $this -> invoice -> paid_to_date ; //21-02-2024 cannot use the calculated $paid_to_date here as it could send the balance backward.
2020-11-15 09:24:57 +01:00
} else {
2023-04-26 11:25:33 +02:00
$this -> invoice -> balance = Number :: roundValue ( $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
2024-03-16 02:36:40 +01:00
if ( $this -> rappen_rounding )
$this -> invoice -> amount = $this -> roundRappen ( $this -> invoice -> amount );
2019-12-30 22:59:12 +01:00
$this -> invoice -> total_taxes = $this -> getTotalTaxes ();
return $this ;
}
2024-03-16 02:36:40 +01:00
function roundRappen ( $value ) : float
{
return round ( $value / . 05 , 0 ) * . 05 ;
}
2019-12-30 22:59:12 +01:00
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 ;
}
2023-04-26 11:25:33 +02:00
public function setGrossSubTotal ( $value ) : self
2021-09-15 01:02:25 +02:00
{
$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 ;
}
2023-04-05 11:22:41 +02:00
public function getTotalSurcharges ()
{
return $this -> total_custom_values ;
}
2023-04-26 11:25:33 +02:00
public function setTaxMap () : self
2019-12-30 22:59:12 +01:00
{
2023-09-12 09:06:40 +02:00
if ( $this -> invoice -> is_amount_discount ) {
2019-12-30 22:59:12 +01:00
$this -> invoice_items -> calcTaxesWithAmountDiscount ();
2023-09-12 09:06:40 +02:00
$this -> invoice -> line_items = $this -> invoice_items -> getLineItems ();
2019-12-30 22:59:12 +01:00
}
$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' );
$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
2023-04-26 11:25:33 +02:00
public function purgeTaxes () : self
2020-10-15 11:41:59 +02:00
{
$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
}