mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-03 23:07:32 -05:00 
			
		
		
		
	Merge branch 'v5-develop' of https://github.com/turbo124/invoiceninja into v5-develop
This commit is contained in:
		
						commit
						dcb44314b8
					
				
							
								
								
									
										43
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								README.md
									
									
									
									
									
								
							@ -1,5 +1,5 @@
 | 
				
			|||||||
<p align="center">
 | 
					<p align="center">
 | 
				
			||||||
    <img src="https://raw.githubusercontent.com/hillelcoren/invoice-ninja/master/public/images/round_logo.png" alt="Sublime's custom image"/>
 | 
					<a href ="https://www.youtube.com/watch?v=CxGxXiotv0I" target="_blank" title="Invoice Ninja Overview Video"><img src="https://raw.githubusercontent.com/hillelcoren/invoice-ninja/master/public/images/round_logo.png" alt="Sublime's custom image"/></a>
 | 
				
			||||||
</p>
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||

 | 
					
 | 
				
			||||||
@ -8,25 +8,30 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Invoice Ninja 5
 | 
					# Invoice Ninja 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [Hosted](https://www.invoiceninja.com) | [Self-Hosted](https://www.invoiceninja.org)
 | 
					Invoice Ninja Version 5 is here! We've taken the best parts of version 4 and added the most requested features to create an invoicing application like no other. Check the [Invoice Ninja YouTube Channel](https://www.youtube.com/@appinvoiceninja) to get up to speed, or try the [Demo](https://react.invoicing.co/demo) now.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Join us on [Slack](http://slack.invoiceninja.com), [Discord](https://discord.gg/ZwEdtfCwXA), [Support Forum](https://forum.invoiceninja.com)
 | 
					**Choose your setup**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Introduction
 | 
					- [Hosted](https://www.invoiceninja.com): Our hosted version is a Software as a Service (SaaS) solution. You're up and running in under 5 minutes, with no need to worry about hosting or server infrastructure.
 | 
				
			||||||
 | 
					- [Self-Hosted](https://www.invoiceninja.org): For those who prefer to manage their own hosting and server infrastructure. This version gives you full control and flexibility.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Version 5 of Invoice Ninja is here!
 | 
					All Pro and Enterprise features from the hosted app are included in the open-source code. We offer a $30 per year white-label license to remove the Invoice Ninja branding from client-facing parts of the app.  
 | 
				
			||||||
We took the best parts of version 4 and add the most requested features 
 | 
					 | 
				
			||||||
to produce a invoicing application like no other. 
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
All Pro and Enterprise features from the hosted app are included in the open code.
 | 
					#### Get social with us
 | 
				
			||||||
We offer a $30 per year white-label license to remove the Invoice Ninja branding from client facing parts of the app.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
* [Videos](https://www.youtube.com/@appinvoiceninja)
 | 
					 | 
				
			||||||
* [API Documentation](https://api-docs.invoicing.co/)
 | 
					 | 
				
			||||||
* [APP Documentation](https://invoiceninja.github.io/)
 | 
					 | 
				
			||||||
* [Support Forum](https://forum.invoiceninja.com)
 | 
					* [Support Forum](https://forum.invoiceninja.com)
 | 
				
			||||||
 | 
					* [Slack](http://slack.invoiceninja.com)
 | 
				
			||||||
 | 
					* [Discord](https://discord.gg/ZwEdtfCwXA)
 | 
				
			||||||
 | 
					* [Instagram](https://www.instagram.com/appinvoiceninja)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Setup
 | 
					#### Documentation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [Invoice Ninja - API](https://api-docs.invoicing.co/)
 | 
				
			||||||
 | 
					* [Invoice Ninja - Developer Guide](https://invoiceninja.github.io/en/developer-guide/)
 | 
				
			||||||
 | 
					* [Invoice Ninja - User Guide](https://invoiceninja.github.io/en/user-guide/)
 | 
				
			||||||
 | 
					* [Invoice Ninja - Self-Hosted Installation Guide](https://invoiceninja.github.io/en/self-host-installation/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Installation Options and Clients
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Mobile Apps
 | 
					### Mobile Apps
 | 
				
			||||||
* [iPhone](https://apps.apple.com/app/id1503970375?platform=iphone)
 | 
					* [iPhone](https://apps.apple.com/app/id1503970375?platform=iphone)
 | 
				
			||||||
@ -39,16 +44,21 @@ We offer a $30 per year white-label license to remove the Invoice Ninja branding
 | 
				
			|||||||
* [Linux - Snap](https://snapcraft.io/invoiceninja)
 | 
					* [Linux - Snap](https://snapcraft.io/invoiceninja)
 | 
				
			||||||
* [Linux - Flatpak](https://flathub.org/apps/com.invoiceninja.InvoiceNinja)
 | 
					* [Linux - Flatpak](https://flathub.org/apps/com.invoiceninja.InvoiceNinja)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Installation Options
 | 
					### Self-Hosted Server Installation 
 | 
				
			||||||
 | 
					**Note:** The self-hosted options do support the desktop and mobile apps.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* [Server or VM](https://invoiceninja.github.io/en/self-host-installation/)
 | 
				
			||||||
* [Docker File](https://hub.docker.com/r/invoiceninja/invoiceninja/)
 | 
					* [Docker File](https://hub.docker.com/r/invoiceninja/invoiceninja/)
 | 
				
			||||||
* [Cloudron](https://cloudron.io/store/com.invoiceninja.cloudronapp.html)
 | 
					* [Cloudron](https://www.cloudron.io/store/com.invoiceninja.cloudronapp2.html)
 | 
				
			||||||
* [Softaculous](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja)
 | 
					* [Softaculous](https://www.softaculous.com/apps/ecommerce/Invoice_Ninja)
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
### Recommended Providers
 | 
					### Recommended Providers
 | 
				
			||||||
* [Stripe](https://stripe.com/)
 | 
					* [Stripe](https://stripe.com/)
 | 
				
			||||||
* [Postmark](https://postmarkapp.com/)
 | 
					* [Postmark](https://postmarkapp.com/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Quick Hosting Setup
 | 
					## [Advanced] Quick Hosting Setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition to the official [Invoice Ninja - Self-Hosted Installation Guide](https://invoiceninja.github.io/en/self-host-installation/) we have a few commands for you.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```sh
 | 
					```sh
 | 
				
			||||||
git clone --single-branch --branch v5-stable https://github.com/invoiceninja/invoiceninja.git
 | 
					git clone --single-branch --branch v5-stable https://github.com/invoiceninja/invoiceninja.git
 | 
				
			||||||
@ -84,6 +94,7 @@ pass: password
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
## Developers Guide
 | 
					## Developers Guide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition to the official [Invoice Ninja - Developer Guide](https://invoiceninja.github.io/en/developer-guide/) we've got your back with some insights.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### App Design
 | 
					### App Design
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1258,7 +1258,7 @@ class BaseExport
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $date_range = $this->input['date_range'];
 | 
					        $date_range = $this->input['date_range'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (array_key_exists('date_key', $this->input) && strlen($this->input['date_key']) > 1 && ($table_name && $this->columnExists($table_name, $this->input['date_key']))) {
 | 
					        if (array_key_exists('date_key', $this->input) && strlen($this->input['date_key'] ?? '') > 1 && ($table_name && $this->columnExists($table_name, $this->input['date_key']))) {
 | 
				
			||||||
            $this->date_key = $this->input['date_key'];
 | 
					            $this->date_key = $this->input['date_key'];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,7 @@ class TaskExport extends BaseExport
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    private $entity_transformer;
 | 
					    private $entity_transformer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public string $date_key = 'created_at';
 | 
					    public string $date_key = 'calculated_start_date';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private string $date_format = 'Y-m-d';
 | 
					    private string $date_format = 'Y-m-d';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -155,11 +155,13 @@ class BankTransactionFilters extends QueryFilters
 | 
				
			|||||||
        $dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
 | 
					        $dir = ($sort_col[1] == 'asc') ? 'asc' : 'desc';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($sort_col[0] == 'deposit') {
 | 
					        if ($sort_col[0] == 'deposit') {
 | 
				
			||||||
            return $this->builder->where('base_type', 'CREDIT')->orderBy('amount', $dir);
 | 
					            return $this->builder->orderByRaw("(CASE WHEN base_type = 'CREDIT' THEN amount END) $dir")->orderBy('amount', $dir);
 | 
				
			||||||
 | 
					            // return $this->builder->where('base_type', 'CREDIT')->orderBy('amount', $dir);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($sort_col[0] == 'withdrawal') {
 | 
					        if ($sort_col[0] == 'withdrawal') {
 | 
				
			||||||
            return $this->builder->where('base_type', 'DEBIT')->orderBy('amount', $dir);
 | 
					            return $this->builder->orderByRaw("(CASE WHEN base_type = 'DEBIT' THEN amount END) $dir")->orderBy('amount', $dir);
 | 
				
			||||||
 | 
					            // return $this->builder->where('base_type', 'DEBIT')->orderBy('amount', $dir);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($sort_col[0] == 'status') {
 | 
					        if ($sort_col[0] == 'status') {
 | 
				
			||||||
 | 
				
			|||||||
@ -11,16 +11,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace App\Helpers\Invoice;
 | 
					namespace App\Helpers\Invoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\DataMapper\BaseSettings;
 | 
					use App\Models\Quote;
 | 
				
			||||||
use App\DataMapper\InvoiceItem;
 | 
					use App\Utils\Number;
 | 
				
			||||||
use App\DataMapper\Tax\RuleInterface;
 | 
					 | 
				
			||||||
use App\Models\Client;
 | 
					use App\Models\Client;
 | 
				
			||||||
use App\Models\Credit;
 | 
					use App\Models\Credit;
 | 
				
			||||||
 | 
					use App\Models\Vendor;
 | 
				
			||||||
use App\Models\Invoice;
 | 
					use App\Models\Invoice;
 | 
				
			||||||
use App\Models\PurchaseOrder;
 | 
					use App\Models\PurchaseOrder;
 | 
				
			||||||
use App\Models\Quote;
 | 
					 | 
				
			||||||
use App\Models\RecurringInvoice;
 | 
					 | 
				
			||||||
use App\Models\RecurringQuote;
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use App\DataMapper\InvoiceItem;
 | 
				
			||||||
 | 
					use App\DataMapper\BaseSettings;
 | 
				
			||||||
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
 | 
					use App\DataMapper\Tax\RuleInterface;
 | 
				
			||||||
use App\Utils\Traits\NumberFormatter;
 | 
					use App\Utils\Traits\NumberFormatter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InvoiceItemSum
 | 
					class InvoiceItemSum
 | 
				
			||||||
@ -120,7 +122,7 @@ class InvoiceItemSum
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private $tax_collection;
 | 
					    private $tax_collection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ?Client $client;
 | 
					    private Client | Vendor $client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private bool $calc_tax = false;
 | 
					    private bool $calc_tax = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -131,10 +133,10 @@ class InvoiceItemSum
 | 
				
			|||||||
        $this->tax_collection = collect([]);
 | 
					        $this->tax_collection = collect([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->invoice = $invoice;
 | 
					        $this->invoice = $invoice;
 | 
				
			||||||
 | 
					        $this->client = $invoice->client ?? $invoice->vendor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($this->invoice->client) {
 | 
					        if ($this->invoice->client) {
 | 
				
			||||||
            $this->currency = $this->invoice->client->currency();
 | 
					            $this->currency = $this->invoice->client->currency();
 | 
				
			||||||
            $this->client = $this->invoice->client;
 | 
					 | 
				
			||||||
            $this->shouldCalculateTax();
 | 
					            $this->shouldCalculateTax();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            $this->currency = $this->invoice->vendor->currency();
 | 
					            $this->currency = $this->invoice->vendor->currency();
 | 
				
			||||||
@ -313,7 +315,7 @@ class InvoiceItemSum
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $key = str_replace(' ', '', $tax_name.$tax_rate);
 | 
					        $key = str_replace(' ', '', $tax_name.$tax_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $group_tax = ['key' => $key, 'total' => $tax_total, 'tax_name' => $tax_name.' '.floatval($tax_rate).'%'];
 | 
					        $group_tax = ['key' => $key, 'total' => $tax_total, 'tax_name' => $tax_name.' '.Number::formatValueNoTrailingZeroes(floatval($tax_rate), $this->client).'%'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->tax_collection->push(collect($group_tax));
 | 
					        $this->tax_collection->push(collect($group_tax));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -11,14 +11,16 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace App\Helpers\Invoice;
 | 
					namespace App\Helpers\Invoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\DataMapper\Tax\RuleInterface;
 | 
					use App\Models\Quote;
 | 
				
			||||||
 | 
					use App\Utils\Number;
 | 
				
			||||||
use App\Models\Client;
 | 
					use App\Models\Client;
 | 
				
			||||||
use App\Models\Credit;
 | 
					use App\Models\Credit;
 | 
				
			||||||
 | 
					use App\Models\Vendor;
 | 
				
			||||||
use App\Models\Invoice;
 | 
					use App\Models\Invoice;
 | 
				
			||||||
use App\Models\PurchaseOrder;
 | 
					use App\Models\PurchaseOrder;
 | 
				
			||||||
use App\Models\Quote;
 | 
					 | 
				
			||||||
use App\Models\RecurringInvoice;
 | 
					 | 
				
			||||||
use App\Models\RecurringQuote;
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
 | 
					use App\DataMapper\Tax\RuleInterface;
 | 
				
			||||||
use App\Utils\Traits\NumberFormatter;
 | 
					use App\Utils\Traits\NumberFormatter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InvoiceItemSumInclusive
 | 
					class InvoiceItemSumInclusive
 | 
				
			||||||
@ -109,7 +111,7 @@ class InvoiceItemSumInclusive
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private bool $calc_tax = false;
 | 
					    private bool $calc_tax = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private ?Client $client;
 | 
					    private Client | Vendor $client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private RuleInterface $rule;
 | 
					    private RuleInterface $rule;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -118,10 +120,10 @@ class InvoiceItemSumInclusive
 | 
				
			|||||||
        $this->tax_collection = collect([]);
 | 
					        $this->tax_collection = collect([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->invoice = $invoice;
 | 
					        $this->invoice = $invoice;
 | 
				
			||||||
 | 
					        $this->client = $invoice->client ?? $invoice->vendor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($this->invoice->client) {
 | 
					        if ($this->invoice->client) {
 | 
				
			||||||
            $this->currency = $this->invoice->client->currency();
 | 
					            $this->currency = $this->invoice->client->currency();
 | 
				
			||||||
            $this->client = $this->invoice->client;
 | 
					 | 
				
			||||||
            $this->shouldCalculateTax();
 | 
					            $this->shouldCalculateTax();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            $this->currency = $this->invoice->vendor->currency();
 | 
					            $this->currency = $this->invoice->vendor->currency();
 | 
				
			||||||
@ -265,7 +267,7 @@ class InvoiceItemSumInclusive
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $key = str_replace(' ', '', $tax_name.$tax_rate);
 | 
					        $key = str_replace(' ', '', $tax_name.$tax_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $group_tax = ['key' => $key, 'total' => $tax_total, 'tax_name' => $tax_name.' '.$tax_rate.'%'];
 | 
					        $group_tax = ['key' => $key, 'total' => $tax_total, 'tax_name' => $tax_name.' '.Number::formatValueNoTrailingZeroes(floatval($tax_rate), $this->client).'%'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->tax_collection->push(collect($group_tax));
 | 
					        $this->tax_collection->push(collect($group_tax));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -11,12 +11,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace App\Helpers\Invoice;
 | 
					namespace App\Helpers\Invoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Client;
 | 
				
			||||||
use App\Models\Credit;
 | 
					use App\Models\Credit;
 | 
				
			||||||
use App\Models\Invoice;
 | 
					use App\Models\Invoice;
 | 
				
			||||||
use App\Models\PurchaseOrder;
 | 
					use App\Models\PurchaseOrder;
 | 
				
			||||||
use App\Models\Quote;
 | 
					use App\Models\Quote;
 | 
				
			||||||
use App\Models\RecurringInvoice;
 | 
					use App\Models\RecurringInvoice;
 | 
				
			||||||
use App\Models\RecurringQuote;
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
 | 
					use App\Models\Vendor;
 | 
				
			||||||
use App\Utils\Number;
 | 
					use App\Utils\Number;
 | 
				
			||||||
use App\Utils\Traits\NumberFormatter;
 | 
					use App\Utils\Traits\NumberFormatter;
 | 
				
			||||||
use Illuminate\Support\Collection;
 | 
					use Illuminate\Support\Collection;
 | 
				
			||||||
@ -50,6 +52,8 @@ class InvoiceSum
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private $precision;
 | 
					    private $precision;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Client | Vendor $client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public InvoiceItemSum $invoice_items;
 | 
					    public InvoiceItemSum $invoice_items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private $rappen_rounding = false;
 | 
					    private $rappen_rounding = false;
 | 
				
			||||||
@ -60,18 +64,15 @@ class InvoiceSum
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct($invoice)
 | 
					    public function __construct($invoice)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->invoice = $invoice;
 | 
					        $this->invoice = $invoice;
 | 
				
			||||||
 | 
					        $this->client = $invoice->client ?? $invoice->vendor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($this->invoice->client) {
 | 
					        $this->precision = $this->client->currency()->precision;
 | 
				
			||||||
            $this->precision = $this->invoice->client->currency()->precision;
 | 
					        $this->rappen_rounding = $this->client->getSetting('enable_rappen_rounding');
 | 
				
			||||||
            $this->rappen_rounding = $this->invoice->client->getSetting('enable_rappen_rounding');
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            $this->precision = $this->invoice->vendor->currency()->precision;
 | 
					 | 
				
			||||||
            $this->rappen_rounding = $this->invoice->vendor->getSetting('enable_rappen_rounding');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->tax_map = new Collection();
 | 
					        $this->tax_map = new Collection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function build()
 | 
					    public function build()
 | 
				
			||||||
@ -131,7 +132,7 @@ class InvoiceSum
 | 
				
			|||||||
            $tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name1, $this->invoice->tax_rate1);
 | 
					            $tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name1, $this->invoice->tax_rate1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $this->total_taxes += $tax;
 | 
					            $this->total_taxes += $tax;
 | 
				
			||||||
            $this->total_tax_map[] = ['name' => $this->invoice->tax_name1.' '.floatval($this->invoice->tax_rate1).'%', 'total' => $tax];
 | 
					            $this->total_tax_map[] = ['name' => $this->invoice->tax_name1.' '.Number::formatValueNoTrailingZeroes(floatval($this->invoice->tax_rate1), $this->client).'%', 'total' => $tax];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (is_string($this->invoice->tax_name2) && strlen($this->invoice->tax_name2) >= 2) {
 | 
					        if (is_string($this->invoice->tax_name2) && strlen($this->invoice->tax_name2) >= 2) {
 | 
				
			||||||
@ -139,7 +140,7 @@ class InvoiceSum
 | 
				
			|||||||
            $tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name2, $this->invoice->tax_rate2);
 | 
					            $tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name2, $this->invoice->tax_rate2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $this->total_taxes += $tax;
 | 
					            $this->total_taxes += $tax;
 | 
				
			||||||
            $this->total_tax_map[] = ['name' => $this->invoice->tax_name2.' '.floatval($this->invoice->tax_rate2).'%', 'total' => $tax];
 | 
					            $this->total_tax_map[] = ['name' => $this->invoice->tax_name2.' '.Number::formatValueNoTrailingZeroes(floatval($this->invoice->tax_rate2), $this->client).'%', 'total' => $tax];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (is_string($this->invoice->tax_name3) && strlen($this->invoice->tax_name3) >= 2) {
 | 
					        if (is_string($this->invoice->tax_name3) && strlen($this->invoice->tax_name3) >= 2) {
 | 
				
			||||||
@ -147,7 +148,7 @@ class InvoiceSum
 | 
				
			|||||||
            $tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name3, $this->invoice->tax_rate3);
 | 
					            $tax += $this->getSurchargeTaxTotalForKey($this->invoice->tax_name3, $this->invoice->tax_rate3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $this->total_taxes += $tax;
 | 
					            $this->total_taxes += $tax;
 | 
				
			||||||
            $this->total_tax_map[] = ['name' => $this->invoice->tax_name3.' '.floatval($this->invoice->tax_rate3).'%', 'total' => $tax];
 | 
					            $this->total_tax_map[] = ['name' => $this->invoice->tax_name3.' '.Number::formatValueNoTrailingZeroes(floatval($this->invoice->tax_rate3), $this->client).'%', 'total' => $tax];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,10 @@
 | 
				
			|||||||
namespace App\Helpers\Invoice;
 | 
					namespace App\Helpers\Invoice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\Models\Quote;
 | 
					use App\Models\Quote;
 | 
				
			||||||
 | 
					use App\Utils\Number;
 | 
				
			||||||
 | 
					use App\Models\Client;
 | 
				
			||||||
use App\Models\Credit;
 | 
					use App\Models\Credit;
 | 
				
			||||||
 | 
					use App\Models\Vendor;
 | 
				
			||||||
use App\Models\Invoice;
 | 
					use App\Models\Invoice;
 | 
				
			||||||
use App\Models\PurchaseOrder;
 | 
					use App\Models\PurchaseOrder;
 | 
				
			||||||
use App\Models\RecurringQuote;
 | 
					use App\Models\RecurringQuote;
 | 
				
			||||||
@ -49,6 +52,8 @@ class InvoiceSumInclusive
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private $rappen_rounding = false;
 | 
					    private $rappen_rounding = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Client | Vendor $client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public InvoiceItemSumInclusive $invoice_items;
 | 
					    public InvoiceItemSumInclusive $invoice_items;
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Constructs the object with Invoice and Settings object.
 | 
					     * Constructs the object with Invoice and Settings object.
 | 
				
			||||||
@ -58,14 +63,10 @@ class InvoiceSumInclusive
 | 
				
			|||||||
    public function __construct($invoice)
 | 
					    public function __construct($invoice)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->invoice = $invoice;
 | 
					        $this->invoice = $invoice;
 | 
				
			||||||
 | 
					        $this->client = $invoice->client ?? $invoice->vendor;
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        if ($this->invoice->client) {
 | 
					        $this->precision = $this->client->currency()->precision;
 | 
				
			||||||
            $this->precision = $this->invoice->client->currency()->precision;
 | 
					        $this->rappen_rounding = $this->client->getSetting('enable_rappen_rounding');
 | 
				
			||||||
            $this->rappen_rounding = $this->invoice->client->getSetting('enable_rappen_rounding');
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            $this->precision = $this->invoice->vendor->currency()->precision;
 | 
					 | 
				
			||||||
            $this->rappen_rounding = $this->invoice->vendor->getSetting('enable_rappen_rounding');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->tax_map = new Collection();
 | 
					        $this->tax_map = new Collection();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -157,19 +158,19 @@ class InvoiceSumInclusive
 | 
				
			|||||||
            $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate1, $amount);
 | 
					            $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate1, $amount);
 | 
				
			||||||
            $this->total_taxes += $tax;
 | 
					            $this->total_taxes += $tax;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $this->total_tax_map[] = ['name' => $this->invoice->tax_name1.' '.floatval($this->invoice->tax_rate1).'%', 'total' => $tax];
 | 
					            $this->total_tax_map[] = ['name' => $this->invoice->tax_name1.' '.Number::formatValueNoTrailingZeroes(floatval($this->invoice->tax_rate1), $this->client).'%', 'total' => $tax];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (is_string($this->invoice->tax_name2) && strlen($this->invoice->tax_name2) > 1) {
 | 
					        if (is_string($this->invoice->tax_name2) && strlen($this->invoice->tax_name2) > 1) {
 | 
				
			||||||
            $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate2, $amount);
 | 
					            $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate2, $amount);
 | 
				
			||||||
            $this->total_taxes += $tax;
 | 
					            $this->total_taxes += $tax;
 | 
				
			||||||
            $this->total_tax_map[] = ['name' => $this->invoice->tax_name2.' '.floatval($this->invoice->tax_rate2).'%', 'total' => $tax];
 | 
					            $this->total_tax_map[] = ['name' => $this->invoice->tax_name2.' '.Number::formatValueNoTrailingZeroes(floatval($this->invoice->tax_rate2), $this->client).'%', 'total' => $tax];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (is_string($this->invoice->tax_name3) && strlen($this->invoice->tax_name3) > 1) {
 | 
					        if (is_string($this->invoice->tax_name3) && strlen($this->invoice->tax_name3) > 1) {
 | 
				
			||||||
            $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate3, $amount);
 | 
					            $tax = $this->calcInclusiveLineTax($this->invoice->tax_rate3, $amount);
 | 
				
			||||||
            $this->total_taxes += $tax;
 | 
					            $this->total_taxes += $tax;
 | 
				
			||||||
            $this->total_tax_map[] = ['name' => $this->invoice->tax_name3.' '.floatval($this->invoice->tax_rate3).'%', 'total' => $tax];
 | 
					            $this->total_tax_map[] = ['name' => $this->invoice->tax_name3.' '.Number::formatValueNoTrailingZeroes(floatval($this->invoice->tax_rate3), $this->client).'%', 'total' => $tax];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
 | 
				
			|||||||
@ -153,7 +153,7 @@ class BrowserPay implements MethodInterface
 | 
				
			|||||||
            $this->stripe->client->company,
 | 
					            $this->stripe->client->company,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id)]);
 | 
					        return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -160,7 +160,7 @@ class CreditCard
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id)]);
 | 
					        return redirect()->route('client.payments.show', ['payment' => $payment->hashed_id]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function processUnsuccessfulPayment($server_response)
 | 
					    public function processUnsuccessfulPayment($server_response)
 | 
				
			||||||
 | 
				
			|||||||
@ -739,7 +739,7 @@ class PdfBuilder
 | 
				
			|||||||
                if ($item->is_amount_discount) {
 | 
					                if ($item->is_amount_discount) {
 | 
				
			||||||
                    $data[$key][$table_type.'.discount'] = $this->service->config->formatMoney($item->discount);
 | 
					                    $data[$key][$table_type.'.discount'] = $this->service->config->formatMoney($item->discount);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    $data[$key][$table_type.'.discount'] = floatval($item->discount).'%';
 | 
					                    $data[$key][$table_type.'.discount'] = $this->service->config->formatValueNoTrailingZeroes(floatval($item->discount)).'%';
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                $data[$key][$table_type.'.discount'] = '';
 | 
					                $data[$key][$table_type.'.discount'] = '';
 | 
				
			||||||
@ -749,17 +749,17 @@ class PdfBuilder
 | 
				
			|||||||
            // but that's no longer necessary.
 | 
					            // but that's no longer necessary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (isset($item->tax_rate1)) {
 | 
					            if (isset($item->tax_rate1)) {
 | 
				
			||||||
                $data[$key][$table_type.'.tax_rate1'] = floatval($item->tax_rate1).'%';
 | 
					                $data[$key][$table_type.'.tax_rate1'] = $this->service->config->formatValueNoTrailingZeroes(floatval($item->tax_rate1)).'%';
 | 
				
			||||||
                $data[$key][$table_type.'.tax1'] = &$data[$key][$table_type.'.tax_rate1'];
 | 
					                $data[$key][$table_type.'.tax1'] = &$data[$key][$table_type.'.tax_rate1'];
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (isset($item->tax_rate2)) {
 | 
					            if (isset($item->tax_rate2)) {
 | 
				
			||||||
                $data[$key][$table_type.'.tax_rate2'] = floatval($item->tax_rate2).'%';
 | 
					                $data[$key][$table_type.'.tax_rate2'] = $this->service->config->formatValueNoTrailingZeroes(floatval($item->tax_rate2)).'%';
 | 
				
			||||||
                $data[$key][$table_type.'.tax2'] = &$data[$key][$table_type.'.tax_rate2'];
 | 
					                $data[$key][$table_type.'.tax2'] = &$data[$key][$table_type.'.tax_rate2'];
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (isset($item->tax_rate3)) {
 | 
					            if (isset($item->tax_rate3)) {
 | 
				
			||||||
                $data[$key][$table_type.'.tax_rate3'] = floatval($item->tax_rate3).'%';
 | 
					                $data[$key][$table_type.'.tax_rate3'] = $this->service->config->formatValueNoTrailingZeroes(floatval($item->tax_rate3)).'%';
 | 
				
			||||||
                $data[$key][$table_type.'.tax3'] = &$data[$key][$table_type.'.tax_rate3'];
 | 
					                $data[$key][$table_type.'.tax3'] = &$data[$key][$table_type.'.tax_rate3'];
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								composer.lock
									
									
									
										generated
									
									
									
								
							@ -16199,16 +16199,16 @@
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "name": "friendsofphp/php-cs-fixer",
 | 
					            "name": "friendsofphp/php-cs-fixer",
 | 
				
			||||||
            "version": "v3.60.0",
 | 
					            "version": "v3.61.1",
 | 
				
			||||||
            "source": {
 | 
					            "source": {
 | 
				
			||||||
                "type": "git",
 | 
					                "type": "git",
 | 
				
			||||||
                "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
 | 
					                "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
 | 
				
			||||||
                "reference": "e595e4e070d17c5d42ed8c4206f630fcc5f401a4"
 | 
					                "reference": "94a87189f55814e6cabca2d9a33b06de384a2ab8"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "dist": {
 | 
					            "dist": {
 | 
				
			||||||
                "type": "zip",
 | 
					                "type": "zip",
 | 
				
			||||||
                "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/e595e4e070d17c5d42ed8c4206f630fcc5f401a4",
 | 
					                "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/94a87189f55814e6cabca2d9a33b06de384a2ab8",
 | 
				
			||||||
                "reference": "e595e4e070d17c5d42ed8c4206f630fcc5f401a4",
 | 
					                "reference": "94a87189f55814e6cabca2d9a33b06de384a2ab8",
 | 
				
			||||||
                "shasum": ""
 | 
					                "shasum": ""
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "require": {
 | 
					            "require": {
 | 
				
			||||||
@ -16290,7 +16290,7 @@
 | 
				
			|||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "support": {
 | 
					            "support": {
 | 
				
			||||||
                "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
 | 
					                "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
 | 
				
			||||||
                "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.60.0"
 | 
					                "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.61.1"
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            "funding": [
 | 
					            "funding": [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@ -16298,7 +16298,7 @@
 | 
				
			|||||||
                    "type": "github"
 | 
					                    "type": "github"
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            "time": "2024-07-25T09:26:51+00:00"
 | 
					            "time": "2024-07-31T14:33:15+00:00"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "name": "hamcrest/hamcrest-php",
 | 
					            "name": "hamcrest/hamcrest-php",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user