From 9ef3cf04153150ebe3f5d12dc4b38d982710b28c Mon Sep 17 00:00:00 2001 From: "Emanuele \"ToX\" Toscano" Date: Mon, 31 Jul 2023 15:09:19 +0200 Subject: [PATCH] Added stricter checks for Belgium and Germany --- .gitignore | 3 +- composer.json | 2 +- phpunit.xml.dist | 26 ++++++++-------- src/VatNumber.php | 77 ++++++++++++++++++++++++++++++++++++----------- tests/Test.php | 32 +++++++++++--------- 5 files changed, 91 insertions(+), 49 deletions(-) diff --git a/.gitignore b/.gitignore index e3c2ef3..d558b74 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,5 @@ Thumbs.db # IDE folders /.idea -/.vscode \ No newline at end of file +/.vscode +.phpunit.result.cache diff --git a/composer.json b/composer.json index 4d91581..4e9b02a 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,7 @@ "php": ">=7.0.0" }, "require-dev": { - "phpunit/phpunit": "^5.5" + "phpunit/phpunit": "*" }, "autoload": { "psr-4": { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 62fec58..df69949 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,15 +1,13 @@ - - - - - tests - - - - - - src - - - \ No newline at end of file + + + + src + + + + + tests + + + diff --git a/src/VatNumber.php b/src/VatNumber.php index 56241a3..f6e5b73 100644 --- a/src/VatNumber.php +++ b/src/VatNumber.php @@ -21,7 +21,6 @@ class VatNumber * * @param string $country Country code * @param string $code VAT number - * * @return bool */ public static function check(string $country, string $code): bool @@ -39,7 +38,7 @@ public static function check(string $country, string $code): bool return self::_checkLength($code, 11, 11) && self::_numbersOnly($code); case "BE": // 10 digits. - return self::_checkLength($code, 10, 10) && self::_numbersOnly($code); + return self::_checkLength($code, 10, 10) && self::_checkBelgium($code); case "BG": // 9 or 10 digits. return self::_checkLength($code, 9, 10) && self::_numbersOnly($code); @@ -49,6 +48,9 @@ public static function check(string $country, string $code): bool case "CA": // 9 characters. return self::_checkLength($code, 9, 9); + case "CO": + // 10 characters. + return self::_checkLength($code, 10, 10); case "HR": // 11 digits. return self::_checkLength($code, 11, 11) && self::_numbersOnly($code); @@ -75,7 +77,7 @@ public static function check(string $country, string $code): bool return self::_checkLength($code, 11, 11) && self::_checkFrance($code); case "DE": // 9 or 10 digits. - return self::_checkLength($code, 9, 9) && self::_numbersOnly($code); + return self::_checkLength($code, 9, 9) && self::_checkGermany($code); case "EL": // 9 digits. return self::_checkLength($code, 9, 9) && self::_numbersOnly($code); @@ -186,7 +188,6 @@ public static function check(string $country, string $code): bool * @param string $code VAT number * @param int $min Min length * @param int $max Max length - * * @return bool */ private static function _checkLength(string $code, int $min, int $max): bool @@ -198,7 +199,6 @@ private static function _checkLength(string $code, int $min, int $max): bool * Checks that a string is only numbers. * * @param string $code VAT number - * * @return bool */ private static function _numbersOnly(string $code): bool @@ -211,7 +211,6 @@ private static function _numbersOnly(string $code): bool * Eg. K99999999L or L99999999G * * @param string $code VAT number - * * @return bool */ private static function _checkAlbania(string $code): bool @@ -228,7 +227,6 @@ private static function _checkAlbania(string $code): bool * Eg. U12345678 * * @param string $code VAT number - * * @return bool */ private static function _checkAustria(string $code): bool @@ -241,12 +239,30 @@ private static function _checkAustria(string $code): bool return true; } + /** + * Additional validations for Belgium + * Eg. 09999999XX + * + * @param string $code VAT number + * @return bool + */ + private static function _checkBelgium(string $code): bool + { + if (!preg_match('/^\d{8}[0-9][0-9]$/', $code)) { + return false; + } + + $checkDigits = substr($code, 0, 8) % 97; + $checkDigits = sprintf('%02d', 97 - $checkDigits); + + return substr($code, 8, 2) == $checkDigits; + } + /** * Additional validations for Switzerland * Eg. 123.456.789 * * @param string $code VAT number - * * @return bool */ private static function _checkSwitzerland(string $code): bool @@ -264,7 +280,6 @@ private static function _checkSwitzerland(string $code): bool * Eg. 12345678X * * @param string $code VAT number - * * @return bool */ private static function _checkCyprus(string $code): bool @@ -282,7 +297,6 @@ private static function _checkCyprus(string $code): bool * Eg. 12345678901 - X1234567890 - 1X123456789 - XX123456789 * * @param string $code VAT number - * * @return bool */ private static function _checkFrance(string $code): bool @@ -300,11 +314,45 @@ private static function _checkFrance(string $code): bool return true; } + /** + * Additional validations for Germany + * Eg. 122265872 + * + * @param string $code VAT number + * @return bool + */ + private static function _checkGermany(string $code): bool + { + $count = 1; + $product = 10; + $sum = 0; + $checkDigit = intval(substr($code, -1)); + $result = 0; + + while ($count < 9) { + $sum = (intval(substr($code, $count - 1, 1)) + $product) % 10; + + if ($sum === 0) { + $sum = 10; + } + + $product = (2 * $sum) % 11; + $count++; + } + + $result = 11 - $product; + + if ($result === 10) { + $result = 0; + } + + return $result === $checkDigit; + } + /** * Additional validations for Ireland * * @param string $code Regional VAT code - * * @return bool */ private static function _checkIreland(string $code): bool @@ -324,7 +372,6 @@ private static function _checkIreland(string $code): bool * Additional validations for Italy * * @param string $code Regional VAT code - * * @return bool */ private static function _checkItaly(string $code): bool @@ -356,7 +403,6 @@ private static function _checkItaly(string $code): bool * Eg. MK4032013544513 * * @param string $code Regional VAT code - * * @return bool */ private static function _checkNorthMacedonia(string $code): bool @@ -373,7 +419,6 @@ private static function _checkNorthMacedonia(string $code): bool * Eg. 01012345-0001 * * @param string $code Regional VAT code - * * @return bool */ private static function _checkNigeria(string $code): bool @@ -389,7 +434,6 @@ private static function _checkNigeria(string $code): bool * Additional validations for Netherlands * * @param string $code Regional VAT code - * * @return bool */ private static function _checkNetherlands(string $code): bool @@ -406,7 +450,6 @@ private static function _checkNetherlands(string $code): bool * Additional validations for Norway * * @param string $code Regional VAT code - * * @return bool */ private static function _checkNorway(string $code): bool @@ -427,7 +470,6 @@ private static function _checkNorway(string $code): bool * Additional validations for Russia * * @param string $code Regional VAT code - * * @return bool */ private static function _checkRussia(string $code): bool @@ -443,7 +485,6 @@ private static function _checkRussia(string $code): bool * Additional validations for Spain * * @param string $code Regional VAT code - * * @return bool */ private static function _checkSpain(string $code): bool diff --git a/tests/Test.php b/tests/Test.php index 1b29706..3de1fa2 100644 --- a/tests/Test.php +++ b/tests/Test.php @@ -8,13 +8,13 @@ namespace Tox82\Tests\Validator; -use PHPUnit_Framework_TestCase; +use PHPUnit\Framework\TestCase; use Tox82\VatNumber; /** * Tests! */ -class VatTest extends PHPUnit_Framework_TestCase +class VatTest extends TestCase { /** * Valid VAT numbers should be valid! @@ -27,38 +27,41 @@ public function testCheckValids() $this->assertTrue(VatNumber::check('AL', 'L99999999G')); $this->assertTrue(VatNumber::check('AT', 'U12345678')); $this->assertTrue(VatNumber::check('AU', '12345678901')); - $this->assertTrue(VatNumber::check('BE', '1234567890')); + $this->assertTrue(VatNumber::check('BE', '1234567894')); $this->assertTrue(VatNumber::check('BG', '123456789')); $this->assertTrue(VatNumber::check('BG', '1234567890')); $this->assertTrue(VatNumber::check('BY', '190190190')); - $this->assertTrue(VatNumber::check('HR', '12345678901')); $this->assertTrue(VatNumber::check('CA', '1234567AB')); $this->assertTrue(VatNumber::check('CH', '123.456.789')); $this->assertTrue(VatNumber::check('CY', '12345678X')); $this->assertTrue(VatNumber::check('CZ', '12345678')); $this->assertTrue(VatNumber::check('CZ', '123456789')); $this->assertTrue(VatNumber::check('CZ', '1234567890')); + $this->assertTrue(VatNumber::check('DE', '122265872')); $this->assertTrue(VatNumber::check('DK', '12345678')); $this->assertTrue(VatNumber::check('EE', '123456789')); + $this->assertTrue(VatNumber::check('EL', '123456789')); + $this->assertTrue(VatNumber::check('ES', '12345678X')); + $this->assertTrue(VatNumber::check('ES', 'X12345678')); + $this->assertTrue(VatNumber::check('ES', 'X1234567X')); $this->assertTrue(VatNumber::check('FI', '12345678')); $this->assertTrue(VatNumber::check('FR', '12345678901')); $this->assertTrue(VatNumber::check('FR', '12345678901')); - $this->assertTrue(VatNumber::check('FR', 'X1234567890')); $this->assertTrue(VatNumber::check('FR', '1X123456789')); + $this->assertTrue(VatNumber::check('FR', 'X1234567890')); $this->assertTrue(VatNumber::check('FR', 'XX123456789')); - $this->assertTrue(VatNumber::check('DE', '123456789')); - $this->assertTrue(VatNumber::check('EL', '123456789')); $this->assertTrue(VatNumber::check('GB', '123456789')); + $this->assertTrue(VatNumber::check('HR', '12345678901')); $this->assertTrue(VatNumber::check('HU', '12345678')); $this->assertTrue(VatNumber::check('IE', '1234567X')); - $this->assertTrue(VatNumber::check('IE', '1X23456X')); $this->assertTrue(VatNumber::check('IE', '1234567XX')); + $this->assertTrue(VatNumber::check('IE', '1X23456X')); $this->assertTrue(VatNumber::check('IT', '00154189997')); - $this->assertTrue(VatNumber::check('LV', '12345678901')); $this->assertTrue(VatNumber::check('IT', '01573850516')); $this->assertTrue(VatNumber::check('LT', '123456789')); $this->assertTrue(VatNumber::check('LT', '123456789012')); $this->assertTrue(VatNumber::check('LU', '12345678')); + $this->assertTrue(VatNumber::check('LV', '12345678901')); $this->assertTrue(VatNumber::check('MK', 'MK4032013544513')); $this->assertTrue(VatNumber::check('MT', '12345678')); $this->assertTrue(VatNumber::check('NG', '01012345-0001')); @@ -79,12 +82,9 @@ public function testCheckValids() $this->assertTrue(VatNumber::check('RU', '9999999999')); $this->assertTrue(VatNumber::check('RU', '999999999999')); $this->assertTrue(VatNumber::check('RU', '9999999999999')); - $this->assertTrue(VatNumber::check('SK', '1234567890')); - $this->assertTrue(VatNumber::check('SI', '12345678')); - $this->assertTrue(VatNumber::check('ES', 'X12345678')); - $this->assertTrue(VatNumber::check('ES', '12345678X')); - $this->assertTrue(VatNumber::check('ES', 'X1234567X')); $this->assertTrue(VatNumber::check('SE', '123456789012')); + $this->assertTrue(VatNumber::check('SI', '12345678')); + $this->assertTrue(VatNumber::check('SK', '1234567890')); } /** @@ -108,6 +108,7 @@ public function testCheckWithInvalidLength() $this->assertFalse(VatNumber::check('AT', 'U123456780')); $this->assertFalse(VatNumber::check('AU', '123456789012')); $this->assertFalse(VatNumber::check('CA', '1234567ABC')); + $this->assertFalse(VatNumber::check('DE', '12226587')); $this->assertFalse(VatNumber::check('IT', '001541899970')); $this->assertFalse(VatNumber::check('MK', 'MK40320135445131')); $this->assertFalse(VatNumber::check('RU', '99999999999999')); @@ -124,8 +125,9 @@ public function testCheckWithInvalidCharacters() $this->assertFalse(VatNumber::check('AL', 'K999999999')); $this->assertFalse(VatNumber::check('AT', 'A12345678')); $this->assertFalse(VatNumber::check('AU', 'A2345678901')); + $this->assertFalse(VatNumber::check('DE', '122265873')); $this->assertFalse(VatNumber::check('IT', '01573850514')); $this->assertFalse(VatNumber::check('MK', 'AA4032013544513')); $this->assertFalse(VatNumber::check('NO', '123456789MV')); } -} \ No newline at end of file +}