diff --git a/app/DataMapper/Tax/RuleInterface.php b/app/DataMapper/Tax/RuleInterface.php index a9403451b539..633ba0b7be8e 100644 --- a/app/DataMapper/Tax/RuleInterface.php +++ b/app/DataMapper/Tax/RuleInterface.php @@ -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); } \ No newline at end of file diff --git a/app/DataMapper/Tax/de/Rule.php b/app/DataMapper/Tax/de/Rule.php index 6097338b9d7e..55d47ef208cc 100644 --- a/app/DataMapper/Tax/de/Rule.php +++ b/app/DataMapper/Tax/de/Rule.php @@ -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 = ''; diff --git a/app/DataMapper/Tax/us/Rule.php b/app/DataMapper/Tax/us/Rule.php index 7fee2564dac3..7454f6b0ca3a 100644 --- a/app/DataMapper/Tax/us/Rule.php +++ b/app/DataMapper/Tax/us/Rule.php @@ -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; + } } diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index f093962f7f98..99de411c0be7 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -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; diff --git a/app/Models/Product.php b/app/Models/Product.php index 30623b9c706b..ad17e87038fa 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -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', diff --git a/app/Services/Tax/ProcessRule.php b/app/Services/Tax/Providers/EuTax.php similarity index 98% rename from app/Services/Tax/ProcessRule.php rename to app/Services/Tax/Providers/EuTax.php index 21a4b197d799..9c29727d72b8 100644 --- a/app/Services/Tax/ProcessRule.php +++ b/app/Services/Tax/Providers/EuTax.php @@ -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; diff --git a/app/Services/Tax/Providers/TaxProvider.php b/app/Services/Tax/Providers/TaxProvider.php new file mode 100644 index 000000000000..7690eca00475 --- /dev/null +++ b/app/Services/Tax/Providers/TaxProvider.php @@ -0,0 +1,194 @@ +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; + + } + +} \ No newline at end of file diff --git a/app/Services/Tax/TaxService.php b/app/Services/Tax/TaxService.php index 20ef2f042013..678418c240b5 100644 --- a/app/Services/Tax/TaxService.php +++ b/app/Services/Tax/TaxService.php @@ -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; - - } + } \ No newline at end of file diff --git a/tests/Unit/Tax/ProcessRuleTest.php b/tests/Unit/Tax/EuTaxTest.php similarity index 93% rename from tests/Unit/Tax/ProcessRuleTest.php rename to tests/Unit/Tax/EuTaxTest.php index f8c00ce48bb0..4db56aad1cff 100644 --- a/tests/Unit/Tax/ProcessRuleTest.php +++ b/tests/Unit/Tax/EuTaxTest.php @@ -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());