diff --git a/app/DataMapper/Tax/BaseRule.php b/app/DataMapper/Tax/BaseRule.php index 1c154e6035..c212c870fd 100644 --- a/app/DataMapper/Tax/BaseRule.php +++ b/app/DataMapper/Tax/BaseRule.php @@ -15,6 +15,7 @@ use App\Models\Client; use App\Models\Invoice; use App\Models\Product; use App\DataMapper\Tax\ZipTax\Response; +use App\DataProviders\USStates; class BaseRule implements RuleInterface { @@ -116,7 +117,7 @@ class BaseRule implements RuleInterface protected ?Client $client; - protected ?Response $tax_data; + public ?Response $tax_data; public mixed $invoice; @@ -129,29 +130,41 @@ class BaseRule implements RuleInterface return $this; } - public function setInvoice(mixed $invoice): self + public function setEntity(mixed $invoice): self { $this->invoice = $invoice; - - $this->configTaxData(); $this->client = $invoice->client; + $this->configTaxData() + ->resolveRegions(); + $this->tax_data = new Response($this->invoice->tax_data); - $this->resolveRegions(); - - return $this; } private function configTaxData(): self { + + if(!array_key_exists($this->client->country->iso_3166_2, $this->region_codes)) { + throw new \Exception('Automatic tax calculations not supported for this country'); + } + + $this->client_region = $this->region_codes[$this->client->country->iso_3166_2]; + if($this->invoice->tax_data && $this->invoice->status_id > 1) return $this; //determine if we are taxing locally or if we are taxing globally - // $this->invoice->tax_data = $this->invoice->client->tax_data; + $this->invoice->tax_data = $this->invoice->client->tax_data ?: new Response([]); + + if(strlen($this->invoice->tax_data?->originDestination) == 0 && $this->client->company->tax_data->seller_subregion != $this->client_subregion) { + $tax_data = $this->invoice->tax_data; + $tax_data->originDestination = "D"; + $this->invoice->tax_data = $tax_data; + $this->invoice->saveQuietly(); + } return $this; } @@ -160,20 +173,25 @@ class BaseRule implements RuleInterface private function resolveRegions(): self { - if(!array_key_exists($this->client->country->iso_3166_2, $this->region_codes)) - throw new \Exception('Automatic tax calculations not supported for this country'); - - $this->client_region = $this->region_codes[$this->client->country->iso_3166_2]; - match($this->client_region){ - 'US' => $this->client_subregion = $this->tax_data->geoState, + 'US' => $this->client_subregion = strlen($this->invoice?->tax_data?->geoState) > 1 ? $this->invoice?->tax_data?->geoState : $this->getUSState(), 'EU' => $this->client_subregion = $this->client->country->iso_3166_2, + 'AU' => $this->client_subregion = 'AU', default => $this->client_subregion = $this->client->country->iso_3166_2, }; return $this; } + private function getUSState(): string + { + try { + return USStates::getState(strlen($this->client->postal_code) > 1 ? $this->client->postal_code : $this->client->shipping_postal_code); + } catch (\Exception $e) { + return 'CA'; + } + } + public function isTaxableRegion(): bool { return $this->client->company->tax_data->regions->{$this->client_region}->tax_all_subregions || $this->client->company->tax_data->regions->{$this->client_region}->subregions->{$this->client_subregion}->apply_tax; diff --git a/app/Helpers/Invoice/InvoiceItemSum.php b/app/Helpers/Invoice/InvoiceItemSum.php index afef994e2b..6c68464703 100644 --- a/app/Helpers/Invoice/InvoiceItemSum.php +++ b/app/Helpers/Invoice/InvoiceItemSum.php @@ -148,7 +148,7 @@ class InvoiceItemSum $this->rule = new $class(); $this->rule - ->setInvoice($this->invoice) + ->setEntity($this->invoice) ->init(); $this->calc_tax = true; diff --git a/tests/Feature/Scheduler/SchedulerTest.php b/tests/Feature/Scheduler/SchedulerTest.php index 3704836837..579186e7c5 100644 --- a/tests/Feature/Scheduler/SchedulerTest.php +++ b/tests/Feature/Scheduler/SchedulerTest.php @@ -480,14 +480,14 @@ class SchedulerTest extends TestCase $c = Client::factory()->create([ 'company_id' => $this->company->id, 'user_id' => $this->user->id, - 'number' => rand(1000, 100000), + 'number' => rand(1000, 10000000), 'name' => 'A fancy client' ]); $c2 = Client::factory()->create([ 'company_id' => $this->company->id, 'user_id' => $this->user->id, - 'number' => rand(1000, 100000), + 'number' => rand(1000, 10000000), 'name' => 'A fancy client' ]); diff --git a/tests/Unit/Tax/EuTaxTest.php b/tests/Unit/Tax/EuTaxTest.php index 6f41d282bb..b56c130507 100644 --- a/tests/Unit/Tax/EuTaxTest.php +++ b/tests/Unit/Tax/EuTaxTest.php @@ -349,7 +349,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); $this->assertEquals('EU', $process->seller_region); @@ -403,7 +403,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); $this->assertEquals('EU', $process->seller_region); @@ -458,7 +458,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); $this->assertEquals('EU', $process->seller_region); @@ -513,7 +513,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); $this->assertInstanceOf(Rule::class, $process); @@ -564,7 +564,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); @@ -615,7 +615,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); @@ -666,7 +666,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); @@ -717,7 +717,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); $this->assertInstanceOf(Rule::class, $process); @@ -766,7 +766,7 @@ class EuTaxTest extends TestCase ]); $process = new Rule(); - $process->setInvoice($invoice); + $process->setEntity($invoice); $process->init(); diff --git a/tests/Unit/Tax/SumTaxTest.php b/tests/Unit/Tax/SumTaxTest.php index f1a4ad5b08..ec3b304723 100644 --- a/tests/Unit/Tax/SumTaxTest.php +++ b/tests/Unit/Tax/SumTaxTest.php @@ -102,10 +102,13 @@ class SumTaxTest extends TestCase $this->company->tax_data = $tax_data; $this->company->save(); + $tax_data = new TaxData($this->response); + $client = Client::factory()->create([ 'user_id' => $this->user->id, 'company_id' => $this->company->id, 'country_id' => 840, + 'tax_data' => $tax_data, ]); $invoice = InvoiceFactory::create($this->company->id, $this->user->id); @@ -114,7 +117,7 @@ class SumTaxTest extends TestCase $line_items = []; - $invoice->tax_data = new TaxData($this->response); + $invoice->tax_data = $tax_data; $line_item = new InvoiceItem(); $line_item->quantity = 1; @@ -131,7 +134,6 @@ class SumTaxTest extends TestCase $line_items = $invoice->line_items; - $this->assertEquals(10, $invoice->amount); $this->assertEquals("", $line_items[0]->tax_name1); $this->assertEquals(0, $line_items[0]->tax_rate1); @@ -152,19 +154,23 @@ class SumTaxTest extends TestCase $this->company->tax_data = $tax_data; $this->company->save(); - $client = Client::factory()->create([ - 'user_id' => $this->user->id, - 'company_id' => $this->company->id, - 'country_id' => 840, - ]); +$tax_data = new TaxData($this->response); - $invoice = InvoiceFactory::create($this->company->id, $this->user->id); - $invoice->client_id = $client->id; - $invoice->uses_inclusive_taxes = false; +$client = Client::factory()->create([ + 'user_id' => $this->user->id, + 'company_id' => $this->company->id, + 'country_id' => 840, + 'tax_data' => $tax_data, +]); - $line_items = []; +$invoice = InvoiceFactory::create($this->company->id, $this->user->id); +$invoice->client_id = $client->id; +$invoice->uses_inclusive_taxes = false; + +$line_items = []; + +$invoice->tax_data = $tax_data; - $invoice->tax_data = new TaxData($this->response); $line_item = new InvoiceItem; $line_item->quantity = 1; diff --git a/tests/Unit/Tax/UsTaxTest.php b/tests/Unit/Tax/UsTaxTest.php index f08b295b38..5ed356723c 100644 --- a/tests/Unit/Tax/UsTaxTest.php +++ b/tests/Unit/Tax/UsTaxTest.php @@ -107,6 +107,7 @@ class UsTaxTest extends TestCase 'shipping_country_id' => 840, 'has_valid_vat_number' => false, 'postal_code' => $postal_code, + 'tax_data' => new Response($this->mock_response), ]); $invoice = Invoice::factory()->create([ @@ -309,6 +310,7 @@ class UsTaxTest extends TestCase 'shipping_country_id' => 276, 'has_valid_vat_number' => false, 'postal_code' => 'xx', + 'tax_data' => new Response($this->mock_response), ]); $invoice = Invoice::factory()->create([ @@ -353,18 +355,18 @@ class UsTaxTest extends TestCase { $invoice = $this->invoiceStub('92582'); - $client = $invoice->client; - $client->is_tax_exempt = false; - $client->save(); + $invoice->client->is_tax_exempt = false; + $invoice->client->tax_data = new Response($this->mock_response); - $company = $invoice->company; - $tax_data = $company->tax_data; + $invoice->client->push(); + + $tax_data = $invoice->company->tax_data; $tax_data->regions->US->has_sales_above_threshold = true; $tax_data->regions->US->tax_all_subregions = true; - $company->tax_data = $tax_data; - $company->save(); + $invoice->company->tax_data = $tax_data; + $invoice->company->push(); $invoice = $invoice->calc()->getInvoice()->service()->markSent()->save();