mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Refactor for taxes
This commit is contained in:
parent
046a72326e
commit
d52d2f1f37
@ -11,6 +11,9 @@
|
||||
|
||||
namespace App\DataMapper\Tax;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
|
||||
interface RuleInterface
|
||||
{
|
||||
public function tax();
|
||||
@ -27,5 +30,11 @@ interface RuleInterface
|
||||
|
||||
public function taxPhysical();
|
||||
|
||||
public function taxReduced();
|
||||
|
||||
public function default();
|
||||
|
||||
public function setClient(Client $client);
|
||||
|
||||
public function setTaxData(Response $tax_data);
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\DataMapper\Tax\de;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Product;
|
||||
use App\DataMapper\Tax\RuleInterface;
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
@ -100,10 +101,24 @@ class Rule implements RuleInterface
|
||||
public string $tax_name3 = '';
|
||||
public float $tax_rate3 = 0;
|
||||
|
||||
protected ?Client $client;
|
||||
|
||||
public function __construct(public Response $tax_data)
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function setClient(Client $client): self
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTaxData(Response $tax_data): self
|
||||
{
|
||||
$this->tax_data = $tax_data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function tax(): self
|
||||
@ -126,12 +141,21 @@ class Rule implements RuleInterface
|
||||
Product::PRODUCT_TYPE_SERVICE => $this->taxService(),
|
||||
Product::PRODUCT_TYPE_SHIPPING => $this->taxShipping(),
|
||||
Product::PRODUCT_TYPE_PHYSICAL => $this->taxPhysical(),
|
||||
Product::PRODUCT_TYPE_REDUCED_TAX => $this->taxReduced(),
|
||||
default => $this->default(),
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxReduced(): self
|
||||
{
|
||||
$this->tax_rate1 = $this->vat_reduced_rate;
|
||||
$this->tax_name1 = 'VAT';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxExempt(): self
|
||||
{
|
||||
$this->tax_name1 = '';
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace App\DataMapper\Tax\us;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Product;
|
||||
use App\DataMapper\Tax\RuleInterface;
|
||||
use App\DataMapper\Tax\ZipTax\Response;
|
||||
@ -80,10 +81,26 @@ class Rule implements RuleInterface
|
||||
public string $tax_name3 = '';
|
||||
public float $tax_rate3 = 0;
|
||||
|
||||
public function __construct(public Response $tax_data)
|
||||
public ?Client $client;
|
||||
|
||||
public ?Response $tax_data;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function setTaxData(Response $tax_data): self
|
||||
{
|
||||
$this->tax_data = $tax_data;
|
||||
nlog($tax_data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setClient(Client $client):self
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function tax(): self
|
||||
@ -158,4 +175,11 @@ class Rule implements RuleInterface
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function taxReduced(): self
|
||||
{
|
||||
$this->tax();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -112,8 +112,8 @@ class InvoiceItemSum
|
||||
|
||||
$tax_data = new Response($this->invoice->tax_data);
|
||||
|
||||
$this->rule = new $class($tax_data);
|
||||
|
||||
$this->rule = new $class();
|
||||
$this->rule->setTaxData($tax_data);
|
||||
$this->calc_tax = true;
|
||||
|
||||
return $this;
|
||||
|
@ -116,6 +116,7 @@ class Product extends BaseModel
|
||||
public const PRODUCT_TYPE_DIGITAL = 3;
|
||||
public const PRODUCT_TYPE_SHIPPING = 4;
|
||||
public const PRODUCT_TAX_EXEMPT = 5;
|
||||
public const PRODUCT_TYPE_REDUCED_TAX = 6;
|
||||
|
||||
protected $fillable = [
|
||||
'custom_value1',
|
||||
|
@ -9,14 +9,14 @@
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Tax;
|
||||
namespace App\Services\Tax\Providers;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Support\Str;
|
||||
use App\DataMapper\Tax\de\Rule;
|
||||
use App\Services\Tax\VatNumberCheck;
|
||||
class ProcessRule
|
||||
class EuTax
|
||||
{
|
||||
public Rule $rule;
|
||||
|
194
app/Services/Tax/Providers/TaxProvider.php
Normal file
194
app/Services/Tax/Providers/TaxProvider.php
Normal file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Services\Tax\Providers;
|
||||
|
||||
use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Http\Client\Response;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class TaxProvider
|
||||
{
|
||||
|
||||
public array $eu_countries = [
|
||||
"AT",
|
||||
"BE",
|
||||
"BG",
|
||||
"HR",
|
||||
"CY",
|
||||
"CZ",
|
||||
"DK",
|
||||
"EE",
|
||||
"FI",
|
||||
"FR",
|
||||
"DE",
|
||||
"GR",
|
||||
"HU",
|
||||
"IE",
|
||||
"IT",
|
||||
"LV",
|
||||
"LT",
|
||||
"LU",
|
||||
"MT",
|
||||
"NL",
|
||||
"PL",
|
||||
"PT",
|
||||
"RO",
|
||||
"SK",
|
||||
"SI",
|
||||
"ES",
|
||||
"SE"
|
||||
];
|
||||
|
||||
private string $provider = ZipTax::class;
|
||||
|
||||
private mixed $api_credentials;
|
||||
|
||||
|
||||
public function __construct(protected Company $company, protected Client $client)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function updateCompanyTaxData(): self
|
||||
{
|
||||
$this->configureProvider($this->provider); //hard coded for now to one provider, but we'll be able to swap these out later
|
||||
|
||||
$company_details = [
|
||||
'address1' => $this->company->settings->address1,
|
||||
'address2' => $this->company->settings->address2,
|
||||
'city' => $this->company->settings->city,
|
||||
'state' => $this->company->settings->state,
|
||||
'postal_code' => $this->company->settings->postal_code,
|
||||
'country_id' => $this->company->settings->country_id,
|
||||
];
|
||||
|
||||
$tax_provider = new $this->provider($company_details);
|
||||
|
||||
$tax_provider->setApiCredentials($this->api_credentials);
|
||||
|
||||
$tax_data = $tax_provider->run();
|
||||
|
||||
$this->company->tax_data = $tax_data;
|
||||
|
||||
$this->company->save();
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
public function updateClientTaxData(): self
|
||||
{
|
||||
$this->configureProvider($this->provider); //hard coded for now to one provider, but we'll be able to swap these out later
|
||||
|
||||
$billing_details =[
|
||||
'address1' => $this->client->address1,
|
||||
'address2' => $this->client->address2,
|
||||
'city' => $this->client->city,
|
||||
'state' => $this->client->state,
|
||||
'postal_code' => $this->client->postal_code,
|
||||
'country_id' => $this->client->country_id,
|
||||
];
|
||||
|
||||
$shipping_details =[
|
||||
'address1' => $this->client->shipping_address1,
|
||||
'address2' => $this->client->shipping_address2,
|
||||
'city' => $this->client->shipping_city,
|
||||
'state' => $this->client->shipping_state,
|
||||
'postal_code' => $this->client->shipping_postal_code,
|
||||
'country_id' => $this->client->shipping_country_id,
|
||||
];
|
||||
|
||||
|
||||
$tax_provider = new $this->provider();
|
||||
|
||||
$tax_provider->setApiCredentials($this->api_credentials);
|
||||
|
||||
$tax_data = $tax_provider->run();
|
||||
|
||||
$this->company->tax_data = $tax_data;
|
||||
|
||||
$this->company->save();
|
||||
|
||||
return $this;
|
||||
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function configureProvider(?string $provider): self
|
||||
{
|
||||
|
||||
match($this->client->country->iso_3166_2){
|
||||
'US' => $this->configureZipTax(),
|
||||
"AT" => $this->configureEuTax(),
|
||||
"BE" => $this->configureEuTax(),
|
||||
"BG" => $this->configureEuTax(),
|
||||
"HR" => $this->configureEuTax(),
|
||||
"CY" => $this->configureEuTax(),
|
||||
"CZ" => $this->configureEuTax(),
|
||||
"DK" => $this->configureEuTax(),
|
||||
"EE" => $this->configureEuTax(),
|
||||
"FI" => $this->configureEuTax(),
|
||||
"FR" => $this->configureEuTax(),
|
||||
"DE" => $this->configureEuTax(),
|
||||
"GR" => $this->configureEuTax(),
|
||||
"HU" => $this->configureEuTax(),
|
||||
"IE" => $this->configureEuTax(),
|
||||
"IT" => $this->configureEuTax(),
|
||||
"LV" => $this->configureEuTax(),
|
||||
"LT" => $this->configureEuTax(),
|
||||
"LU" => $this->configureEuTax(),
|
||||
"MT" => $this->configureEuTax(),
|
||||
"NL" => $this->configureEuTax(),
|
||||
"PL" => $this->configureEuTax(),
|
||||
"PT" => $this->configureEuTax(),
|
||||
"RO" => $this->configureEuTax(),
|
||||
"SK" => $this->configureEuTax(),
|
||||
"SI" => $this->configureEuTax(),
|
||||
"ES" => $this->configureEuTax(),
|
||||
"SE" => $this->configureEuTax(),
|
||||
default => $this->noTaxRegionDefined(),
|
||||
};
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function configureEuTax(): self
|
||||
{
|
||||
$this->provider = EuTax::class;
|
||||
|
||||
// $this->api_credentials = config('services.tax.eu_tax.key');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function noTaxRegionDefined(): self
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function configureZipTax(): self
|
||||
{
|
||||
|
||||
$this->provider = ZipTax::class;
|
||||
|
||||
$this->api_credentials = config('services.tax.zip_tax.key');
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -18,101 +18,10 @@ use App\Services\Tax\Providers\ZipTax;
|
||||
|
||||
class TaxService
|
||||
{
|
||||
private string $provider = ZipTax::class;
|
||||
|
||||
private mixed $api_credentials;
|
||||
|
||||
public function __construct(protected Company $company, protected Client $client)
|
||||
{
|
||||
}
|
||||
|
||||
public function updateCompanyTaxData(): self
|
||||
{
|
||||
$this->configureProvider($this->provider); //hard coded for now to one provider, but we'll be able to swap these out later
|
||||
|
||||
$company_details = [
|
||||
'address1' => $this->company->settings->address1,
|
||||
'address2' => $this->company->settings->address2,
|
||||
'city' => $this->company->settings->city,
|
||||
'state' => $this->company->settings->state,
|
||||
'postal_code' => $this->company->settings->postal_code,
|
||||
'country_id' => $this->company->settings->country_id,
|
||||
];
|
||||
|
||||
$tax_provider = new $this->provider($company_details);
|
||||
|
||||
$tax_provider->setApiCredentials($this->api_credentials);
|
||||
|
||||
$tax_data = $tax_provider->run();
|
||||
|
||||
$this->company->tax_data = $tax_data;
|
||||
|
||||
$this->company->save();
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
public function updateClientTaxData(): self
|
||||
{
|
||||
$this->configureProvider($this->provider); //hard coded for now to one provider, but we'll be able to swap these out later
|
||||
|
||||
$billing_details =[
|
||||
'address1' => $this->client->address1,
|
||||
'address2' => $this->client->address2,
|
||||
'city' => $this->client->city,
|
||||
'state' => $this->client->state,
|
||||
'postal_code' => $this->client->postal_code,
|
||||
'country_id' => $this->client->country_id,
|
||||
];
|
||||
|
||||
$shipping_details =[
|
||||
'address1' => $this->client->shipping_address1,
|
||||
'address2' => $this->client->shipping_address2,
|
||||
'city' => $this->client->shipping_city,
|
||||
'state' => $this->client->shipping_state,
|
||||
'postal_code' => $this->client->shipping_postal_code,
|
||||
'country_id' => $this->client->shipping_country_id,
|
||||
];
|
||||
|
||||
|
||||
$tax_provider = new $this->provider();
|
||||
|
||||
$tax_provider->setApiCredentials($this->api_credentials);
|
||||
|
||||
$tax_data = $tax_provider->run();
|
||||
|
||||
$this->company->tax_data = $tax_data;
|
||||
|
||||
$this->company->save();
|
||||
|
||||
return $this;
|
||||
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function configureProvider(?string $provider): self
|
||||
{
|
||||
|
||||
match($provider){
|
||||
ZipTax::class => $this->configureZipTax(),
|
||||
default => $this->configureZipTax(),
|
||||
};
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
private function configureZipTax(): self
|
||||
{
|
||||
|
||||
$this->provider = ZipTax::class;
|
||||
|
||||
$this->api_credentials = config('services.tax.zip_tax.key');
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -16,15 +16,15 @@ use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use Tests\MockAccountData;
|
||||
use App\DataMapper\Tax\de\Rule;
|
||||
use App\Services\Tax\ProcessRule;
|
||||
use App\Services\Tax\Providers\EuTax;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
|
||||
/**
|
||||
* @test App\Services\Tax\ProcessRule
|
||||
* @test App\Services\Tax\Providers\EuTax
|
||||
*/
|
||||
class ProcessRuleTest extends TestCase
|
||||
class EuTaxTest extends TestCase
|
||||
{
|
||||
use MockAccountData;
|
||||
use DatabaseTransactions;
|
||||
@ -60,7 +60,7 @@ class ProcessRuleTest extends TestCase
|
||||
'shipping_country_id' => 276,
|
||||
]);
|
||||
|
||||
$process = new ProcessRule($company, $client);
|
||||
$process = new EuTax($company, $client);
|
||||
$process->run();
|
||||
|
||||
$this->assertEquals('de', $process->getVendorCountryCode());
|
||||
@ -96,7 +96,7 @@ class ProcessRuleTest extends TestCase
|
||||
'shipping_country_id' => 56,
|
||||
]);
|
||||
|
||||
$process = new ProcessRule($company, $client);
|
||||
$process = new EuTax($company, $client);
|
||||
$process->run();
|
||||
|
||||
$this->assertEquals('de', $process->getVendorCountryCode());
|
||||
@ -132,7 +132,7 @@ class ProcessRuleTest extends TestCase
|
||||
'shipping_country_id' => 840,
|
||||
]);
|
||||
|
||||
$process = new ProcessRule($company, $client);
|
||||
$process = new EuTax($company, $client);
|
||||
$process->run();
|
||||
|
||||
$this->assertEquals('de', $process->getVendorCountryCode());
|
Loading…
x
Reference in New Issue
Block a user