Skip to content

Commit

Permalink
Added Validator
Browse files Browse the repository at this point in the history
  • Loading branch information
Evert Harmeling committed Jun 13, 2017
1 parent 0c5415d commit b53ab21
Show file tree
Hide file tree
Showing 7 changed files with 387 additions and 3 deletions.
1 change: 0 additions & 1 deletion .travis.yml
@@ -1,7 +1,6 @@
language: php

php:
- 5.5
- 5.6
- 7.0
- 7.1
Expand Down
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -9,7 +9,7 @@ The `http://www.controleerbtwnummer.nl/` API relies on the [VIES/EU](http://ec.e

## Installation

`composer install evertharmeling/vat-client`
`composer require evertharmeling/vat-client`

## Usage

Expand All @@ -26,3 +26,7 @@ catch (TaxableObjectNotFoundException $e) {
// VAT number not found
}
```

## Roadmap

- Formatter, add formatter who according to the regexes defined in the validator, formats the VAT number
10 changes: 10 additions & 0 deletions src/VIESApi/Exception/InvalidVATNumberException.php
@@ -0,0 +1,10 @@
<?php

namespace VIESApi\Exception;

/**
* @author Evert Harmeling <evert@freshheads.com>
*/
class InvalidVATNumberException extends \Exception implements VIESApiExceptionInterface
{
}
38 changes: 38 additions & 0 deletions src/VIESApi/Model/Country.php
@@ -0,0 +1,38 @@
<?php

namespace VIESApi\Model;

/**
* @author Evert Harmeling <evert@freshheads.com>
*/
class Country
{
const CODE_AUSTRIA = 'AT';
const CODE_BELGIUM = 'BE';
const CODE_BULGARY = 'BG';
const CODE_CYPRUS = 'CY';
const CODE_CZECH_REPUBLIC = 'CZ';
const CODE_GERMANY = 'DE';
const CODE_DENMARK = 'DK';
const CODE_ESTONIA = 'EE';
const CODE_GREECE = 'EL';
const CODE_SPAIN = 'ES';
const CODE_FINLAND = 'FI';
const CODE_FRANCE = 'FR';
const CODE_GREAT_BRITAIN = 'GB';
const CODE_CROATIA = 'HR';
const CODE_HUNGARY = 'HU';
const CODE_IRELAND = 'IE';
const CODE_ITALY = 'IT';
const CODE_LITHUANIA = 'LT';
const CODE_LUXEMBOURG = 'LU';
const CODE_LATVIA = 'LV';
const CODE_MALTA = 'MT';
const CODE_NETHERLANDS = 'NL';
const CODE_POLAND = 'PL';
const CODE_PORTUGAL = 'PT';
const CODE_ROMANIA = 'RO';
const CODE_SWEDEN = 'SE';
const CODE_SLOVENIA = 'SL';
const CODE_SLOVAKIA = 'SK';
}
173 changes: 173 additions & 0 deletions src/VIESApi/Validator/VATNumberValidator.php
@@ -0,0 +1,173 @@
<?php

namespace VIESApi\Validator;

use VIESApi\Client\Client;
use VIESApi\Exception\InvalidVATNumberException;
use VIESApi\Exception\VIESApiExceptionInterface;
use VIESApi\Model\Country;

/**
* @author Evert Harmeling <evert@freshheads.com>
*/
class VATNumberValidator
{
/**
* @var Client
*/
private $client;

/**
* @param Client $client
*/
public function __construct(Client $client)
{
$this->client = $client;
}

public function validate($value)
{
self::checkFormat($value);

try {
$this->client->getInfo($value);

return true;
} catch (VIESApiExceptionInterface $e) { }
}

/**
* Checks if the $value is the right format according to the country specifications
*
* @param string $value
* @return string
* @throws InvalidVATNumberException
*/
private static function checkFormat($value)
{
$countryCode = substr($value, 0, 2);

if (isset(self::getFiscalNumberFormatsPerCountry()[$countryCode])) {
$regexes = self::getFiscalNumberFormatsPerCountry()[$countryCode];

foreach ($regexes as $regex) {
preg_match($regex, $value, $matches);
if (count($matches)) {
return true;
}
}

throw new InvalidVATNumberException(sprintf("'%s' isn't a valid VATNumber according to the country (%s) specifications. It should match the regex: '%s'", $value, $countryCode, implode(', ', $regexes)));
}

throw new InvalidVATNumberException(sprintf("'%s' isn't a valid VATNumber according to the country (%s) specifications", $value, $countryCode));
}

/**
* @link https://www.btw-nummer-controle.nl/Userfiles/images/Format%20btw-nummers%20EU(4).pdf
*
* @return array
*/
private static function getFiscalNumberFormatsPerCountry()
{
return [
Country::CODE_AUSTRIA => [
self::regexify('U\d{9}')
],
Country::CODE_BELGIUM => [
self::regexify('0\d{9}')
],
Country::CODE_BULGARY => [
self::regexify('\d{9,10}')
],
Country::CODE_CYPRUS => [
self::regexify('\d{8}[A-Z]{1}')
],
Country::CODE_CZECH_REPUBLIC => [
self::regexify('\d{8,10}')
],
Country::CODE_GERMANY => [
self::regexify('\d{9}')
],
Country::CODE_DENMARK => [
self::regexify('\d{2}\s{1}\d{2}\s{1}\d{2}\s{1}\d{2}')
],
Country::CODE_ESTONIA => [
self::regexify('\d{9}')
],
Country::CODE_GREECE => [
self::regexify('\d{9}')
],
Country::CODE_SPAIN => [
self::regexify('[0-9A-Z]{1}\d{7}[0-9A-Z]{1}')
],
Country::CODE_FINLAND => [
self::regexify('\d{8}')
],
Country::CODE_FRANCE => [
self::regexify('[0-9A-Z]{2}\s{1}\d{9}')
],
Country::CODE_GREAT_BRITAIN => [
self::regexify('\d{3}\s{1}\d{4}\s{1}\d{2}'),
self::regexify('\d{3}\s{1}\d{4}\s{1}\d{2}\s{1}\d{3}'),
self::regexify('GD|HA\d{3}')
],
Country::CODE_CROATIA => [
self::regexify('\d{11}')
],
Country::CODE_HUNGARY => [
self::regexify('\d{8}')
],
Country::CODE_IRELAND => [
self::regexify('\d{1}[0-9A-Z+*]{1}\d{5}[A-Z]{1}')
],
Country::CODE_ITALY => [
self::regexify('\d{11}')
],
Country::CODE_LITHUANIA => [
self::regexify('\d{9}'),
self::regexify('\d{12}')
],
Country::CODE_LUXEMBOURG => [
self::regexify('\d{8}')
],
Country::CODE_LATVIA => [
self::regexify('\d{11}')
],
Country::CODE_MALTA => [
self::regexify('\d{8}')
],
Country::CODE_NETHERLANDS => [
self::regexify('\d{9}B\d{2}')
],
Country::CODE_POLAND => [
self::regexify('\d{10}')
],
Country::CODE_PORTUGAL => [
self::regexify('\d{9}')
],
Country::CODE_ROMANIA => [
self::regexify('\d{2,10}')
],
Country::CODE_SWEDEN => [
self::regexify('\d{12}')
],
Country::CODE_SLOVENIA => [
self::regexify('\d{8}')
],
Country::CODE_SLOVAKIA => [
self::regexify('\d{10}')
]
];
}

/**
* @param string $value
* @return string
*/
private static function regexify($value)
{
// always add 2-letter country code to the regex
return sprintf('/^[A-Z]{2}%s$/', $value);
}
}
2 changes: 1 addition & 1 deletion tests/VIESApi/Client/ClientTest.php
Expand Up @@ -13,7 +13,7 @@
class ClientTest extends \PHPUnit_Framework_TestCase
{
const VAT_NUMBER = 'NL818918172B01';
const VAT_NUMBER_INVALID = 'NL818918172B02';
const VAT_NUMBER_INVALID = 'NL818918172B99';

public function testGetInfo()
{
Expand Down

0 comments on commit b53ab21

Please sign in to comment.