Skip to content

Commit 1a4df7c

Browse files
committed
Initial commit
1 parent a2874ae commit 1a4df7c

File tree

6 files changed

+318
-0
lines changed

6 files changed

+318
-0
lines changed

README.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Greek VAT ID Validator for Laravel
2+
3+
The Greek VAT ID validator checks if a number is POTENTIALLY valid in Greek VAT ID Registry.
4+
5+
Validator does NOT check if VAT ID does actually belong to a person or a company, it checks only if it obeys the algorithm of a valid Greek VAT ID:
6+
7+
```
8+
1. VAT ID = 090000045
9+
2. Calculate sum of 0*2^8+9*2^7+0*2^6+0*2^5+0*2^4+0*2^3+0*2^2+4*2^1 = 1160
10+
3. Calculate mod11 = 1160 % 11 = 5
11+
4. Calculate mod10 = 5 % 10 = 5
12+
5. mod10 (5) is not equal to 5 (last digit), so VAT ID is VALID
13+
```
14+
15+
```
16+
1. VAT ID = 123456789
17+
2. Calculate sum of 1*2^8+2*2^7+3*2^6+4*2^5+5*2^4+6*2^3+7*2^2+8*2^1 = 1004
18+
3. Calculate mod11 = 1004 % 11 = 3
19+
4. Calculate mod10 = 3 % 10 = 3
20+
5. mod10 (3) is not equal to 9 (last digit), so VAT ID is INVALID
21+
```
22+
23+
## Installation
24+
25+
Install the package using Composer:
26+
27+
```
28+
composer require liagkos/laravel-grvatid-validator
29+
```
30+
31+
Laravel's service provider discovery will automatically configure the Grvatval service provider for you.
32+
33+
## Using the `grvatval` validator
34+
35+
After installation, the `grvatval` validator will be available for use directly in your validation rules.
36+
```php
37+
'vatid' => 'grvatval',
38+
```
39+
40+
Within the context of a registration form, it would look like this:
41+
```php
42+
return Validator::make($data, [
43+
'name' => 'required',
44+
'email' => 'required|string|email',
45+
'password' => 'required',
46+
'vatid' => 'required|grvatval'
47+
]);
48+
```
49+
50+
## Using the Rule Object
51+
52+
Alternatively, you can use the `Liagkos\Grvatval\Grvatval` [Validation Rule Object](https://laravel.com/docs/5.5/validation#using-rule-objects)
53+
instead of the `grvatval` alias if you prefer:
54+
55+
```php
56+
return Validator::make($data, [
57+
'name' => 'required',
58+
'email' => 'required|string|email',
59+
'password' => 'required',
60+
'vatid' => ['required', new \Liagkos\Grvatval\Grvatval],
61+
]);
62+
```
63+
64+
## Validation message
65+
66+
You will need to assign your own validation message within the `resources/lang/*/validation.php` file(s).
67+
Both the Rule object and the `grvatval` validator alias refer to the validation string `validation.grvatval`.
68+
69+
## Testing
70+
71+
Just run the the test in `tests` directory. I use the [orchestra/testbench](https://github.com/orchestral/testbench) along with PHPUnit.
72+
73+
## Credits
74+
75+
Since I'm quite new in all Laravel stuff, I got the idea from [Stephen Rees-Carten](https://github.com/valorin) and his own [valorin/pwned-validator](https://github.com/valorin/pwned-validator) validator, from whom I used some code and README.md stuff, modified accordingly to make this validator. Thank you Stephen, live long and propsper!

composer.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "liagkos/laravel-grvatid-validator",
3+
"description": "Validator for Laravel in order to check if a number is POTENTIALLY valid in Greek VAT ID Registry",
4+
"version": "v1.0.0",
5+
"license": "MIT",
6+
"authors": [
7+
{
8+
"name": "Athanasios (Nasos) Liagkos",
9+
"email": "[email protected]"
10+
}
11+
],
12+
"autoload": {
13+
"psr-4": {
14+
"Liagkos\\Grvatval\\": "src/"
15+
}
16+
},
17+
"require": {
18+
"php": ">=7.1.3",
19+
"illuminate/support": "~5.5"
20+
},
21+
"require-dev": {
22+
"orchestra/testbench": "~3.0"
23+
},
24+
"extra": {
25+
"laravel": {
26+
"providers": [
27+
"Liagkos\\Grvatval\\ServiceProvider"
28+
]
29+
}
30+
}
31+
}

phpunit.xml.dist

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit bootstrap="../../autoload.php"
3+
backupGlobals="false"
4+
backupStaticAttributes="false"
5+
colors="true"
6+
verbose="true"
7+
convertErrorsToExceptions="true"
8+
convertNoticesToExceptions="true"
9+
convertWarningsToExceptions="true"
10+
processIsolation="false"
11+
stopOnFailure="false">
12+
<testsuites>
13+
<testsuite name="Laravel Greek VAT ID Validator Test Suite">
14+
<directory>tests</directory>
15+
</testsuite>
16+
</testsuites>
17+
<filter>
18+
<whitelist>
19+
<directory suffix=".php">src/</directory>
20+
</whitelist>
21+
</filter>
22+
</phpunit>

src/Grvatval.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
namespace Liagkos\Grvatval;
3+
4+
use Illuminate\Contracts\Validation\Rule;
5+
use Illuminate\Support\Facades\Lang;
6+
7+
/**
8+
* Class Grvatval
9+
* @package Liagkos\Grvatval
10+
*/
11+
class Grvatval implements Rule
12+
{
13+
/**
14+
* @param $attribute string Form attribute
15+
* @param $value string VAT ID
16+
* @param null $params
17+
*
18+
* @return bool
19+
*/
20+
public function validate($attribute, $value, $params = null)
21+
{
22+
return $this->passes($attribute, $value);
23+
}
24+
25+
/**
26+
* @param $attribute string Form attribute
27+
* @param $value string VAT ID
28+
*
29+
* @return bool
30+
*/
31+
public function passes($attribute, $value)
32+
{
33+
// No need for 'numeric' validation rule
34+
if (strlen($value) != 9 || !is_numeric($value)) {
35+
return false;
36+
}
37+
38+
return $this->checkMod($value);
39+
}
40+
41+
/**
42+
* Make the actual check
43+
*
44+
* a. Get the first 8 digits
45+
* b. Calculate sum of product digit * 2^(8-digit index[0..8])
46+
* c. Calculate sum mod11 mod10
47+
* d. Result must be the same as last (9th) digit
48+
*
49+
* @param $value string VAT ID
50+
*
51+
* @return bool
52+
*/
53+
private function checkMod($value)
54+
{
55+
$digits = str_split(substr($value, 0, -1));
56+
$sum = 0;
57+
foreach ($digits as $index => $digit) {
58+
$sum += $digit * pow(2, 8 - $index);
59+
}
60+
return $sum % 11 % 10 == (int) $value[8];
61+
}
62+
63+
/**
64+
* @return mixed
65+
*/
66+
public function message()
67+
{
68+
return Lang::get('validation.grvatval');
69+
}
70+
}

src/ServiceProvider.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
namespace Liagkos\Grvatval;
3+
4+
Use Illuminate\Support\Facades\Validator;
5+
use Illuminate\Support\ServiceProvider as BaseServiceProvider;
6+
7+
class ServiceProvider extends BaseServiceProvider
8+
{
9+
/**
10+
* Bootstrap any application services.
11+
*
12+
* @return void
13+
*/
14+
public function boot()
15+
{
16+
Validator::extend('grvatval', Grvatval::class);
17+
}
18+
19+
/**
20+
* Register any application services.
21+
*
22+
* @return void
23+
*/
24+
public function register()
25+
{
26+
//
27+
}
28+
}

tests/GrvatvalTests.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
namespace Liagkos\Grvatval\Tests;
3+
4+
use Liagkos\Grvatval\Grvatval;
5+
use Orchestra\Testbench\TestCase;
6+
7+
/**
8+
* Class GrvatvalTests
9+
* @package Liagkos\Grvatval\Tests
10+
*/
11+
class GrvatvalTests extends TestCase
12+
{
13+
/**
14+
* @var \Validator Laravel validator instance
15+
*/
16+
protected $validator;
17+
18+
/**
19+
* @var string Form attribute
20+
*/
21+
protected $attribute;
22+
23+
/**
24+
* @var string Valid numeric VAT ID
25+
*/
26+
protected $validVatId;
27+
28+
/**
29+
* @var string Invalid numeric VAT ID with correct length
30+
*/
31+
protected $invalidVatId;
32+
33+
/**
34+
* @var string Invalid numeric VAT ID length
35+
*/
36+
protected $invalidVatIdShortNumber;
37+
38+
/**
39+
* @var string Invalid VAT ID combination with characters
40+
*/
41+
protected $invalidVatIdString;
42+
43+
/**
44+
* Prepare the test case and assign values
45+
*/
46+
public function setUp()
47+
{
48+
parent::setUp();
49+
$this->attribute = 'vatid'; // Form attribute, just for testing
50+
$this->validVatId = '090000045'; // Public Energy Corporation
51+
$this->invalidVatId = '090000044'; // Wrong VAT ID
52+
$this->invalidVatIdShortNumber = '09000004'; // Missing last number
53+
$this->invalidVatId = '09000004A'; // Characters instead of numbers
54+
}
55+
56+
/**
57+
* Test validate method of validator
58+
*/
59+
public function testValidate()
60+
{
61+
$this->assertTrue($this->validate($this->validVatId)->passes());
62+
$this->assertTrue($this->validate($this->invalidVatId)->fails());
63+
$this->assertTrue($this->validate($this->invalidVatIdShortNumber)->fails());
64+
$this->assertTrue($this->validate($this->invalidVatIdString)->fails());
65+
}
66+
67+
/**
68+
* Test message method of validator depending on value of VAT ID
69+
*/
70+
public function testMessage()
71+
{
72+
$this->assertEquals(0, $this->validate($this->validVatId)->messages()->count());
73+
$this->assertEquals(1, $this->validate($this->invalidVatId)->messages()->count());
74+
$this->assertEquals(1, $this->validate($this->invalidVatIdShortNumber)->messages()->count());
75+
$this->assertEquals(1, $this->validate($this->invalidVatIdString)->messages()->count());
76+
}
77+
78+
/**
79+
* Create and call the validator
80+
*
81+
* @param $vatId string VAT ID to check
82+
*
83+
* @return mixed
84+
*/
85+
protected function validate($vatId)
86+
{
87+
return \Validator::make(
88+
[$this->attribute => $vatId],
89+
[$this->attribute => new Grvatval($this->attribute, $vatId)]
90+
);
91+
}
92+
}

0 commit comments

Comments
 (0)