From e78e335b6ace4edad160a1637baf2900552ed398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Thu, 10 Sep 2020 17:32:28 +0200 Subject: [PATCH] shouldCollectVat() returns true for manually added countries too but getDetails shouldn't try to talk to VIES Fix #13 (this time with feeling) --- README.md | 10 ++++++++-- UPGRADE.md | 1 + src/VatCalculator.php | 8 +++++++- src/VatRates.php | 7 +++++++ tests/VatCalculatorTest.php | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 522b1c0..3fa6393 100644 --- a/README.md +++ b/README.md @@ -89,11 +89,17 @@ $grossPrice->getTaxRate(); ### Validate EU VAT numbers Prior to validating your customers VAT numbers, you can use the `shouldCollectVat` method to check if the country code requires you to collect VAT -in the first place. +in the first place. This method will return `true` even for non-EU countries added manually with `addRateForCountry` (see below). + +To ignore those manually added non-EU countries and return `true` only for EU member states, you can use `shouldCollectEuVat`. ```php if ($vatCalculator->shouldCollectVat('DE')) { +} + +if ($vatCalculator->shouldCollectEuVat('DE')) { + } ``` @@ -103,7 +109,7 @@ The given VAT numbers will be truncated and non relevant characters / whitespace This service relies on a third party SOAP API provided by the EU. If, for whatever reason, this API is unavailable a `VatCheckUnavailableException` will be thrown. -If a VAT number from a unsupported/non-EU country is provided, `UnsupportedCountryException` will be thrown. +If a VAT number from an unsupported/non-EU country is provided, `UnsupportedCountryException` will be thrown. ```php try { diff --git a/UPGRADE.md b/UPGRADE.md index 9b3ccf2..4076086 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -8,6 +8,7 @@ * `calculate()` & `calculateNet()` methods return `VatPrice` object instead of the calculated price (**BR BREAK**) * After running `calculate()` & `calculateNet()`, the `VatCalculator` object keeps its state, `getNetPrice()`, `getTaxRate()`, `getCountryCode()`, `setCountryCode()`, `getPostalCode()`, `setPostalCode()`, `isCompany()`, `setCompany()` removed (**BR BREAK**) * Norway, Turkey, Switzerland VAT rates removed, can be manually added back with `VatRates::addRateForCountry()` +* `shouldCollectVat()` will also return `true` for those manually added non-EU countries, use `shouldCollectEuVat()` to return `true` only for EU member states * `getIPBasedCountry()` & `getClientIP()` methods have been removed, use some other package (or `CF-IPCountry` HTTP header if you're behind Cloudflare) * Some methods have been properly *camelCased*: methods like `getClientIP()` -> `getClientIp()` and `shouldCollectVAT` -> `shouldCollectVat` and a few more * `VATCheckUnavailableException` has been *camelCased* to `VatCheckUnavailableException` diff --git a/src/VatCalculator.php b/src/VatCalculator.php index 890b709..2417ea3 100644 --- a/src/VatCalculator.php +++ b/src/VatCalculator.php @@ -44,6 +44,12 @@ public function shouldCollectVat(string $countryCode): bool } + public function shouldCollectEuVat(string $countryCode): bool + { + return $this->vatRates->shouldCollectEuVat($countryCode); + } + + /** * Calculate the VAT based on the net price, country code and indication if the * customer is a company or not. Specify a date to use VAT rate valid for that date. @@ -141,7 +147,7 @@ public function getVatDetails(string $vatNumber, ?string $requesterVatNumber = n $countryCode = substr($vatNumber, 0, 2); $vatNumber = substr($vatNumber, 2); - if (!$this->shouldCollectVat($countryCode)) { + if (!$this->shouldCollectEuVat($countryCode)) { throw new UnsupportedCountryException($countryCode); } diff --git a/src/VatRates.php b/src/VatRates.php index 52534c0..bacf0ed 100644 --- a/src/VatRates.php +++ b/src/VatRates.php @@ -389,6 +389,13 @@ public function shouldCollectVat(string $countryCode): bool } + public function shouldCollectEuVat(string $countryCode): bool + { + $countryCode = strtoupper($countryCode); + return isset($this->taxRules[$countryCode]) && !isset($this->optionalTaxRules[$countryCode]); + } + + /** * Returns the tax rate for the given country code. * If a postal code is provided, it will try to lookup the different diff --git a/tests/VatCalculatorTest.php b/tests/VatCalculatorTest.php index 323af0f..c5ab19a 100644 --- a/tests/VatCalculatorTest.php +++ b/tests/VatCalculatorTest.php @@ -208,6 +208,22 @@ public function testCanValidateValidVatNumberWithRequesterVatNumberSet() } + public function testAddNonEuRateShouldCollectValidateThrows(): void + { + $this->assertFalse($this->vatCalculator->shouldCollectVat('NO')); + $this->assertFalse($this->vatCalculator->shouldCollectEuVat('NO')); + $this->vatRates->addRateForCountry('NO'); + $this->assertTrue($this->vatCalculator->shouldCollectVat('NO')); + $this->assertFalse($this->vatCalculator->shouldCollectEuVat('NO')); + + $this->setExpectedException(UnsupportedCountryException::class, 'Unsupported/non-EU country No'); + + $vatNumber = 'Norway132'; // unsupported country NO + $result = $this->vatCalculator->isValidVatNumber($vatNumber); + $this->assertFalse($result); + } + + public function testSetBusinessCountryCode() { $this->vatCalculator->setBusinessCountryCode('DE');