-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A huge thanks to @jonathanmaron for providing a solution for Northern Ireland to validate their VAT ID's after Brexit.
- Loading branch information
Showing
5 changed files
with
145 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,5 @@ vendor/ | |
build/ | ||
composer.lock | ||
.scannerwork/ | ||
.idea/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
<?php | ||
|
||
declare (strict_types=1); | ||
|
||
/** | ||
* \DragonBe\Vies | ||
* | ||
* @author Paweł Krzaczkowski <krzaczek+github@gmail.com> | ||
* @license MIT | ||
*/ | ||
|
||
namespace DragonBe\Vies\Validator; | ||
|
||
/** | ||
* This validator was derived from the "ValidatorGB" validator to validate the "XI" VAT numbers of | ||
* "United Kingdom (Northern Ireland)" following the end of the Brexit transition period on December, 31 2020. | ||
* | ||
* It is based on the information at: | ||
* https://www.avalara.com/vatlive/en/vat-news/brexit-northern-ireland-vat-and-eoro--xi--number.html | ||
* | ||
* As more information is published, this validator may be made more precise: | ||
* | ||
* - Remove the logic to validate Isle of Man numbers? | ||
* - Remove the logic to validate 'GD' and 'HA' prefixes? | ||
* | ||
*/ | ||
|
||
/** | ||
* Class ValidatorXI | ||
* @package DragonBe\Vies\Validator | ||
* | ||
* VAT format: [C1 C2 C3 C4 C5] | ||
* [C1 C2 C3 C4 C5 C6 C7 C8 C9] | ||
* [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12] | ||
* | ||
* Range: | ||
* C1 .. C2 Alphanumeric from A to Z or 0 to 9 | ||
* C2 .. C11 Numeric from 0 to 9 | ||
* | ||
* Rules: | ||
* Case 1: | ||
* [C1 C2] Alpha: “GD” or “HA” | ||
* C3 ... C5 Numeric from 0 to 9 | ||
* | ||
* if [C1 C2] = “GD” | ||
* [C3 C4 C5] from 000 to 499 | ||
* | ||
* If [C1 C2] = “HA” | ||
* [C3 C4 C5] from 500 to 999 | ||
* | ||
* Case 2 | ||
* [C1 C2 C3] from 000 to 009 are numbers for Isle of Man | ||
* [C10 C11 C12] > 000 | ||
* [C1 C2 C3 C4 C5 C6 C7 C8 C9] >000000000 | ||
* | ||
* [C8 C9] | ||
* R1 = (8*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8C9) modulo 97 | ||
* R2 = ((8*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8C9) + 55) modulo 97 | ||
* Either R1 or R2 must equal to zero. | ||
* | ||
*/ | ||
class ValidatorXI extends ValidatorAbstract | ||
{ | ||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function validate(string $vatNumber): bool | ||
{ | ||
if (strlen($vatNumber) == 5) { | ||
return $this->validateGovernment($vatNumber); | ||
} | ||
|
||
if (strlen($vatNumber) != 9 && strlen($vatNumber) != 12) { | ||
return false; | ||
} | ||
|
||
$weights = [8, 7, 6, 5, 4, 3, 2]; | ||
$checkVal = $this->sumWeights($weights, $vatNumber); | ||
$checkVal += (int)substr($vatNumber, 7, 2); | ||
|
||
$Result1 = $checkVal % 97; | ||
$Result2 = ($Result1 + 55) % 97; | ||
|
||
return ! ($Result1 * $Result2); | ||
} | ||
|
||
/** | ||
* Validate Government VAT | ||
* | ||
* @param string $vatNumber | ||
* | ||
* @return bool | ||
*/ | ||
private function validateGovernment(string $vatNumber): bool | ||
{ | ||
$prefix = strtoupper(substr($vatNumber, 0, 2)); | ||
$number = (int) substr($vatNumber, 2, 3); | ||
|
||
// Government departments | ||
if ($prefix == 'GD') { | ||
return $number < 500; | ||
} | ||
|
||
// Health authorities | ||
if ($prefix == 'HA') { | ||
return $number > 499; | ||
} | ||
|
||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?php | ||
|
||
declare (strict_types=1); | ||
|
||
namespace DragonBe\Test\Vies\Validator; | ||
|
||
class ValidatorXITest extends AbstractValidatorTest | ||
{ | ||
/** | ||
* @covers \DragonBe\Vies\Validator\ValidatorXI | ||
* @dataProvider vatNumberProvider | ||
*/ | ||
public function testValidator(string $vatNumber, bool $state) | ||
{ | ||
$this->validateVatNumber('XI', $vatNumber, $state); | ||
} | ||
|
||
public function vatNumberProvider() | ||
{ | ||
return [ | ||
['925901618', true], | ||
['GD001', true], | ||
['HA500', true], | ||
['434031493', false], | ||
['12345', false], | ||
['GD500', false], | ||
['HA100', false], | ||
['12345678', false], | ||
]; | ||
} | ||
} |