From 27c26d9eb6dd2f836d37f4355e2d3b20e1784cf5 Mon Sep 17 00:00:00 2001 From: Alberto Peripolli Date: Thu, 23 Jan 2025 16:08:58 +0100 Subject: [PATCH 1/2] Add exceptions rates support --- src/Clients/IbericodeVatRatesClient.php | 2 +- src/Period.php | 24 +++++++++++++++++++++--- src/Rates.php | 10 ++++++---- tests/RatesTest.php | 20 ++++++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/Clients/IbericodeVatRatesClient.php b/src/Clients/IbericodeVatRatesClient.php index e239b5d..335d165 100644 --- a/src/Clients/IbericodeVatRatesClient.php +++ b/src/Clients/IbericodeVatRatesClient.php @@ -41,7 +41,7 @@ private function parseResponse(string $response_body): array $return = []; foreach ($result->items as $country => $periods) { foreach ($periods as $i => $period) { - $periods[$i] = new Period(new \DateTimeImmutable($period->effective_from), (array) $period->rates); + $periods[$i] = new Period(new \DateTimeImmutable($period->effective_from), (array) $period->rates, $period->exceptions ?? []); } $return[$country] = $periods; diff --git a/src/Period.php b/src/Period.php index 3b59d59..9098589 100644 --- a/src/Period.php +++ b/src/Period.php @@ -17,11 +17,13 @@ class Period { private $effectiveFrom; private $rates = []; + private $exceptions = []; - public function __construct(DateTimeInterface $effectiveFrom, array $rates) + public function __construct(DateTimeInterface $effectiveFrom, array $rates, array $exceptions = []) { $this->effectiveFrom = $effectiveFrom; $this->rates = $rates; + $this->exceptions = $exceptions; } public function getEffectiveFrom(): DateTimeInterface @@ -29,12 +31,28 @@ public function getEffectiveFrom(): DateTimeInterface return $this->effectiveFrom; } - public function getRate(string $level): float + public function getRate(string $level, ?string $postcode = null): float { if (!isset($this->rates[$level])) { throw new InvalidArgumentException("Invalid rate level: {$level}"); } - return $this->rates[$level]; + return $this->getExceptionRate($level, $postcode) ?? $this->rates[$level]; } + + private function getExceptionRate(string $level, ?string $postcode): ?float + { + if (!$postcode) { + return null; + } + + foreach ($this->exceptions as $exception) { + if (preg_match('/^'.$exception['postcode'].'$/', $postcode)) { + return $exception[$level] ?? $exception[Rates::RATE_STANDARD]; + } + } + + return null; + } + } diff --git a/src/Rates.php b/src/Rates.php index a9d7a7a..80bea98 100644 --- a/src/Rates.php +++ b/src/Rates.php @@ -135,24 +135,26 @@ private function resolvePeriod(string $countryCode, DateTimeInterface $datetime) /** * @param string $countryCode ISO-3166-1-alpha2 country code * @param string $level + * @param ?string $postcode * @return float * @throws \Exception */ - public function getRateForCountry(string $countryCode, string $level = self::RATE_STANDARD): float + public function getRateForCountry(string $countryCode, string $level = self::RATE_STANDARD, ?string $postcode = null): float { $todayMidnight = new \DateTimeImmutable('today midnight'); - return $this->getRateForCountryOnDate($countryCode, $todayMidnight, $level); + return $this->getRateForCountryOnDate($countryCode, $todayMidnight, $level, $postcode); } /** * @param string $countryCode ISO-3166-1-alpha2 country code * @param DateTimeInterface $datetime * @param string $level + * @param ?string $postcode * @return float * @throws Exception */ - public function getRateForCountryOnDate(string $countryCode, \DateTimeInterface $datetime, string $level = self::RATE_STANDARD): float + public function getRateForCountryOnDate(string $countryCode, \DateTimeInterface $datetime, string $level = self::RATE_STANDARD, ?string $postcode = null) : float { - return $this->resolvePeriod($countryCode, $datetime)->getRate($level); + return $this->resolvePeriod($countryCode, $datetime)->getRate($level, $postcode); } } diff --git a/tests/RatesTest.php b/tests/RatesTest.php index 0bb596f..f25a424 100644 --- a/tests/RatesTest.php +++ b/tests/RatesTest.php @@ -39,6 +39,17 @@ private function getRatesClientMock(): \PHPUnit\Framework\MockObject\MockObject new Period(new \DateTimeImmutable('2019/01/01'), [ 'standard' => 21.00, 'reduced' => 9.00, + ], [ + [ + "name" => "Park Frankendael", + "postcode" => "1097", + "standard" => 0 + ], + [ + "name" => "Park de Meer", + "postcode" => "(1098|1099)", + "standard" => 0 + ] ]) ] ]); @@ -53,6 +64,15 @@ public function testGetRateForCountry() $this->assertEquals(21.0, $rates->getRateForCountry('NL')); } + public function testGetRateForCountryAndPostcode() + { + $client = $this->getRatesClientMock(); + $rates = new Rates('vendor/rates', 30, $client); + $this->assertEquals(0, $rates->getRateForCountry('NL', Rates::RATE_STANDARD, '1097')); + $this->assertEquals(0, $rates->getRateForCountry('NL', Rates::RATE_STANDARD, '1099')); + $this->assertEquals(0, $rates->getRateForCountry('NL', Rates::RATE_STANDARD, '1098')); + } + public function testGetRateForCountryOnDate() { $client = $this->getRatesClientMock(); From 903203293241e6565e900e4db9d026d9d34f6f72 Mon Sep 17 00:00:00 2001 From: Alberto Peripolli Date: Thu, 23 Jan 2025 17:36:16 +0100 Subject: [PATCH 2/2] fix typo --- src/Period.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Period.php b/src/Period.php index 9098589..217bde2 100644 --- a/src/Period.php +++ b/src/Period.php @@ -47,6 +47,7 @@ private function getExceptionRate(string $level, ?string $postcode): ?float } foreach ($this->exceptions as $exception) { + $exception = (array) $exception; if (preg_match('/^'.$exception['postcode'].'$/', $postcode)) { return $exception[$level] ?? $exception[Rates::RATE_STANDARD]; }