├── .github
└── workflows
│ └── php.yml
├── .gitignore
├── .sensiolabs.yml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENCE
├── README.md
├── bin
└── vatcheck
├── build.xml
├── composer.json
├── docs
└── images
│ └── vies-web-screenshot.png
├── examples
├── EURailwayVATChecker.php
├── async_processing
│ ├── .gitignore
│ ├── README.md
│ ├── list.php
│ ├── queue.php
│ ├── vatqueue.sql
│ └── worker.php
├── checkVat.php
├── checkVatBatch.php
├── checkVatWithDetails.php
└── vatins.php
├── infection.json.dist
├── phpcs.xml
├── phpunit.xml
├── sonar-project.properties
├── src
├── Vies
│ ├── CheckVatResponse.php
│ ├── HeartBeat.php
│ ├── Validator
│ │ ├── ValidatorAT.php
│ │ ├── ValidatorAbstract.php
│ │ ├── ValidatorBE.php
│ │ ├── ValidatorBG.php
│ │ ├── ValidatorCY.php
│ │ ├── ValidatorCZ.php
│ │ ├── ValidatorDE.php
│ │ ├── ValidatorDK.php
│ │ ├── ValidatorEE.php
│ │ ├── ValidatorEL.php
│ │ ├── ValidatorES.php
│ │ ├── ValidatorEU.php
│ │ ├── ValidatorFI.php
│ │ ├── ValidatorFR.php
│ │ ├── ValidatorGB.php
│ │ ├── ValidatorHR.php
│ │ ├── ValidatorHU.php
│ │ ├── ValidatorIE.php
│ │ ├── ValidatorIT.php
│ │ ├── ValidatorInterface.php
│ │ ├── ValidatorLT.php
│ │ ├── ValidatorLU.php
│ │ ├── ValidatorLV.php
│ │ ├── ValidatorMT.php
│ │ ├── ValidatorNL.php
│ │ ├── ValidatorPL.php
│ │ ├── ValidatorPT.php
│ │ ├── ValidatorRO.php
│ │ ├── ValidatorSE.php
│ │ ├── ValidatorSI.php
│ │ ├── ValidatorSK.php
│ │ └── ValidatorXI.php
│ ├── Vies.php
│ ├── ViesException.php
│ └── ViesServiceException.php
└── autoload.php
└── tests
└── Vies
├── CheckVatResponseTest.php
├── HeartBeatTest.php
├── Validator
├── AbstractValidatorTest.php
├── ValidatorATTest.php
├── ValidatorBETest.php
├── ValidatorBGTest.php
├── ValidatorCYTest.php
├── ValidatorCZTest.php
├── ValidatorDETest.php
├── ValidatorDKTest.php
├── ValidatorEETest.php
├── ValidatorELTest.php
├── ValidatorESTest.php
├── ValidatorEUTest.php
├── ValidatorFITest.php
├── ValidatorFRTest.php
├── ValidatorGBTest.php
├── ValidatorHRTest.php
├── ValidatorHUTest.php
├── ValidatorIETest.php
├── ValidatorITTest.php
├── ValidatorLTTest.php
├── ValidatorLUTest.php
├── ValidatorLVTest.php
├── ValidatorMTTest.php
├── ValidatorNLTest.php
├── ValidatorPLTest.php
├── ValidatorPTTest.php
├── ValidatorROTest.php
├── ValidatorSETest.php
├── ValidatorSITest.php
├── ValidatorSKTest.php
└── ValidatorXITest.php
├── ValidatorTest.php
├── ViesTest.php
└── _files
├── checkVatService.wsdl
├── checkVatTestService.wsdl
└── soapVersionCheck.code
/.github/workflows/php.yml:
--------------------------------------------------------------------------------
1 | name: PHP Composer
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | build:
11 | name: ViesBuild
12 | runs-on: ${{ matrix.operating-system }}
13 | strategy:
14 | matrix:
15 | operating-system: [ubuntu-latest]
16 | php-versions: ['7.4', '8.0', '8.1']
17 |
18 | steps:
19 | - name: Set default PHP version ${{ matrix.php-versions }}
20 | uses: shivammathur/setup-php@v2
21 | with:
22 | php-version: "${{ matrix.php-versions }}"
23 |
24 | - name: Display current PHP version
25 | run: php --version
26 |
27 | - uses: actions/checkout@v2
28 |
29 | - name: Validate composer.json and composer.lock
30 | run: composer validate
31 |
32 | - name: Cache Composer packages
33 | id: composer-cache
34 | uses: actions/cache@v2
35 | with:
36 | path: vendor
37 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
38 | restore-keys: |
39 | ${{ runner.os }}-php-
40 |
41 | - name: Install dependencies
42 | if: steps.composer-cache.outputs.cache-hit != 'true'
43 | run: |
44 | composer config --no-plugins allow-plugins.infection/extension-installer true
45 | composer install --prefer-dist --no-progress --no-suggest
46 |
47 | - name: Prepare for Quality
48 | run: /bin/sh -c 'mkdir -p ${{ github.workspace }}/build/logs && touch ${{ github.workspace }}/build/logs/checkstyle.xml'
49 |
50 | - name: Run PHP CodeSniffer
51 | run: ${{ github.workspace }}/vendor/bin/phpcs
52 |
53 | - name: Run PHPUnit
54 | run: php -dxdebug.mode=coverage ${{ github.workspace }}/vendor/bin/phpunit
55 |
56 | - name: Run PMD-Naming
57 | run: ${{ github.workspace }}/vendor/bin/phpmd src xml naming --reportfile build/logs/pmd-naming.xml --strict --ignore-violations-on-exit
58 |
59 | - name: Run PMD-Unused
60 | run: ${{ github.workspace }}/vendor/bin/phpmd src xml unusedcode --reportfile build/logs/pmd-unusedcode.xml --strict --ignore-violations-on-exit
61 |
62 | - name: Run PMD-Codesize
63 | run: ${{ github.workspace }}/vendor/bin/phpmd src xml codesize --reportfile build/logs/pmd-codesize.xml --strict --ignore-violations-on-exit
64 |
65 | - name: Run PMD-Cleancode
66 | run: ${{ github.workspace }}/vendor/bin/phpmd src xml cleancode --reportfile build/logs/pmd-cleancode.xml --strict --ignore-violations-on-exit
67 |
68 | - name: Run PDepend
69 | run: ${{ github.workspace }}/vendor/bin/pdepend --jdepend-chart=build/logs/jdepend-chart.svg --jdepend-xml=build/logs/jdepend.xml --overview-pyramid=build/logs/pyramid.svg src
70 |
71 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | build/
3 | .phpunit.result.cache
4 | composer.lock
5 | composer.phar
6 | .scannerwork/
7 | .idea/
8 |
9 |
--------------------------------------------------------------------------------
/.sensiolabs.yml:
--------------------------------------------------------------------------------
1 | global_exclude_dirs:
2 | - vendor
3 | - examples
4 | - tests
5 |
6 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | nationality, personal appearance, race, religion, or sexual identity and
10 | orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at [dragonbe+github@gmail.com](mailto:dragonbe+github@gmail.com). All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct/
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Contributing
2 |
3 | First off, thank you for considering contributing to VIES. It's people
4 | like you that make VIES such a great tool for anyone who needs to validate
5 | VAT ID's within the European Union.
6 |
7 | ### 1. Where do I go from here?
8 |
9 | If you've noticed a bug or have a question, [search the issue tracker](https://github.com/dragonbe/vies/issues?q=something)
10 | to see if someone else in the community has already created a ticket.
11 | If not, go ahead and [make one](https://github.com/dragonbe/vies/issues/new)!
12 |
13 | ### 2. Fork the project and create a branch
14 |
15 | If this is something you think you can fix, then
16 | [fork VIES](https://help.github.com/articles/fork-a-repo)
17 | and create a branch with a descriptive name.
18 |
19 | A good branch name would be (where issue #123 is the ticket you're working on):
20 |
21 | ```sh
22 | git checkout -b 123-update-be-vat-numbers
23 | ```
24 |
25 | ### 3. Get the test suite running
26 |
27 | Make sure you're using the most recent PHP version:
28 |
29 | - 1.0 branch requires PHP 5.6.x or higher
30 | - 2.0 branch requires PHP 7.1.x or higher
31 |
32 | Now install PHP packages using [composer](https://getcomposer.org):
33 |
34 | ```sh
35 | composer install
36 | ```
37 |
38 | At this point you should be able to run the entire test suite using:
39 |
40 | ```sh
41 | ./vendor/bin/phpunit
42 | ```
43 |
44 | ### 4. Did you find a bug?
45 |
46 | * **Ensure the bug was not already reported** by [searching all
47 | issues](https://github.com/dragonbe/vies/issues?q=).
48 |
49 | * If you're unable to find an open issue addressing the problem, [open a new
50 | one](https://github.com/dragonbe/vies/issues/new). Be sure to
51 | include a **title and clear description**, as much relevant information as
52 | possible, and a **code sample** or an **executable test case** demonstrating
53 | the expected behavior that is not occurring.
54 |
55 | ### 5. Implement your fix or feature
56 |
57 | At this point, you're ready to make your changes! Feel free to ask for help;
58 | everyone is a beginner at first :smile_cat:
59 |
60 | ### 6. Make a Pull Request
61 |
62 | At this point, you should switch back to your master branch and make sure it's
63 | up to date with VIES's master branch:
64 |
65 | ```sh
66 | git remote add upstream git@github.com:dragonbe/vies.git
67 | git checkout master
68 | git pull upstream master
69 | ```
70 |
71 | Then update your feature branch from your local copy of master, and push it!
72 |
73 | ```sh
74 | git checkout 123-update-be-vat-numbers
75 | git rebase master
76 | git push --set-upstream origin 123-update-be-vat-numbers
77 | ```
78 |
79 | Replace `123-update-be-vat-numbers` with the branch name you have given yourself.
80 |
81 | Finally, go to GitHub and
82 | [make a Pull Request](https://help.github.com/articles/creating-a-pull-request)
83 | :D
84 |
85 | Travis CI will run our test suite against all supported PHP versions. We care
86 | about quality, so your PR won't be merged until all tests pass. It's unlikely,
87 | but it's possible that your changes pass tests in one PHP version but fails in
88 | another. In that case, you'll have to setup your development environment (as
89 | explained in step 3) to use the problematic PHP version, and investigate
90 | what's going on!
91 |
92 | The [PHP containers on Docker HUB](https://hub.docker.com/_/php) might be
93 | convenient for this purpose. You might want to make use of them.
94 |
95 | ### 7. Keeping your Pull Request updated
96 |
97 | If a maintainer asks you to "rebase" your PR, they're saying that a lot of code
98 | has changed, and that you need to update your branch so it's easier to merge.
99 |
100 | To learn more about rebasing in Git, there are a lot of
101 | [good](http://git-scm.com/book/en/Git-Branching-Rebasing)
102 | [resources](https://help.github.com/articles/interactive-rebase),
103 | but here's the suggested workflow:
104 |
105 | ```sh
106 | git checkout 123-update-be-vat-numbers
107 | git pull --rebase upstream master
108 | git push --force-with-lease 123-update-be-vat-numbers
109 | ```
110 |
111 | ### 8. Merging a PR (maintainers only)
112 |
113 | A PR can only be merged into master by a maintainer if:
114 |
115 | * It is passing CI.
116 | * It has been approved by at least two maintainers. If it was a maintainer who
117 | opened the PR, only one extra approval is needed.
118 | * It has no requested changes.
119 | * It is up to date with current master.
120 |
121 | Any maintainer is allowed to merge a PR if all of these conditions are
122 | met.
123 |
124 | ### 9. Shipping a release (maintainers only)
125 |
126 | Maintainers need to do the following to push out a release:
127 |
128 | * Make sure all pull requests are in
129 | * Create a stable branch for that release:
130 |
131 | This example explains the process to tag a new version on the 2.0 branch, where
132 | `upstream` references [dragonbe/vies](https://github.com/dragonbe/vies)and 2.0.8
133 | is our latest tag.
134 |
135 | ```sh
136 | git fetch upstream
137 | git checkout master
138 | git pull --rebase upstream master
139 | git checkout 2.0
140 | git merge master
141 | git tag -a 2.0.9
142 | git push upstream 2.0.9
143 | ```
144 |
145 | That's all there is to it.
146 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Michelangelo van Dam
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VIES
2 |
3 | Component using the European Commission (EC) VAT Information Exchange System (VIES) to verify and validate VAT registration numbers in the EU, using PHP and Composer.
4 |
5 | The `Vies` class provides functionality to make a SOAP call to VIES and returns an object `CheckVatResponse` containing the following information:
6 |
7 | - Country code (string): a 2-character notation of the country code
8 | - VAT registration number (string): contains the complete registration number without the country code
9 | - Date of request (DateTime): the date when the request was made
10 | - Valid (boolean): flag indicating the registration number was valid (TRUE) or not (FALSE)
11 | - Name (string): registered company name (if provided by EC member state)
12 | - Address (string): registered company address (if provided by EC member state)
13 |
14 | Stated on the European Commission website:
15 | > To make an intra-Community supply without charging VAT, you **should ensure** that the person to whom you are supplying the goods is a taxable person in another Member State, and that the goods in question have left, or will leave your Member State to another MS. VAT-number should also be in the invoice.
16 |
17 | More information at http://ec.europa.eu/taxation_customs/vies/faqvies.do#item16
18 |
19 | [](https://github.com/DragonBe/vies/actions) [](https://sonarcloud.io/dashboard?id=dragonbe-vies)
20 |
21 | ## GDPR and privacy regulation of VAT within the EU
22 |
23 | On May 25, 2018 the General Data Protection Regulation or GDPR becomes law within all 28 European Member States. Is this VIES service package going to be compliant with GDPR?
24 |
25 | In short: yes.
26 |
27 | The longer answer is that this VIES package only interacts with the service for VAT ID verification provided by the European Commission. VAT validation is mandatory in European countries and therefor this service is allowed as lawfulness and legal basis. Please read more about this in [European DPO-3816.1](http://ec.europa.eu/dpo-register/details.htm?id=40647). This service does not store any data itself or collects more information than what's strictly required by law and provided by the EC VIES service.
28 |
29 | When you have implemented this service package in your own project, be sure that you're making sure you're just store the VAT ID, the timestamp of validation, the result of validation and optionally the given validation ID provided by the EC VIES service.
30 |
31 | ## Requirements
32 |
33 | - Minimum PHP version: 7.3
34 | - Recommended PHP version: 7.4
35 | - Extension: soap
36 | - Extension: pcntl
37 | - Extension: ctype
38 |
39 | Please read the [release notes](https://github.com/DragonBe/vies/releases) for details.
40 |
41 | ## Installation
42 |
43 | This project is on [Packagist](https://packagist.org/packages/dragonbe/vies)!
44 |
45 | To install the latest stable version use `composer require dragonbe/vies`.
46 |
47 | To install specifically a version (e.g. 2.2.0), just add it to the command above, for example `composer require dragonbe/vies:2.2.0`
48 |
49 | ## Usage
50 |
51 | Here's a usage example you can immediately execute on the command line (or in cron, worker or whatever) as this will most likely be your most common usecase.
52 |
53 | ### 1. Setting it up
54 |
55 | ```php
56 | getHeartBeat()->isAlive()) {
71 |
72 | echo 'Service is not available at the moment, please try again later.' . PHP_EOL;
73 | exit(1);
74 | }
75 | ```
76 |
77 | #### If using a proxy, you can now use the following approach
78 |
79 | ```php
80 | $vies = new Vies();
81 | $options = [
82 | 'proxy_host' => '127.0.0.1',
83 | 'proxy_port' => '8888',
84 | ];
85 | $vies->setOptions($options);
86 |
87 | $heartBeat = new \DragonBe\Vies\HeartBeat('tcp://' . $options['proxy_host'], $options['proxy_port']);
88 | $vies->setHeartBeat($heartBeat);
89 |
90 | $isAlive = $vies->getHeartBeat()->isAlive();
91 | ```
92 |
93 | ### 3. Validate VAT
94 |
95 | Now that we know the service is alive, we can start validating VAT ID's
96 |
97 | #### 3.1. Simple usage
98 |
99 | ```php
100 | $vatResult = $vies->validateVat(
101 | 'BE', // Trader country code
102 | '0203430576', // Trader VAT ID
103 | 'BE', // Requester country code
104 | '0811231190' // Requester VAT ID
105 | );
106 | ```
107 |
108 | #### 3.2. Advanced usage
109 |
110 | ```php
111 | $vatResult = $vies->validateVat(
112 | 'BE', // Trader country code
113 | '0203430576', // Trader VAT ID
114 | 'BE', // Requester country code
115 | '0811231190' // Requester VAT ID
116 | 'B-Rail', // Trader name
117 | 'NV', // Trader company type
118 | 'Frankrijkstraat 65', // Trader street address
119 | '1060', // Trader postcode
120 | 'Sint-Gillis' // Trader city
121 | );
122 | ```
123 |
124 | #### 3.3. Result methods
125 |
126 | ##### 3.3.1. Is the VAT ID valid?
127 |
128 | The most important functionality is to see if the VAT ID is valid
129 |
130 | ```php
131 | echo ($vatResult->isValid() ? 'Valid' : 'Not valid') . PHP_EOL;
132 |
133 | // Result: Valid
134 | ```
135 |
136 | ##### 3.3.2. Retrieve the VAT validation identifier
137 |
138 | ```php
139 | echo 'Identifier: ' . $vatResult->getIdentifier() . PHP_EOL;
140 |
141 | // Result: Identifier: WAPIAAAAWaXGj4Ra
142 | ```
143 |
144 | ##### 3.3.3. Retrieve validation date
145 |
146 | **Note: VIES service returns date and timezone, but no time**
147 |
148 | ```php
149 | echo 'Date and time: ' . $vatResult->getRequestDate()->format('r') . PHP_EOL;
150 |
151 | // Result: Date and time: Sat, 31 Aug 2019 00:00:00 +0200
152 | ```
153 |
154 | ##### 3.3.4. Retrieve official trader name (not always available)
155 |
156 | ```php
157 | echo 'Company name: ' . $vatResult->getName() . PHP_EOL;
158 |
159 | // Result: Company name: NV OR NATIONALE MAATSCHAPPIJ DER BELGISCHE SPOORWEGEN
160 | ```
161 |
162 | ##### 3.3.5. Retrieve official trader street (not always available)
163 |
164 | ```php
165 | echo 'Company address: ' . $vatResult->getAddress() . PHP_EOL;
166 |
167 | // Result: Company address: FRANKRIJKSTRAAT 56
168 | 1060 SINT-GILLIS (BIJ-BRUSSEL)
169 | ```
170 |
171 | ##### 3.3.6. Retrieve a match for trader name (not always available)
172 |
173 | ```php
174 | echo 'Trader name match: ' . $vatResult->getNameMatch() . PHP_EOL;
175 |
176 | // Result: Trader name match:
177 | ```
178 |
179 | ##### 3.3.7. Retrieve a match for trader company type (not always available)
180 |
181 | ```php
182 | echo 'Trader company type match: ' . $vatResult->getCompanyTypeMatch() . PHP_EOL;
183 |
184 | // Result: Trader company type match:
185 | ```
186 |
187 | ##### 3.3.8. Retrieve a match for trader street (not always available)
188 |
189 | ```php
190 | echo 'Trader street match: ' . $vatResult->getStreetMatch() . PHP_EOL;
191 |
192 | // Result: Trader street match:
193 | ```
194 |
195 | ##### 3.3.9. Retrieve a match for trader postcode (not always available)
196 |
197 | ```php
198 | echo 'Trader postcode match: ' . $vatResult->getPostcodeMatch() . PHP_EOL;
199 |
200 | // Result: Trader postcode match:
201 | ```
202 |
203 | ##### 3.3.10. Retrieve a match for trader city (not always available)
204 |
205 | ```php
206 | echo 'Trader city match: ' . $vatResult->getCityMatch() . PHP_EOL;
207 |
208 | // Result: Trader city match:
209 | ```
210 |
211 | ### Example code
212 |
213 | ```php
214 | 'BE',
226 | 'vat_id' => '0203430576',
227 | 'trader_name' => 'B-Rail',
228 | 'trader_company_type' => 'NV',
229 | 'trader_street' => 'Frankrijkstraat 65',
230 | 'trader_postcode' => '1060',
231 | 'trader_city' => 'Sint-Gillis',
232 | ];
233 |
234 | try {
235 | $vatResult = $vies->validateVat(
236 | $company['country_code'], // Trader country code
237 | $company['vat_id'], // Trader VAT ID
238 | 'BE', // Requester country code (your country code)
239 | '0811231190', // Requester VAT ID (your VAT ID)
240 | $company['trader_name'], // Trader name
241 | $company['trader_company_type'], // Trader company type
242 | $company['trader_street'], // Trader street address
243 | $company['trader_postcode'], // Trader postcode
244 | $company['trader_city'] // Trader city
245 | );
246 | } catch (ViesException $viesException) {
247 | echo 'Cannot process VAT validation: ' . $viesException->getMessage();
248 | exit (2);
249 | } catch (ViesServiceException $viesServiceException) {
250 | echo 'Cannot process VAT validation: ' . $viesServiceException->getMessage();
251 | exit (2);
252 | }
253 |
254 | echo ($vatResult->isValid() ? 'Valid' : 'Not valid') . PHP_EOL;
255 | echo 'Identifier: ' . $vatResult->getIdentifier() . PHP_EOL;
256 | echo 'Date and time: ' . $vatResult->getRequestDate()->format('d/m/Y H:i') . PHP_EOL;
257 | echo 'Company name: ' . $vatResult->getName() . PHP_EOL;
258 | echo 'Company address: ' . $vatResult->getAddress() . PHP_EOL;
259 |
260 | echo 'Trader name match: ' . $vatResult->getNameMatch() . PHP_EOL;
261 | echo 'Trader company type match: ' . $vatResult->getCompanyTypeMatch() . PHP_EOL;
262 | echo 'Trader street match: ' . $vatResult->getStreetMatch() . PHP_EOL;
263 | echo 'Trader postcode match: ' . $vatResult->getPostcodeMatch() . PHP_EOL;
264 | echo 'Trader city match: ' . $vatResult->getCityMatch() . PHP_EOL;
265 | echo PHP_EOL;
266 | ```
267 |
268 | When you run this, you will get the following result:
269 |
270 | ```
271 | Valid
272 | Identifier: WAPIAAAAWaYR0O8D
273 | Date and time: 21/10/2018 02:00
274 | Company name: NV OR NATIONALE MAATSCHAPPIJ DER BELGISCHE SPOORWEGEN
275 | Company address: FRANKRIJKSTRAAT 56
276 | 1060 SINT-GILLIS (BIJ-BRUSSEL)
277 | Trader name match:
278 | Trader company type match:
279 | Trader street match:
280 | Trader postcode match:
281 | Trader city match:
282 |
283 | ```
284 |
285 | ## Community involvement
286 |
287 | Here's a list of products or projects that have included this VIES package
288 |
289 | - [Symfony bundle](https://github.com/MyOnlineStore/ViesBundle) by [MyOnlineStore](https://www.myonlinestore.com)
290 | - [sandwich/vies-bundle](https://packagist.org/packages/sandwich/vies-bundle)
291 |
292 | If you have a product or a project that's using this package and you want some attribution for your work, send me an [email](mailto://dragonbe+github@gmail.com) or ping me on [Twitter](https://www.twitter.com/DragonBe) or [Facebook](https://www.facebook.com/dragonbe).
293 |
294 | ## Docker containers
295 |
296 | If you like to have Docker containers, you can now make use of a container designed for that purpose.
297 |
298 | ```shell
299 | docker run --rm -d -p 8000:18080 dragonbe/vies-web
300 | ```
301 |
302 | Point your browser to [localhost:8000](http://localhost:8000) to use the web interface for validating VAT.
303 |
304 | 
305 |
306 | ## Referenced on the web
307 |
308 | - [Microsoft Dynamics GP - Dynamics GP real time EU tax registration number validation using VIES](http://timwappat.info/post/2013/08/22/Dynamics-GP-real-time-EU-tax-registration-number-validation-using-VIES)
309 | - [Popular RIA law eu projects](https://libraries.io/search?keywords=RIA%2Claw%2Ceu)
310 | - [PHP Code Examples - HotExamples.com](https://hotexamples.com/examples/dragonbe.vies/Vies/validateVat/php-vies-validatevat-method-examples.html)
311 |
312 | ## Clarification on exceptions
313 |
314 | For Greece the [international country ISO code](https://www.iso.org/obp/ui/#iso:code:3166:GR) is **GR**, but for VAT IDN's they use the prefix **EL**. Thanks to [Johan Wilfer](https://github.com/johanwilfer) for [reporting this](https://github.com/DragonBe/vies/issues/57).
315 |
316 | Since January 1, 2021 the UK is no longer a member of the European Union and as a result, the VIES service provided by the European Commission no longer validates VAT ID's for the UK. There is one exception though and that is for Northern Ireland (XI) for which VAT ID's can be validated using this library and the EC VIES service.
317 |
318 | ## Licence
319 |
320 | DragonBe\Vies is released under the MIT Licence. See the bundled [LICENCE](LICENCE) file for details.
321 |
--------------------------------------------------------------------------------
/bin/vatcheck:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | ' . PHP_EOL;
11 | exit(1);
12 | }
13 |
14 | $vies = new Vies();
15 | if (false === $vies->getHeartBeat()->isAlive()) {
16 | echo 'EU VIES Service not available at this moment, please try again later' . PHP_EOL;
17 | exit(2);
18 | }
19 |
20 | $vatId = $vies->splitVatId($argv[1]);
21 |
22 | $result = null;
23 | try {
24 | $result = $vies->validateVat($vatId['country'], $vatId['id']);
25 | } catch (ViesServiceException $vse) {
26 | echo $vse->getMessage() . PHP_EOL;
27 | exit(3);
28 | } catch (ViesException $ve) {
29 | echo $ve->getMessage() . PHP_EOL;
30 | exit(4);
31 | }
32 |
33 | echo sprintf(
34 | 'VAT ID %s %s is %s',
35 | $result->getCountryCode(),
36 | $result->getVatNumber(),
37 | $result->isValid() ? 'VALID' : 'NOT VALID'
38 | ) . PHP_EOL;
39 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
18 |
19 |
20 |
21 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dragonbe/vies",
3 | "type": "tool",
4 | "description": "EU VAT numbers validation using the VIES Service of the European Commission",
5 | "keywords": ["VIES","VAT","EU","EC"],
6 | "homepage": "https://github.com/DragonBe/vies",
7 | "minimum-stability": "stable",
8 | "license": "MIT",
9 | "authors": [
10 | {
11 | "name": "Michelangelo van Dam",
12 | "email": "dragonbe@gmail.com",
13 | "homepage": "http://dragonbe.com",
14 | "role": "Developer"
15 | }
16 | ],
17 | "autoload": {
18 | "psr-4": {
19 | "DragonBe\\Vies\\": "src/Vies"
20 | }
21 | },
22 | "autoload-dev": {
23 | "psr-4": {
24 | "DragonBe\\Tests\\Vies\\": "tests/Vies"
25 | }
26 | },
27 | "require": {
28 | "php": ">=7.3",
29 | "ext-soap": "*",
30 | "ext-ctype": "*"
31 | },
32 | "require-dev": {
33 | "ext-pcntl": "*",
34 | "phpunit/phpunit": "^9.4",
35 | "phpunit/php-invoker": "^3.1",
36 | "phploc/phploc": "^7.0",
37 | "phpmd/phpmd": "^2.6",
38 | "sebastian/phpcpd": "^6.0",
39 | "pdepend/pdepend": "^2.5",
40 | "squizlabs/php_codesniffer": "^3.2",
41 | "phing/phing": "^2.16",
42 | "infection/infection": "^0.25",
43 | "enlightn/security-checker": "^1.2"
44 | },
45 | "scripts": {
46 | "phpcs": "phpcs",
47 | "phpunit": "phpunit",
48 | "test": [
49 | "@phpcs",
50 | "@phpunit"
51 | ],
52 | "pmd": [
53 | "@pmd-naming",
54 | "@pmd-unused",
55 | "@pmd-codesize",
56 | "@pmd-cleancode",
57 | "@phpcpd"
58 | ],
59 | "pmd-naming": "phpmd src xml naming --reportfile build/logs/pmd-naming.xml --strict --ignore-violations-on-exit",
60 | "pmd-unused": "phpmd src xml unusedcode --reportfile build/logs/pmd-unusedcode.xml --strict --ignore-violations-on-exit",
61 | "pmd-codesize": "phpmd src xml codesize --reportfile build/logs/pmd-codesize.xml --strict --ignore-violations-on-exit",
62 | "pmd-cleancode": "phpmd src xml cleancode --reportfile build/logs/pmd-cleancode.xml --strict --ignore-violations-on-exit",
63 | "pdepend": "pdepend --jdepend-chart=build/logs/jdepend-chart.svg --jdepend-xml=build/logs/jdepend.xml --overview-pyramid=build/logs/pyramid.svg src",
64 | "phpcpd": "phpcpd --log-pmd=build/logs/pmd-cpd.xml --min-lines=3 --min-tokens=50 --fuzzy --progress src",
65 | "test-all": [
66 | "@test",
67 | "@pmd"
68 | ]
69 | },
70 | "config": {
71 | "allow-plugins": {
72 | "infection/extension-installer": true
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/docs/images/vies-web-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DragonBe/vies/d9193cbaba7e2faefbdc228fb1bf5670f20acf30/docs/images/vies-web-screenshot.png
--------------------------------------------------------------------------------
/examples/EURailwayVATChecker.php:
--------------------------------------------------------------------------------
1 | getHeartBeat()->isAlive()) {
20 |
21 | echo 'Back-end VIES service is not available at the moment, please try again later.' . PHP_EOL;
22 | exit(1);
23 |
24 | }
25 |
26 | $companies = [
27 | [
28 | 'country_code' => 'BE',
29 | 'vat_id' => '0203430576',
30 | 'trader_name' => 'B-Rail',
31 | 'trader_company_type' => 'NV',
32 | 'trader_street' => 'Frankrijkstraat 65',
33 | 'trader_postcode' => '1060',
34 | 'trader_city' => 'Sint-Gillis',
35 | ],
36 | [
37 | 'country_code' => 'NL',
38 | 'vat_id' => '803979988B01',
39 | 'trader_name' => 'NS Groep',
40 | 'trader_company_type' => 'NV',
41 | 'trader_street' => 'Laan van Puntenburg 100',
42 | 'trader_postcode' => '3511ER',
43 | 'trader_city' => 'Utrecht',
44 | ],
45 | [
46 | 'country_code' => 'DE',
47 | 'vat_id' => '811569869',
48 | 'trader_name' => 'Deutsche Bahn',
49 | 'trader_company_type' => 'AG',
50 | 'trader_street' => 'Potsdamer Platz 2',
51 | 'trader_postcode' => '10785',
52 | 'trader_city' => 'Berlin',
53 | ],
54 | [
55 | 'country_code' => 'FR',
56 | 'vat_id' => '35552049447',
57 | 'trader_name' => 'Societe Nationale des Chemins de fer Francais',
58 | 'trader_company_type' => '',
59 | 'trader_street' => '2, place aux Étoiles',
60 | 'trader_postcode' => '93200',
61 | 'trader_city' => 'Saint-Denis',
62 | ],
63 | [
64 | 'country_code' => 'ES',
65 | 'vat_id' => 'A86868189',
66 | 'trader_name' => 'Renfe Viajeros',
67 | 'trader_company_type' => 'SA',
68 | 'trader_street' => 'Avda. Ciudad de Barcelona, 8',
69 | 'trader_postcode' => '28007',
70 | 'trader_city' => 'Madrid',
71 | ],
72 | [
73 | 'country_code' => 'PT',
74 | 'vat_id' => '500498601',
75 | 'trader_name' => 'Comboios de Portugal',
76 | 'trader_company_type' => 'SA',
77 | 'trader_street' => 'Calçada do Duque, n.º 20',
78 | 'trader_postcode' => '1249-109',
79 | 'trader_city' => 'Lisboa',
80 | ],
81 | [
82 | 'country_code' => 'IT',
83 | 'vat_id' => '04983351000',
84 | 'trader_name' => 'POL-RAIL',
85 | 'trader_company_type' => 'SRL',
86 | 'trader_street' => 'Viale dello Scalo San Lorenzo, 16',
87 | 'trader_postcode' => '00185',
88 | 'trader_city' => 'Roma',
89 | ],
90 | [
91 | 'country_code' => 'AT',
92 | 'vat_id' => 'U58044244',
93 | 'trader_name' => 'Rail Cargo Austria',
94 | 'trader_company_type' => 'AG',
95 | 'trader_street' => 'Hauptbahnhof 2',
96 | 'trader_postcode' => '1100',
97 | 'trader_city' => 'Vienna',
98 | ],
99 | [
100 | 'country_code' => 'EL',
101 | 'vat_id' => '999645865',
102 | 'trader_name' => 'Trainose',
103 | 'trader_company_type' => 'SA',
104 | 'trader_street' => '1-3 Karolou',
105 | 'trader_postcode' => '10437',
106 | 'trader_city' => 'Athens',
107 | ],
108 | [
109 | 'country_code' => 'PL',
110 | 'vat_id' => '1132316427',
111 | 'trader_name' => 'PKP POLSKIE LINIE KOLEJOWE SPÓŁKA AKCYJNA',
112 | 'trader_company_type' => '',
113 | 'trader_street' => 'TARGOWA 74',
114 | 'trader_postcode' => '03-734',
115 | 'trader_city' => 'WARSZAWA',
116 | ],
117 | [
118 | 'country_code' => 'LV',
119 | 'vat_id' => '40003032065',
120 | 'trader_name' => 'Valsts akciju sabiedrība "Latvijas dzelzceļš"',
121 | 'trader_company_type' => '',
122 | 'trader_street' => 'Gogoļa iela 3,',
123 | 'trader_postcode' => 'LV-1050',
124 | 'trader_city' => 'Riga',
125 | ],
126 | ];
127 |
128 | foreach ($companies as $company) {
129 | try {
130 | $vatResult = $vies->validateVat(
131 | $company['country_code'], // Trader country code
132 | $company['vat_id'], // Trader VAT ID
133 | 'BE', // Requester country code
134 | '0811231190', // Requester VAT ID
135 | $company['trader_name'], // Trader name
136 | $company['trader_company_type'], // Trader company type
137 | $company['trader_street'], // Trader street address
138 | $company['trader_postcode'], // Trader postcode
139 | $company['trader_city'] // Trader city
140 | );
141 | } catch (ViesException $viesException) {
142 | echo 'Cannot process VAT validation: ' . $viesException->getMessage();
143 | continue;
144 | } catch (ViesServiceException $viesServiceException) {
145 | echo 'Cannot process VAT validation: ' . $viesServiceException->getMessage();
146 | continue;
147 | }
148 |
149 | echo ($vatResult->isValid() ? 'Valid' : 'Not valid') . PHP_EOL;
150 | echo 'Identifier: ' . $vatResult->getIdentifier() . PHP_EOL;
151 | echo 'Date and time: ' . $vatResult->getRequestDate()->format('d/m/Y H:i') . PHP_EOL;
152 | echo 'Company name: ' . $vatResult->getName() . PHP_EOL;
153 | echo 'Company address: ' . $vatResult->getAddress() . PHP_EOL;
154 |
155 | echo 'Trader name match: ' . $vatResult->getNameMatch() . PHP_EOL;
156 | echo 'Trader company type match: ' . $vatResult->getCompanyTypeMatch() . PHP_EOL;
157 | echo 'Trader street match: ' . $vatResult->getStreetMatch() . PHP_EOL;
158 | echo 'Trader postcode match: ' . $vatResult->getPostcodeMatch() . PHP_EOL;
159 | echo 'Trader city match: ' . $vatResult->getCityMatch() . PHP_EOL;
160 | echo PHP_EOL;
161 | }
162 |
163 | exit (0);
164 |
--------------------------------------------------------------------------------
/examples/async_processing/.gitignore:
--------------------------------------------------------------------------------
1 | vatqueue.db
2 |
--------------------------------------------------------------------------------
/examples/async_processing/README.md:
--------------------------------------------------------------------------------
1 | # Async processing of VAT ID validation
2 |
3 | A common question we got is how we deal with VAT ID validation when the official [European Commission (EC) VAT Information Exchange System (VIES)](http://ec.europa.eu/taxation_customs/vies) is down or not operational. Often we explain that we have several tools in place to perform many validations offline like `validateVatSum` and our `getHeartBeat()->isAlive()`, but this doesn't solve the problem for many users.
4 |
5 | Therefor I've created this simple Async VAT Validation setup using a `queue.php` for adding VAT ID's into a simple SQLite DB queue and `worker.php` which will run as a daemon constantly checking the queue to see if there's a new VAT ID to validate. This worker also implements the "heart beat" checker which puts it into sleep mode for 30 minutes.
6 |
7 | The benefit is you can run the worker as a process and have the queue script listening onto a seperate port to which you can easily send your VAT ID's.
8 |
9 | **THIS IS A PROOF-OF-CONCEPT!!! DO NOT USE AS-IS IN PRODUCTION!!!**
10 |
11 | ## Step 1: Initialise the database
12 |
13 | We're making use of SQLite for this PoC, but feel free to set it up for whatever backend you feel comfortable with.
14 |
15 | ```
16 | cd examples/async_processing
17 | sqlite3 vatqueue.db < vatqueue.sql
18 | ```
19 |
20 | ## Step 2: Starting the worker
21 |
22 | This will run the worker as a daemon and puts it in the background. You can also run it in Screen or even in Docker if you want.
23 |
24 | ```
25 | php worker.php &
26 | ```
27 |
28 | ## Step 3: Start the queue listener
29 |
30 | We also want a simple interface where we can just point the VAT ID to, and nothing is easier than to use it as a web service. In this case we're using the build-in PHP web server to handle requests, but you can also have it run in Apache, Nginx or even inside a Docker container.
31 |
32 | ```
33 | php -S localhost:11984 queue.php
34 | ```
35 |
36 | ## Step 4: Add VAT ID's to the queue
37 |
38 | Assuming that all steps have been followed as described above, you can just throw VAT ID's to the web service endpoint by using curl or ajax calls.
39 |
40 | ```
41 | curl "http://localhost:11984/?vatid=BE0811231234"
42 | curl "http://localhost:11984/?vatid=BE0811231235"
43 | curl "http://localhost:11984/?vatid=BE0811231236"
44 | ```
45 |
46 | ## Step 5: See the validation
47 |
48 | Now you just need to read from the backend to see which VAT ID was valid and which one did not. And as long the `worker.php` is running, it will keep reading the queue until all things are processed.
49 |
--------------------------------------------------------------------------------
/examples/async_processing/list.php:
--------------------------------------------------------------------------------
1 | query('SELECT * FROM `vat_validation` ORDER BY `id` DESC');
8 |
9 | $vatIdList = $listStmt->fetchAll(\PDO::FETCH_ASSOC);
10 |
11 | ?>
12 |
13 |
14 |
15 | Listing VAT ID's
16 |
17 |
18 | Listing VAT ID's
19 |
20 | Add new VAT ID
21 |
22 |
23 |
24 | VAT ID |
25 | Date |
26 | Status |
27 |
28 |
29 |
30 | |
31 | format('d-m-Y') ?> |
32 | |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/examples/async_processing/queue.php:
--------------------------------------------------------------------------------
1 | prepare('SELECT `id` FROM `vat_validation` WHERE `vat_id` = ?');
7 | $addToQueueStmt = $pdo->prepare('INSERT INTO `vat_validation` (`vat_id`) VALUES (?)');
8 | $updateQueueStmt = $pdo->prepare('UPDATE `vat_validation` SET `validated` = "" WHERE `id` = ?');
9 |
10 | if ([] !== $_GET && array_key_exists('vatid', $_GET)) {
11 | $vatId = filter_var($_GET['vatid'], FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH);
12 | $vatId = str_replace(['.', '-', ' ', '_'], '', $vatId);
13 |
14 | $isAlreadyValidatedStmt->bindValue(1, $vatId);
15 | $isAlreadyValidatedStmt->execute();
16 |
17 | $result = $isAlreadyValidatedStmt->fetchColumn(0);
18 | if (false === $result) {
19 | $addToQueueStmt->bindValue(1, $vatId);
20 | $addToQueueStmt->execute();
21 | } else {
22 | $updateQueueStmt->bindValue(1, $result);
23 | $updateQueueStmt->execute();
24 | }
25 | header('Location: ' . $_SERVER['PHP_SELF']);
26 | }
27 | ?>
28 |
29 |
30 |
31 | Add a new VAT ID to the queue
32 |
33 |
34 | Add a new VAT ID to the queue
35 |
36 | Back to list
37 |
38 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/examples/async_processing/vatqueue.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE IF EXISTS `vat_validation`;
2 | CREATE TABLE `vat_validation` (
3 | `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4 | `vat_id` TEXT NOT NULL,
5 | `validated` TEXT NOT NULL DEFAULT '',
6 | `result` TEXT NOT NULL DEFAULT '',
7 | `reason` TEXT NOT NULL DEFAULT '',
8 | `name` TEXT NOT NULL DEFAULT '',
9 | `address` TEXT NOT NULL DEFAULT '',
10 | `identifier` TEXT NOT NULL DEFAULT ''
11 | );
12 |
--------------------------------------------------------------------------------
/examples/async_processing/worker.php:
--------------------------------------------------------------------------------
1 | prepare('SELECT `id`, `vat_id` FROM `vat_validation` WHERE `validated` = "" ORDER BY `id` DESC LIMIT 1');
13 | $updateVatId = $pdo->prepare('UPDATE `vat_validation` SET `validated` = ?, `result` = ?, `reason` = ?, `name` = ?, `address` = ?, `identifier` = ? WHERE `id` = ?');
14 |
15 | function debug($message = ''): void
16 | {
17 | $debug = false;
18 | if ($debug) {
19 | echo '[DEBUG] >>> ' . $message . PHP_EOL;
20 | }
21 | }
22 |
23 | $vies = new Vies();
24 | do {
25 | if (!$vies->getHeartBeat()->isAlive()) {
26 | debug('Service is down, sleeping for 30 minutes');
27 | sleep(1800); // sleep for 30 minutes
28 | continue;
29 | }
30 | $validationStmt->execute();
31 |
32 | $row = $validationStmt->fetch(\PDO::FETCH_ASSOC);
33 | if (false === $row) {
34 | debug('No new data found');
35 | sleep(60);
36 | continue;
37 | }
38 | $id = (int) $row['id'];
39 | $vatin = $row['vat_id'];
40 | $vatCountry = substr($vatin, 0, 2);
41 | $vatNumber = substr($vatin, 2);
42 | $vatNumber = $vies->filterVat($vatNumber);
43 | $reason = '';
44 |
45 | try {
46 | $result = $vies->validateVat($vatCountry, $vatNumber);
47 | debug('Result: ' . var_export($result, 1));
48 | } catch (ViesServiceException $viesServiceException) {
49 | // Connection was broken or other weird things went on, let's wait a few
50 | debug('ViesServiceException: ' . $viesServiceException->getMessage());
51 | sleep(60);
52 | continue;
53 | } catch (ViesException $viesException) {
54 | // Something went wrong with the validation, add to log and notify service operators
55 | debug('ViesException: ' . $viesException->getMessage());
56 | $reason = $viesException->getMessage();
57 | }
58 |
59 | $updateVatId->bindValue(1, $result->getRequestDate()->format('Y-m-d H:i:s O'));
60 | $updateVatId->bindValue(2, $result->isValid() ? 'valid' : 'invalid');
61 | $updateVatId->bindValue(3, $reason);
62 | $updateVatId->bindValue(4, $result->getName());
63 | $updateVatId->bindValue(5, $result->getAddress());
64 | $updateVatId->bindValue(6, $result->getIdentifier());
65 | $updateVatId->bindValue(7, $id);
66 |
67 | $updateVatId->execute();
68 |
69 | } while (true);
70 |
--------------------------------------------------------------------------------
/examples/checkVat.php:
--------------------------------------------------------------------------------
1 | getHeartBeat()->isAlive()) {
12 |
13 | echo 'Back-end VIES service is not available at the moment, please try again later.' . PHP_EOL;
14 |
15 | } else {
16 |
17 | $vatNumberProvider = [
18 | [
19 | 'BE' => '0811231190', // valid
20 | 'HR' => '20649144807'
21 | ],
22 | [
23 | 'BE' => '1234567890', // invalid
24 | 'ES' => '9999999999',
25 | ],
26 | [
27 | 'AA' => '1234567890', // invalid country code
28 | 'NO' => '1234567890'
29 | ],
30 | ];
31 |
32 | foreach ($vatNumberProvider as $vatNumbers) {
33 |
34 | foreach ($vatNumbers as $countryCode => $vatNumber) {
35 |
36 | echo 'Validating ' . $countryCode . $vatNumber . '... ';
37 |
38 | try {
39 | $result = $vies->validateVat($countryCode, $vatNumber); // - Validation routine worked as expected.
40 | echo ($result->isValid()) ? 'Valid' : 'Invalid'; //
41 | } catch (ViesServiceException $e) { // - Recoverable exception.
42 | echo $e->getMessage(); // There is probably a temporary problem with back-end VIES service.
43 | } catch (ViesException $e) { // - Unrecoverable exception.
44 | echo $e->getMessage(); // Invalid country code etc.
45 | }
46 |
47 | echo PHP_EOL;
48 |
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/examples/checkVatBatch.php:
--------------------------------------------------------------------------------
1 | getHeartBeat()->isAlive()) {
12 |
13 | echo 'Back-end VIES service is not available at the moment, please try again later.' . PHP_EOL;
14 |
15 | } else {
16 |
17 | $splQueue = new SplQueue();
18 |
19 | foreach (vatinProvider() as $vatin) {
20 | $splQueue->enqueue($vatin);
21 | }
22 |
23 | foreach ($splQueue as $item) {
24 |
25 | $vatin = $splQueue->dequeue();
26 |
27 | echo 'Validating ' . $vatin . '... ';
28 |
29 | $countryCode = substr($vatin, 0, 2);
30 | $vatNumber = substr($vatin, 2);
31 | $vatNumber = $vies->filterVat($vatNumber);
32 |
33 | try {
34 | $result = $vies->validateVat($countryCode, $vatNumber); // Validation routine worked as expected.
35 | echo ($result->isValid()) ? 'VALID' : 'INVALID';
36 | } catch (ViesServiceException $e) { // Recoverable exception. There is probably a temporary problem
37 | echo $e->getMessage(); // with back-end VIES service. Try again. Add VATIN back to queue.
38 | $splQueue->enqueue($vatin);
39 | } catch (ViesException $e) { // Unrecoverable exception. Invalid country code etc.
40 | echo $e->getMessage(); // Do not try again.
41 | }
42 |
43 | echo PHP_EOL;
44 | }
45 | }
46 |
47 |
48 | /**
49 | * Load an array of VATINs (country code + VAT number)
50 | *
51 | * Source:
52 | * http://www.braemoor.co.uk/software/vattest.php
53 | *
54 | * @return array
55 | */
56 | function vatinProvider(): array
57 | {
58 | $filename = realpath(__DIR__ . '/vatins.php');
59 |
60 | if (is_readable($filename)) {
61 | $ret = include $filename;
62 | } else {
63 | $ret = [];
64 | }
65 |
66 | return $ret;
67 | }
68 |
--------------------------------------------------------------------------------
/examples/checkVatWithDetails.php:
--------------------------------------------------------------------------------
1 | getHeartBeat()->isAlive()) {
11 |
12 | echo 'Back-end VIES service is not available at the moment, please try again later.' . PHP_EOL;
13 |
14 | } else {
15 | $vatDataProvider = [
16 | [
17 | 'countryCode' => 'BE', // Country code
18 | 'vatId' => '0811231190', // VAT ID
19 | 'traderName' => 'In2it', // Trader name
20 | 'traderCompanyType' => 'VOF', // Trader company type
21 | 'traderStreet' => 'Battelsesteenweg 134', // Trader street address
22 | 'traderPostcode' => '2800', // Trader postcode
23 | 'traderCity' => 'Mechelen' // Trader city
24 | ],
25 | [
26 | 'countryCode' => 'HR', // Country code
27 | 'vatId' => '20649144807', // VAT ID
28 | 'traderName' => 'Aning Usluge', // Trader name
29 | 'traderCompanyType' => 'DOO', // Trader company type
30 | 'traderStreet' => 'Zeleni Trg 4', // Trader street address
31 | 'traderPostcode' => '10000', // Trader postcode
32 | 'traderCity' => 'Zagreb' // Trader city
33 | ],
34 | ];
35 |
36 | foreach ($vatDataProvider as $trader) {
37 | try {
38 | $response = $vies->validateVat(
39 | $trader['countryCode'],
40 | $trader['vatId'],
41 | $trader['countryCode'], // duplicate for requester VAT country code
42 | $trader['vatId'], // duplicate for requester VAT ID
43 | $trader['traderName'],
44 | $trader['traderCompanyType'],
45 | $trader['traderStreet'],
46 | $trader['traderPostcode'],
47 | $trader['traderCity']
48 | );
49 |
50 | echo sprintf('Company %s with VAT ID %s%s is %s (validation ID: %s)',
51 | $response->getName(),
52 | $response->getCountryCode(),
53 | $response->getVatNumber(),
54 | $response->isValid() ? 'Valid' : 'Not valid',
55 | $response->getIdentifier()
56 | ) . PHP_EOL;
57 | echo sprintf('Company name: %s (%s)',
58 | $response->getName(),
59 | '' === $response->getNameMatch() ? 'No match returned' : $response->getNameMatch()
60 | ) . PHP_EOL;
61 | echo sprintf('Company address: %s (%s)',
62 | $response->getAddress(),
63 | '' === $response->getStreetMatch() ? 'No match returned' : $response->getStreetMatch()
64 | ) . PHP_EOL;
65 | } catch (ViesException $viesException) {
66 | echo 'An error occurred: ' . $viesException->getMessage();
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/infection.json.dist:
--------------------------------------------------------------------------------
1 | {
2 | "timeout": 5,
3 | "source": {
4 | "directories": [
5 | "src"
6 | ]
7 | },
8 | "logs": {
9 | "text": "build\/logs\/infection.txt"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | VIES Coding Standard
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | src
26 | tests
27 |
28 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./src
16 |
17 |
18 | ./src/autoload.php
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | ./tests
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/sonar-project.properties:
--------------------------------------------------------------------------------
1 | sonar.organization=dragonbe-github
2 | sonar.projectKey=dragonbe-vies
3 | sonar.projectName=VIES QA
4 | sonar.projectVersion=2.1.13
5 | sonar.sources=.
6 | sonar.host.url=https://sonarcloud.io
7 |
8 | # =====================================================
9 | # Meta-data for the project
10 | # =====================================================
11 |
12 | sonar.links.homepage=https://github.com/DragonBe/vies
13 | sonar.links.ci=https://travis-ci.org/DragonBe/vies
14 | sonar.links.scm=https://github.com/DragonBe/vies
15 | sonar.links.issue=https://github.com/DragonBe/vies/issues
16 |
17 |
18 | # =====================================================
19 | # Properties that will be shared amongst all modules
20 | # =====================================================
21 |
22 | # SQ standard properties
23 | sonar.sources=src
24 | sonar.tests=tests
25 |
26 | # Properties specific to language plugins:
27 | sonar.java.checkstyle.reportPaths=build/logs/checkstyle.xml
28 | sonar.java.pmd.reportPaths=build/logs/pmd-*.xml
29 | sonar.php.coverage.reportPath=build/logs/coverage/coverage-xml/index.xml
30 | sonar.php.coverage.reportPaths=build/logs/clover.xml
31 | sonar.php.tests.reportPath=build/logs/junit.xml
32 | sonar.php.file.suffixes=php
33 | sonar.php.exclusions=**/vendor/**,src/autoload.php,**/examples/**,**/tests/**
34 | sonar.cpd.exclusions=src/Vies/Validator/ValidatorXI.php
35 |
--------------------------------------------------------------------------------
/src/Vies/CheckVatResponse.php:
--------------------------------------------------------------------------------
1 |
12 | * @license MIT
13 | *
14 | */
15 | namespace DragonBe\Vies;
16 |
17 | use DateTime;
18 | use InvalidArgumentException;
19 | use stdClass;
20 |
21 | /**
22 | * CheckVatResponse
23 | *
24 | * This is the response object from the VIES web service for validation of
25 | * VAT numbers of companies registered in the European Union.
26 | *
27 | * @see \DragonBe\Vies\Exception
28 | * @category DragonBe
29 | * @package \DragonBe\Vies
30 | */
31 | class CheckVatResponse
32 | {
33 | public const VIES_DATETIME_FORMAT = 'Y-m-dP';
34 |
35 | /**
36 | * @var string The country code for a member of the European Union
37 | */
38 | protected $countryCode;
39 | /**
40 | * @var string The VAT number of a registered European company
41 | */
42 | protected $vatNumber;
43 | /**
44 | * @var DateTime The date of the request
45 | */
46 | protected $requestDate;
47 | /**
48 | * @var bool Flag indicating the VAT number is valid
49 | */
50 | protected $valid;
51 | /**
52 | * @var string The registered name of a validated company (optional)
53 | */
54 | protected $name;
55 | /**
56 | * @var string The registered address of a validated company (optional)
57 | */
58 | protected $address;
59 | /**
60 | * @var string The request Identifier (optional)
61 | */
62 | protected $identifier;
63 |
64 | /**
65 | * @var string If optional name was provided, a check on name will be returned
66 | */
67 | protected $nameMatch;
68 |
69 | /**
70 | * @var string If optional company type was provided, a check on type will be returned
71 | */
72 | protected $companyTypeMatch;
73 |
74 | /**
75 | * @var string If optional street was provided, a check on street will be returned
76 | */
77 | protected $streetMatch;
78 |
79 | /**
80 | * @var string If optional postcode was provided, a check on postcode will be returned
81 | */
82 | protected $postcodeMatch;
83 |
84 | /**
85 | * @var string If optional city was provided, a check on city will be returned
86 | */
87 | protected $cityMatch;
88 |
89 | /**
90 | * Constructor for this response object
91 | *
92 | * @param null|array|stdClass $params
93 | */
94 | public function __construct($params = null)
95 | {
96 | if (null !== $params) {
97 | $this->populate($params);
98 | }
99 | }
100 | /**
101 | * Sets the two-character country code for a member of the European Union
102 | *
103 | * @param string $countryCode
104 | *
105 | * @return self
106 | */
107 | public function setCountryCode(string $countryCode): self
108 | {
109 | $this->countryCode = $countryCode;
110 |
111 | return $this;
112 | }
113 | /**
114 | * Retrieves the two-character country code from a member of the European
115 | * Union.
116 | *
117 | * @return string
118 | */
119 | public function getCountryCode(): string
120 | {
121 | return $this->countryCode;
122 | }
123 | /**
124 | * Sets the VAT number of a company within the European Union
125 | *
126 | * @param string $vatNumber
127 | *
128 | * @return self
129 | */
130 | public function setVatNumber(string $vatNumber): self
131 | {
132 | $this->vatNumber = $vatNumber;
133 |
134 | return $this;
135 | }
136 | /**
137 | * Retrieves the VAT number from a company within the European Union
138 | *
139 | * @return string
140 | */
141 | public function getVatNumber(): string
142 | {
143 | return $this->vatNumber;
144 | }
145 |
146 | /**
147 | * Sets the date- and timestamp when the VIES service response was created
148 | *
149 | * @param DateTime $requestDate
150 | *
151 | * @return self
152 | */
153 | public function setRequestDate(DateTime $requestDate): self
154 | {
155 | $this->requestDate = $requestDate;
156 |
157 | return $this;
158 | }
159 |
160 | /**
161 | * Retrieves the date- and timestamp the VIES service response was created
162 | *
163 | * @return DateTime
164 | */
165 | public function getRequestDate(): DateTime
166 | {
167 | $this->requestDate = $this->requestDate ?? date_create();
168 |
169 | return $this->requestDate;
170 | }
171 | /**
172 | * Sets the flag to indicate the provided details were valid or not
173 | *
174 | * @param bool $flag
175 | *
176 | * @return self
177 | */
178 | public function setValid(bool $flag): self
179 | {
180 | $this->valid = $flag;
181 |
182 | return $this;
183 | }
184 | /**
185 | * Checks to see if a request is valid with given parameters
186 | *
187 | * @return bool
188 | */
189 | public function isValid(): bool
190 | {
191 | return $this->valid;
192 | }
193 | /**
194 | * Sets optionally the registered name of the company
195 | *
196 | * @param string $name
197 | *
198 | * @return self
199 | */
200 | public function setName(string $name): self
201 | {
202 | $this->name = $name;
203 |
204 | return $this;
205 | }
206 | /**
207 | * Retrieves the registered name of the company
208 | *
209 | * @return string
210 | */
211 | public function getName(): string
212 | {
213 | return $this->name;
214 | }
215 |
216 | /**
217 | * Sets the registered address of a company
218 | *
219 | * @param string $address
220 | *
221 | * @return self
222 | */
223 | public function setAddress(string $address): self
224 | {
225 | $this->address = $address;
226 |
227 | return $this;
228 | }
229 |
230 | /**
231 | * Retrieves the registered address of a company
232 | *
233 | * @return string
234 | */
235 | public function getAddress(): string
236 | {
237 | return $this->address;
238 | }
239 |
240 | /**
241 | * Sets request Identifier
242 | *
243 | * @param string $identifier
244 | *
245 | * @return self
246 | */
247 | public function setIdentifier(string $identifier): self
248 | {
249 | $this->identifier = $identifier;
250 |
251 | return $this;
252 | }
253 | /**
254 | * get request Identifier
255 | *
256 | * @return string
257 | */
258 | public function getIdentifier(): string
259 | {
260 | return $this->identifier;
261 | }
262 |
263 | /**
264 | * @return string
265 | */
266 | public function getNameMatch(): string
267 | {
268 | return $this->nameMatch;
269 | }
270 |
271 | /**
272 | * @param string $nameMatch
273 | * @return CheckVatResponse
274 | */
275 | public function setNameMatch(string $nameMatch): self
276 | {
277 | $this->nameMatch = $nameMatch;
278 |
279 | return $this;
280 | }
281 |
282 | /**
283 | * @return string
284 | */
285 | public function getCompanyTypeMatch(): string
286 | {
287 | return $this->companyTypeMatch;
288 | }
289 |
290 | /**
291 | * @param string $companyTypeMatch
292 | * @return CheckVatResponse
293 | */
294 | public function setCompanyTypeMatch(string $companyTypeMatch): self
295 | {
296 | $this->companyTypeMatch = $companyTypeMatch;
297 |
298 | return $this;
299 | }
300 |
301 | /**
302 | * @return string
303 | */
304 | public function getStreetMatch(): string
305 | {
306 | return $this->streetMatch;
307 | }
308 |
309 | /**
310 | * @param string $streetMatch
311 | * @return CheckVatResponse
312 | */
313 | public function setStreetMatch(string $streetMatch): self
314 | {
315 | $this->streetMatch = $streetMatch;
316 |
317 | return $this;
318 | }
319 |
320 | /**
321 | * @return string
322 | */
323 | public function getPostcodeMatch(): string
324 | {
325 | return $this->postcodeMatch;
326 | }
327 |
328 | /**
329 | * @param string $postcodeMatch
330 | * @return CheckVatResponse
331 | */
332 | public function setPostcodeMatch(string $postcodeMatch): self
333 | {
334 | $this->postcodeMatch = $postcodeMatch;
335 |
336 | return $this;
337 | }
338 |
339 | /**
340 | * @return string
341 | */
342 | public function getCityMatch(): string
343 | {
344 | return $this->cityMatch;
345 | }
346 |
347 | /**
348 | * @param string $cityMatch
349 | * @return CheckVatResponse
350 | */
351 | public function setCityMatch(string $cityMatch): self
352 | {
353 | $this->cityMatch = $cityMatch;
354 |
355 | return $this;
356 | }
357 |
358 | /**
359 | * Populates this response object with external data
360 | *
361 | * @param array|stdClass $row
362 | */
363 | public function populate($row): void
364 | {
365 | if (is_array($row)) {
366 | $row = (object) $row;
367 | }
368 |
369 | $requiredFields = ['countryCode', 'vatNumber', 'requestDate', 'valid'];
370 | foreach ($requiredFields as $requiredField) {
371 | if (! isset($row->{$requiredField})) {
372 | throw new InvalidArgumentException('Required field "' . $requiredField . '" is missing');
373 | }
374 | }
375 |
376 | $requestDateTime = $row->requestDate;
377 | if (! $row->requestDate instanceof DateTime) {
378 | // prepare request date
379 | $requestDateTime = date_create_from_format(
380 | self::VIES_DATETIME_FORMAT,
381 | $row->requestDate
382 | );
383 | // Need to set time to zero
384 | // otherwise datetime would use current system time (which is not the response time)
385 | $requestDateTime->setTime(0, 0, 0, 0);
386 | }
387 |
388 | $this
389 | // required parameters
390 | ->setCountryCode($row->countryCode)
391 | ->setVatNumber($row->vatNumber)
392 | ->setRequestDate($requestDateTime)
393 | ->setValid($row->valid)
394 | // optional parameters
395 | ->setName($row->traderName ?? '---')
396 | ->setAddress($row->traderAddress ?? '---')
397 | ->setIdentifier($row->requestIdentifier ?? '')
398 | ->setNameMatch($row->traderNameMatch ?? '')
399 | ->setCompanyTypeMatch($row->traderCompanyTypeMatch ?? '')
400 | ->setStreetMatch($row->traderStreetMatch ?? '')
401 | ->setPostcodeMatch($row->traderPostcodeMatch ?? '')
402 | ->setCityMatch($row->traderCityMatch ?? '')
403 | ;
404 | }
405 |
406 | /**
407 | * Return this object as an array
408 | *
409 | * @return array
410 | */
411 | public function toArray(): array
412 | {
413 | return [
414 | 'countryCode' => $this->getCountryCode(),
415 | 'vatNumber' => $this->getVatNumber(),
416 | 'requestDate' => $this->getRequestDate()->format('Y-m-d'),
417 | 'valid' => $this->isValid(),
418 | 'name' => $this->getName(),
419 | 'address' => $this->getAddress(),
420 | 'identifier' => $this->getIdentifier(),
421 | 'nameMatch' => $this->getNameMatch(),
422 | 'companyTypeMatch' => $this->getCompanyTypeMatch(),
423 | 'streetMatch' => $this->getStreetMatch(),
424 | 'postcodeMatch' => $this->getPostcodeMatch(),
425 | 'cityMatch' => $this->getCityMatch(),
426 | ];
427 | }
428 | }
429 |
--------------------------------------------------------------------------------
/src/Vies/HeartBeat.php:
--------------------------------------------------------------------------------
1 |
12 | * @license MIT
13 | *
14 | */
15 | namespace DragonBe\Vies;
16 |
17 | use DomainException;
18 |
19 | /**
20 | * Class HeartBeat
21 | *
22 | * This class provides a simple but essential heartbeat cheack
23 | * on the VIES service as it's known to have availability issues.
24 | *
25 | * @category DragonBe
26 | * @package \DragonBe\Vies
27 | * @link http://ec.europa.eu/taxation_customs/vies/faqvies.do#item16
28 | */
29 | class HeartBeat
30 | {
31 | public const DEFAULT_TIMEOUT = 10;
32 |
33 | /**
34 | * @var string The host you want to verify
35 | */
36 | protected $host;
37 | /**
38 | * @var int The port you want to verify
39 | */
40 | protected $port;
41 | /**
42 | * @var ?string The path to append
43 | */
44 | protected $path;
45 |
46 | /**
47 | * @var int The timeout in seconds
48 | */
49 | protected $timeout;
50 |
51 | /**
52 | * @var bool Allow the service to be tested without integration of sockets
53 | */
54 | public static $testingEnabled = false;
55 |
56 | /**
57 | * @var bool Allow to define the validation return setting
58 | */
59 | public static $testingServiceIsUp = true;
60 |
61 | /**
62 | * @param string|null $host
63 | * @param int $port
64 | * @param int $timeout
65 | */
66 | public function __construct(
67 | ?string $host = null,
68 | int $port = Vies::VIES_PORT,
69 | int $timeout = self::DEFAULT_TIMEOUT,
70 | ?string $path = null
71 | ) {
72 | if (null !== $host) {
73 | $this->setHost($host);
74 | }
75 |
76 | $this->setPath($path);
77 | $this->setPort($port);
78 | $this->setTimeout($timeout);
79 | }
80 |
81 | /**
82 | * @return string
83 | */
84 | public function getHost(): string
85 | {
86 | if (null !== $this->host) {
87 | return $this->host;
88 | }
89 |
90 | throw new DomainException('A host is required');
91 | }
92 |
93 | /**
94 | * @param string $host
95 | * @return self
96 | */
97 | public function setHost(string $host): self
98 | {
99 | $this->host = $host;
100 |
101 | return $this;
102 | }
103 |
104 | /**
105 | * @return ?string
106 | */
107 | public function getPath(): ?string
108 | {
109 | return $this->path;
110 | }
111 |
112 | /**
113 | * @param ?string $path
114 | * @return self
115 | */
116 | public function setPath(?string $path = null): self
117 | {
118 | $this->path = $path;
119 |
120 | return $this;
121 | }
122 |
123 | /**
124 | * @return int
125 | */
126 | public function getPort(): int
127 | {
128 | return $this->port;
129 | }
130 |
131 | /**
132 | * @param int $port
133 | * @return self
134 | */
135 | public function setPort(int $port): self
136 | {
137 | $this->port = $port;
138 |
139 | return $this;
140 | }
141 |
142 | /**
143 | * @return int
144 | */
145 | public function getTimeout(): int
146 | {
147 | return $this->timeout;
148 | }
149 |
150 | /**
151 | * @param int $timeout
152 | * @return HeartBeat
153 | */
154 | public function setTimeout(int $timeout): HeartBeat
155 | {
156 | $this->timeout = $timeout;
157 | return $this;
158 | }
159 |
160 | /**
161 | * Checks if the VIES service is online and available
162 | *
163 | * @return bool
164 | */
165 | public function isAlive(): bool
166 | {
167 | if (false === static::$testingEnabled) {
168 | return $this->reachOut();
169 | }
170 |
171 | return static::$testingServiceIsUp;
172 | }
173 |
174 | /**
175 | * A private routine to send a request over a socket to
176 | * test if the remote service is responding with a status
177 | * code of 200 OK. Now supports also proxy connections.
178 | *
179 | * @return bool
180 | */
181 | private function reachOut(): bool
182 | {
183 | try {
184 | $data = $this->getSecuredResponse();
185 | } catch (\RuntimeException $runtimeException) {
186 | return false;
187 | }
188 | return (
189 | (0 === strcmp('HTTP/1.1 200 OK', $data[0])) ||
190 | (0 === strcmp('HTTP/1.1 307 Temporary Redirect', $data[0]))
191 | );
192 | }
193 |
194 | /**
195 | * This method will make a simple request inside a stream
196 | * resource to retrieve its contents. Useful inside secured
197 | * streams.
198 | *
199 | * @param resource $handle
200 | * @return array
201 | */
202 | private function readContents($handle): array
203 | {
204 | if (! is_resource($handle)) {
205 | throw new \InvalidArgumentException('Expecting a resource to be provided');
206 | }
207 | $response = '';
208 | $uri = sprintf('%s://%s%s', Vies::VIES_PROTO, $this->host, $this->path);
209 | $stream = [
210 | 'GET ' . $uri . ' HTTP/1.0',
211 | 'Host: ' . $this->host,
212 | 'Connection: close',
213 | ];
214 | fwrite($handle, implode("\r\n", $stream) . "\r\n\r\n");
215 | while (! feof($handle)) {
216 | $response .= fgets($handle, 1024);
217 | }
218 | fclose($handle);
219 | $response = str_replace("\r\n", PHP_EOL, $response);
220 | $data = explode(PHP_EOL, $response);
221 | return $data;
222 | }
223 |
224 | /**
225 | * Will make a secured request over SSL/TLS where this
226 | * method will first create a secured stream before
227 | * making the request.
228 | *
229 | * @return array
230 | * @throws \RuntimeException
231 | * @see https://bytephunk.wordpress.com/2017/11/27/ssl-tls-stream-sockets-in-php-7/
232 | */
233 | private function getSecuredResponse(): array
234 | {
235 | $streamOptions = [
236 | 'ssl' => [
237 | 'verify_peer' => true,
238 | 'verify_peer_name' => true,
239 | 'allow_self_signed' => false,
240 | ],
241 | ];
242 | $streamContext = stream_context_create($streamOptions);
243 | $socketAddress = sprintf(
244 | 'tls://%s:%d',
245 | $this->host,
246 | $this->port
247 | );
248 | $error = null;
249 | $errno = null;
250 | $stream = stream_socket_client(
251 | $socketAddress,
252 | $errno,
253 | $error,
254 | self::DEFAULT_TIMEOUT,
255 | STREAM_CLIENT_CONNECT,
256 | $streamContext
257 | );
258 |
259 | if (! $stream) {
260 | throw new \RuntimeException('Can not create socket stream: ' . $error);
261 | }
262 |
263 | return $this->readContents($stream);
264 | }
265 | }
266 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorAT.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorAT
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C1 Alphabetic
22 | * C2 ... C9 Numeric from 0 to 9
23 | *
24 | * Rules:
25 | * C1
26 | * U
27 | * C9
28 | * Si = INT(Ci / 5) + (Ci * 2) modulo10
29 | * R = S3 + S5 + S7
30 | * (10 – (R + C2 + C4 + C6 + C8 + 4) modulo 10) modulo 10
31 | *
32 | */
33 | class ValidatorAT extends ValidatorAbstract
34 | {
35 | /**
36 | * {@inheritdoc}
37 | */
38 | public function validate(string $vatNumber): bool
39 | {
40 | if (strlen($vatNumber) != 9) {
41 | return false;
42 | }
43 |
44 | if (strtoupper($vatNumber[0]) != 'U') {
45 | return false;
46 | }
47 |
48 | $checkVal = 0;
49 | for ($i = 1; $i < 8; $i++) {
50 | $checkVal += $this->crossSum((int)$vatNumber[$i] * ($this->isEven($i) ? 2 : 1));
51 | }
52 |
53 | $checkVal = substr((string)(96 - $checkVal), -1);
54 |
55 | return (int)$vatNumber[8] == $checkVal;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorAbstract.php:
--------------------------------------------------------------------------------
1 | sumWeights($weights, $vatNumber);
79 | if ($checkVal % 11 == 10) {
80 | $weights = [3, 4, 5, 6, 7, 8, 9, 10];
81 | $checkVal = $this->sumWeights($weights, $vatNumber, $weightStart);
82 |
83 | $checkVal = ($checkVal % 11) == 10 ? 0 : ($checkVal % 11);
84 | } else {
85 | $checkVal = $checkVal % $restModulo;
86 | }
87 | return $checkVal == (int) $vatNumber[$vatNumberPosition];
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorBE.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorBE
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C0 C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C0 Either 0 or 1 (starting september 2023)
22 | * C1 Numeric from 1 to 9
23 | * C2 ... C9 Numeric from 0 to 9
24 | *
25 | * Rules:
26 | * [C8 C9]
27 | * 97 - ([C0 C1 C2 C3 C4 C5 C6 C7] modulo 97)
28 | */
29 | class ValidatorBE extends ValidatorAbstract
30 | {
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function validate(string $vatNumber): bool
35 | {
36 | if (strlen($vatNumber) != 10) {
37 | return false;
38 | }
39 |
40 | $checkVal = (int) substr($vatNumber, 0, -2);
41 |
42 | return 97 - ($checkVal % 97) == (int) substr($vatNumber, -2);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorBG.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorBG
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C1 ... C9 Numeric from 0 to 9
22 | *
23 | * Rules:
24 | * C9
25 | * A1 = 1*C1 + 2*C2 + 3*C3 + 4*C4 + 5*C5 + 6*C6 + 7*C7 + 8*C8
26 | * R1 = A1 modulo 11
27 | * If R1 = 10, then
28 | * A2 = 3*C1 + 4*C2 + 5*C3 + 6*C4 + 7*C5 + 8*C6 + 9*C7 + 10*C8
29 | * R2 = A2 modulo 11
30 | * If R2 = 10 then R = 0
31 | * Else R = R2
32 | * Else R = R1
33 | * C9 = R
34 | */
35 | class ValidatorBG extends ValidatorAbstract
36 | {
37 | /**
38 | * {@inheritdoc}
39 | */
40 | public function validate(string $vatNumber): bool
41 | {
42 | $vatNumberLength = strlen($vatNumber);
43 | if (! in_array($vatNumberLength, [9, 10], true)) {
44 | return false;
45 | }
46 |
47 | if (10 === $vatNumberLength) {
48 | return $this->validateNaturalPerson($vatNumber)
49 | || $this->validateForeignNaturalPerson($vatNumber);
50 | }
51 | return $this->validateBusiness($vatNumber);
52 | }
53 |
54 | /**
55 | * Validation for business VAT ID's with 9 digits
56 | *
57 | * @param string $vatNumber
58 | * @return bool
59 | */
60 | private function validateBusiness(string $vatNumber): bool
61 | {
62 | $weights = [1, 2, 3, 4, 5, 6, 7, 8];
63 | return $this->checkValue($vatNumber, $weights, parent::DEFAULT_MODULO, 8);
64 | }
65 |
66 | /**
67 | * Validate VAT ID's for natural persons
68 | *
69 | * @param string $vatNumber
70 | * @return bool
71 | * @see https://github.com/yolk/valvat/blob/master/lib/valvat/checksum/bg.rb
72 | */
73 | private function validateNaturalPerson(string $vatNumber): bool
74 | {
75 | $weights = [2, 4, 8, 5, 10, 9, 7, 3, 6];
76 | return $this->checkValue($vatNumber, $weights, parent::DEFAULT_MODULO, parent::DEFAULT_VAT_POSITION);
77 | }
78 |
79 | /**
80 | * Validate VAT ID's for foreign natural persons
81 | *
82 | * @param string $vatNumber
83 | * @return bool
84 | * @see https://github.com/yolk/valvat/blob/master/lib/valvat/checksum/bg.rb
85 | */
86 | private function validateForeignNaturalPerson(string $vatNumber): bool
87 | {
88 | $weights = [21, 19, 17, 13, 11, 9, 7, 3, 1];
89 | return $this->checkValue($vatNumber, $weights, 10, parent::DEFAULT_VAT_POSITION);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorCY.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorCY
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C1 ... C8 Numeric from 0 to 9
22 | * C9 Alphabetic
23 | * C1 0, 1, 3, 4, 5, 6, 9
24 | *
25 | * Rules:
26 | * C1 C2
27 | * C1C2 cannot be 12 (e.g. 12000139V is invalid)
28 | */
29 | class ValidatorCY extends ValidatorAbstract
30 | {
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function validate(string $vatNumber): bool
35 | {
36 | if (strlen($vatNumber) != 9) {
37 | return false;
38 | }
39 |
40 | if (intval(substr($vatNumber, 0, 2) == 12)) {
41 | return false;
42 | }
43 |
44 | return in_array((int) $vatNumber[0], [0, 1, 3, 4, 5, 6, 9], true)
45 | && ctype_alpha($vatNumber[8]);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorCZ.php:
--------------------------------------------------------------------------------
1 |
6 | * @license MIT
7 | */
8 |
9 | namespace DragonBe\Vies\Validator;
10 |
11 | /**
12 | * Class ValidatorCZ
13 | * @package DragonBe\Vies\Validator
14 | *
15 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
16 | *
17 | * Range:
18 | * C1 ... C8 Numeric from 0 to 9
19 | * C1 <> 9
20 | *
21 | * Rules:
22 | * C8
23 | * A1 = 8*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7
24 | * A2 = nearest higher multiple of 11
25 | *
26 | * if A1 mod 11 = 0
27 | * then
28 | * A2= A1 + 11
29 | * else
30 | * A2 = CEIL1(A1/11, 1) * 11
31 | *
32 | * D = A2 -A1
33 | * C8 = D mod 10
34 | */
35 | class ValidatorCZ extends ValidatorAbstract
36 | {
37 | /**
38 | * @var array
39 | */
40 | protected $allowedD = [8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8];
41 |
42 | /**
43 | * @param string $vatNumber
44 | * @return bool
45 | */
46 | public function validate(string $vatNumber): bool
47 | {
48 | $vatLength = strlen($vatNumber);
49 |
50 | if ($vatLength === 8) {
51 | return $this->validateLegalEntities($vatNumber);
52 | } elseif ($vatLength === 10) {
53 | return $this->validateIndividualsLong($vatNumber);
54 | } elseif ($vatLength === 9) {
55 | if ($vatNumber[0] == "6") {
56 | return $this->validateIndividualsShortSpecial($vatNumber);
57 | } else {
58 | return $this->validateIndividualsShort($vatNumber);
59 | }
60 | }
61 |
62 | return false;
63 | }
64 |
65 | /**
66 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
67 | *
68 | * Range:
69 | * C1 ... C8 Numeric from 0 to 9
70 | * C1 <> 9
71 | *
72 | * Rules:
73 | * C8
74 | * A1 = 8*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7
75 | * A2 = nearest higher multiple of 11
76 | *
77 | * if A1 mod 11 = 0
78 | * then
79 | * A2= A1 + 11
80 | * else
81 | * A2 = CEIL1(A1/11, 1) * 11
82 | *
83 | * D = A2 -A1
84 | * C8 = D mod 10
85 | *
86 | * @param string $vatNumber
87 | * @return bool
88 | */
89 | protected function validateLegalEntities($vatNumber)
90 | {
91 | $weights = [8, 7, 6, 5, 4, 3, 2];
92 | $checksum = (int)$vatNumber[7];
93 | $checkBase = $this->sumWeights($weights, $vatNumber);
94 |
95 | $checkval = ($checkBase % 11) ? intval(ceil($checkBase / 11) * 11) : intval($checkBase + 11);
96 | $checkval = ($checkval - $checkBase) % 10;
97 |
98 | if ($checksum != $checkval) {
99 | return false;
100 | }
101 |
102 | return true;
103 | }
104 |
105 | /**
106 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
107 | *
108 | * Range:
109 | * C1 ... C9 Numeric from 0 to 9
110 | *
111 | * Rules:
112 | * C1 C2 ... must 00-53
113 | * C3 C4 ... Month of birth
114 | * >= 1 <=12
115 | * >= 51 <= 62
116 | * C5 C6 ... Day of birth
117 | *
118 | * @param string $vatNumber
119 | * @return bool
120 | */
121 | protected function validateIndividualsShort($vatNumber)
122 | {
123 | $monthBase = array_merge(range(1, 12), range(51, 62));
124 |
125 | $yearOfBirth = (int)substr($vatNumber, 0, 2);
126 | $monthOfBirth = (int)substr($vatNumber, 2, 2);
127 | $dayOfBirth = (int)substr($vatNumber, 4, 2);
128 |
129 | //validate day
130 | if ($dayOfBirth < 1 || $dayOfBirth > 31) {
131 | return false;
132 | }
133 |
134 | //validate month
135 | if (in_array($monthOfBirth, $monthBase) === false) {
136 | return false;
137 | }
138 |
139 | //validate year
140 | if ($yearOfBirth > 53) {
141 | return false;
142 | }
143 |
144 | return true;
145 | }
146 |
147 | /**
148 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
149 | *
150 | * Range:
151 | * C1 ... C9 Numeric
152 | * C1 = 6
153 | *
154 | * Rules:
155 | * C9 =
156 | * A1 = 8*C2 + 7*C3 + 6*C4 + 5*C5 + 4*C6 + 3*C7 + 2*C8
157 | * A2 = nearest higher multiple of 11
158 | *
159 | * if A1 mod 11 = 0
160 | * then
161 | * A2 = A1 + 11
162 | * else
163 | * A2 = CEIL1(A1/11, 1) * 11
164 | * D = A2 -A1
165 | *
166 | * @param string $vatNumber
167 | * @return bool
168 | */
169 | protected function validateIndividualsShortSpecial($vatNumber)
170 | {
171 | $weights = [0, 8, 7, 6, 5, 4, 3, 2];
172 | $checkval = $this->sumWeights($weights, $vatNumber, 1);
173 | $checksum = ($checkval % 11);
174 |
175 | if ($checksum > 0) {
176 | $checksum = ceil($checkval / 11) * 11;
177 | } else {
178 | $checksum = $checkval + 11;
179 | }
180 |
181 | $checksum = $checksum - $checkval;
182 | $checkval = $this->allowedD[$checksum - 1];
183 |
184 | if ($vatNumber[8] != $checkval) {
185 | return false;
186 | }
187 |
188 | return true;
189 | }
190 |
191 | /**
192 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10]
193 | *
194 | * Range:
195 | * C1 ... C10 Numeric from 0 to 9
196 | * C1 C2 C3 C4 C5 C6 ... Represents a date of birth of an individual
197 | *
198 | * Rules:
199 | * C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 must be devided by 11 without remainder.
200 | * C1 C2 ... must be in the range 00-[last two digits of current date year] or 54-99
201 | * C3 C4 ... Month of birth
202 | * C5 C6 ... Day of birth
203 | *
204 | * C10 ... A1 = C1C2 + C3C4 + C5C6 + C7C8 + C9C10
205 | * A1 must be divisible by 11 with no remainder.
206 | *
207 | * @param string $vatNumber
208 | * @return bool
209 | */
210 | public function validateIndividualsLong($vatNumber)
211 | {
212 | $monthBase = array_merge(range(1, 12), range(21, 32), range(51, 62), range(71, 82));
213 |
214 | $yearOfBirth = (int)substr($vatNumber, 0, 2);
215 | $monthOfBirth = (int)substr($vatNumber, 2, 2);
216 | $dayOfBirth = (int)substr($vatNumber, 4, 2);
217 |
218 | //validate day
219 | if ($dayOfBirth < 1 || $dayOfBirth > 31) {
220 | return false;
221 | }
222 |
223 | //validate month
224 | if (in_array($monthOfBirth, $monthBase) === false) {
225 | return false;
226 | }
227 |
228 | //validate year
229 | if ($yearOfBirth > (int)date("y") && $yearOfBirth < 54) {
230 | return false;
231 | }
232 |
233 | $checkval = 0;
234 |
235 | for ($i = 0; $i <= 8; $i += 2) {
236 | $checkval += (int)substr($vatNumber, $i, 2);
237 | }
238 |
239 | $checkval = ($checkval % 11);
240 |
241 | if ($checkval) {
242 | return false;
243 | }
244 |
245 | return true;
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorDE.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorDE
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C1 ... C9 Numeric
22 | * C1 > 0
23 | *
24 | * Rules:
25 | * C9
26 | * P = 10
27 | *
28 | * For N = 1…8 (N = character position i.e. C1)
29 | * S = CN + P
30 | * M = S modulo 10
31 | * If M = 0 then M = 10
32 | * P = (2*M) modulo 11
33 | *
34 | * R = 11 – P
35 | * If R = 10
36 | * then
37 | * C9 = 0
38 | * else
39 | * C9 =R
40 | */
41 | class ValidatorDE extends ValidatorAbstract
42 | {
43 | /**
44 | * {@inheritdoc}
45 | */
46 | public function validate(string $vatNumber): bool
47 | {
48 | if (strlen($vatNumber) != 9) {
49 | return false;
50 | }
51 |
52 | $prod = 10;
53 | for ($i = 0; $i < 8; $i++) {
54 | $checkVal = ((int)$vatNumber[$i] + $prod) % 10;
55 | $checkVal = ($checkVal == 0) ? 10 : $checkVal;
56 | $prod = ($checkVal * 2) % 11;
57 | }
58 |
59 | $prod = $prod == 1 ? 11 : $prod;
60 |
61 | return 11 - $prod == (int) substr($vatNumber, -1);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorDK.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorDK
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
19 | *
20 | * Range:
21 | * C1 > 0
22 | *
23 | * Rules:
24 | * R
25 | * R = (2*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8)
26 | *
27 | * R is divisible by 11
28 | */
29 | class ValidatorDK extends ValidatorAbstract
30 | {
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function validate(string $vatNumber): bool
35 | {
36 | if (strlen($vatNumber) != 8) {
37 | return false;
38 | }
39 |
40 | $checksum = $this->sumWeights([2, 7, 6, 5, 4, 3, 2, 1], $vatNumber);
41 |
42 | return ($checksum % 11) === 0;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorEE.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorEE
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C1 .. C9 Numeric
22 | * C1C2 = 10
23 | *
24 | * Rules:
25 | * C9
26 | * A1 = 3*1 + 7*0 + 1*0 + 3*2 + 7*0 + 1*7 + 3*4 + 7*1 = 35
27 | * A2 = CEIL(35;10) = 40
28 | * C9 = 40 - 35 = 5
29 | */
30 | class ValidatorEE extends ValidatorAbstract
31 | {
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function validate(string $vatNumber): bool
36 | {
37 | if (strlen($vatNumber) != 9) {
38 | return false;
39 | }
40 |
41 | $checkVal = $this->sumWeights([3, 7, 1, 3, 7, 1, 3, 7], $vatNumber);
42 | $checkVal = (ceil($checkVal / 10) * 10) - $checkVal;
43 |
44 | return $checkVal == (int)$vatNumber[8];
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorEL.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorEL
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C1 .. C9 Numeric
22 | *
23 | * Rules:
24 | * C9
25 | * A1 = 256*C1 + 128*C2 + 64*C3 + 32*C4 + 16*C5 + 8*C6 + 4*C7 + 2*C8
26 | * A2 = A1 modulo 11
27 | * C9 = A2 modulo 10
28 | */
29 | class ValidatorEL extends ValidatorAbstract
30 | {
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function validate(string $vatNumber): bool
35 | {
36 | if (strlen($vatNumber) != 9) {
37 | return false;
38 | }
39 |
40 | $weights = [256, 128, 64, 32, 16, 8, 4, 2];
41 | $checkVal = $this->sumWeights($weights, $vatNumber);
42 | $checkVal = ($checkVal % 11) > 9 ? 0 : ($checkVal % 11);
43 |
44 | return $checkVal === (int) $vatNumber[8];
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorES.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorES
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C1, C9 Alphanumeric from 0 to 9 or A to Z
22 | * C2 .. C8 Numeric from 0 to 9
23 | *
24 | * Rules:
25 | * C1
26 | * IF C9 Alphabetic then:
27 | * C1 = A, B, C, D, E, F, G, H, N, P, Q, R, S, W
28 | * IF C9 Numeric then:
29 | * C1 = A, B, C, D, E, F, G, H, J, U, V
30 | *
31 | * C9
32 | * IF C9 Alphabetic and C1 = A, B, C, D, E, F, G, H, N, P, Q, R, S, W then
33 | * S1 = C3 + C5 +C7
34 | * S2 = D2 + D4 + D6 + D8, where Di = int(Ci/5) + (2 * Ci)modulo10
35 | * R = 10 – (S1 + S2) modulo 10
36 | * C9 = Check Character(R)
37 | * Check Character: 1-A, 2-B, 3-C, 4-D, 5-E, 6-F, 7-G, 8-H, 9-I, 10-J
38 | *
39 | * IF C9 Alphabetic and C1 = K, L, M, X, Y, Z or numeric
40 | * If C1 = Y then set C1 = 1
41 | * If C1 = Z then set C1 = 2
42 | * If C1 numeric then R = ([C1 C2 C3 C4 C5 C6 C7 C8])modulo23 + 1
43 | * If C1 alphabetic then R = ([C2 C3 C4 C5 C6 C7 C8])modulo23 + 1
44 | * C9 = Check Character(R)
45 | * Check Character: 1-T, 2-R, 3-W, 4-A, 5-G, 6-M, 7-Y, 8-F, 9-P, 10-D, 11-X, 12-B,
46 | * 13-N, 14-J, 15-Z, 16-S, 17-Q, 18-V, 19-H, 20-L, 21-C, 22-K, 23-E
47 | *
48 | * If C9 numeric
49 | * S1 = C3 + C5 + C7
50 | * S2 = D2 + D4 + D6 + D8, where Di = int(Ci/5) + (2 * Ci)modulo10
51 | * R = 10 – (S1 + S2) modulo 1
52 | * C9 = (R)modulo10
53 | */
54 | class ValidatorES extends ValidatorAbstract
55 | {
56 | /**
57 | * Allowed C1 if C9 is Alphabetic
58 | *
59 | * @var array
60 | */
61 | protected $allowedC1Alphabetic = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'N', 'P', 'Q', 'R', 'S', 'W'];
62 |
63 | /**
64 | * Allowed C1 if C9 is Numeric for National juridical
65 | *
66 | * @var array
67 | */
68 | protected $allowedC1Numeric = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'U', 'V'];
69 |
70 | /**
71 | * Allowed C1 if C9 is Numeric for physical person
72 | *
73 | * @var array
74 | */
75 | protected $allowedC1Physical = ['K', 'L', 'M', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
76 |
77 | /**
78 | * Check Character: 1-A, 2-B, 3-C, 4-D, 5-E, 6-F, 7-G, 8-H, 9-I, 10-J
79 | *
80 | * @var array
81 | */
82 | protected $checkCharacter = [
83 | 1 => 'A',
84 | 2 => 'B',
85 | 3 => 'C',
86 | 4 => 'D',
87 | 5 => 'E',
88 | 6 => 'F',
89 | 7 => 'G',
90 | 8 => 'H',
91 | 9 => 'I',
92 | 10 => 'J'
93 | ];
94 |
95 | /**
96 | * Check Character: 1-T, 2-R, 3-W, 4-A, 5-G, 6-M, 7-Y, 8-F, 9-P, 10-D, 11-X, 12-B, 13-N,
97 | * 14-J, 15-Z, 16-S, 17-Q, 18-V, 19-H, 20-L, 21-C, 22-K, 23-E
98 | *
99 | * @var array
100 | */
101 | protected $checkCharacterPhysical = [
102 | 1 => 'T',
103 | 2 => 'R',
104 | 3 => 'W',
105 | 4 => 'A',
106 | 5 => 'G',
107 | 6 => 'M',
108 | 7 => 'Y',
109 | 8 => 'F',
110 | 9 => 'P',
111 | 10 => 'D',
112 | 11 => 'X',
113 | 12 => 'B',
114 | 13 => 'N',
115 | 14 => 'J',
116 | 15 => 'Z',
117 | 16 => 'S',
118 | 17 => 'Q',
119 | 18 => 'V',
120 | 19 => 'H',
121 | 20 => 'L',
122 | 21 => 'C',
123 | 22 => 'K',
124 | 23 => 'E',
125 | ];
126 |
127 | /**
128 | * {@inheritdoc}
129 | */
130 | public function validate(string $vatNumber): bool
131 | {
132 | if (strlen($vatNumber) != 9) {
133 | return false;
134 | }
135 |
136 | if (! is_numeric(substr($vatNumber, 1, 6))) {
137 | return false;
138 | }
139 |
140 | $checksum = $vatNumber[8];
141 | $fieldC1 = $vatNumber[0];
142 |
143 | // Juridical entities other than national ones
144 | if (ctype_alpha($checksum) && in_array($fieldC1, $this->allowedC1Alphabetic)) {
145 | return $checksum === $this->validateJuridical($vatNumber);
146 | }
147 |
148 | // Physical person
149 | if (ctype_alpha($checksum) && in_array($fieldC1, $this->allowedC1Physical)) {
150 | return $checksum === $this->validatePhysical($vatNumber);
151 | }
152 |
153 | // National juridical entities
154 | if (ctype_digit($checksum) && in_array($fieldC1, $this->allowedC1Numeric)) {
155 | return (int) $checksum === $this->validateNational($vatNumber);
156 | }
157 |
158 | return false;
159 | }
160 |
161 | /**
162 | * @param string $vatNumber
163 | *
164 | * @return string
165 | */
166 | private function validateJuridical(string $vatNumber): string
167 | {
168 | $checkVal = 0;
169 |
170 | for ($i = 2; $i <= 8; $i++) {
171 | $checkVal += $this->crossSum((int)$vatNumber[9 - $i] * ($this->isEven($i) ? 2 : 1));
172 | }
173 |
174 | $checkVal = 10 - ($checkVal % 10);
175 |
176 | return $this->checkCharacter[$checkVal];
177 | }
178 |
179 | /**
180 | * @param string $vatNumber
181 | *
182 | * @return int
183 | */
184 | private function validateNational(string $vatNumber): int
185 | {
186 | $checkVal = 0;
187 |
188 | for ($i = 2; $i <= 8; $i++) {
189 | $checkVal += $this->crossSum((int)$vatNumber[9 - $i] * ($this->isEven($i) ? 2 : 1));
190 | }
191 |
192 | $checkVal = 10 - ($checkVal % 10);
193 |
194 | return $checkVal % 10;
195 | }
196 |
197 | /**
198 | * @param string $vatNumber
199 | *
200 | * @return string
201 | */
202 | private function validatePhysical(string $vatNumber): string
203 | {
204 | $vatNumber[0] = str_replace(['Y', 'Z'], [1, 2], $vatNumber[0]);
205 |
206 | if (ctype_digit($vatNumber[0])) {
207 | $checkVal = ((int)substr($vatNumber, 0, 8) % 23) + 1;
208 | } else {
209 | $checkVal = ((int)substr($vatNumber, 1, 7) % 23) + 1;
210 | }
211 |
212 | return $this->checkCharacterPhysical[$checkVal];
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorEU.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorEU
16 | * @package DragonBe\Vies\Validator
17 | */
18 | class ValidatorEU extends ValidatorAbstract
19 | {
20 | /**
21 | * {@inheritdoc}
22 | */
23 | public function validate(string $vatNumber): bool
24 | {
25 | return false;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorFI.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorFI
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
19 | *
20 | * Range:
21 | * C2 .. C8 Numeric from 0 to 9
22 | *
23 | * Rules:
24 | * C8
25 | * R = 11 - (7*C1 + 9*C2 + 10*C3 + 5*C4 + 8*C5 + 4*C6 + 2*C7) modulo11
26 | * If R = 10 then, VAT number is invalid
27 | * If R = 11 then C8 = 0
28 | * Else C8 = R
29 | */
30 | class ValidatorFI extends ValidatorAbstract
31 | {
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function validate(string $vatNumber): bool
36 | {
37 | if (strlen($vatNumber) != 8) {
38 | return false;
39 | }
40 |
41 | $weights = [7, 9, 10, 5, 8, 4, 2];
42 | $checkVal = $this->sumWeights($weights, $vatNumber);
43 |
44 | return (0 === $checkVal % 11)
45 | ? (int) $vatNumber[7] === 0
46 | : 11 - ($checkVal % 11) == (int) $vatNumber[7];
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorFR.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorFR
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11]
19 | *
20 | * Range:
21 | * C1 .. C2 Alphanumeric from A to Z or 0 to 9
22 | * C2 .. C11 Numeric from 0 to 9
23 | *
24 | * Rules:
25 | * Case 1: Old Style
26 | * [C1 C2] = ([C3 C4 C5 C6 C7 C8 C9 C10 C11] [1 2])modulo 97
27 | *
28 | * Case 2 : New Style
29 | * S1 = Check Character (C1)
30 | * S2 = Check Character (C2)
31 | *
32 | * If C1 numeric then
33 | * C2 alphabetic
34 | * S = (S1 * 24) + (S2 – 10)
35 | *
36 | * IF C1 alphabetic then
37 | * S = (S1*34) + (S2-100)
38 | *
39 | * P = (S/11) + 1
40 | * R1 = (S)modulo11
41 | * R2 = ( [C3 C4 C5 C6 C7 C8 C9 C10 C11] + P)modulo11
42 | * R1 = R2
43 | *
44 | * Check Character
45 | * 0-0, 1-1, 2-2, 3-3, 4-4, 5-5, 6-6, 7-7, 8-8, 9-9, 10-A, 11-B, 12-C, 13-D, 14-E, 15-F, 16-G, 17-H, 18-J, 19-K,
46 | * 20-L, 21-M, 22-N, 23-P, 24-Q, 25-R, 26-S, 27-T, 28-U, 29-V, 30-W, 31-X, 32-Y, 33-Z.
47 | *
48 | */
49 | class ValidatorFR extends ValidatorAbstract
50 | {
51 | /**
52 | * the valid characters for the first two digits (O and I are missing)
53 | *
54 | * @var string
55 | */
56 | protected $alphabet = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ';
57 |
58 | /**
59 | * {@inheritdoc}
60 | */
61 | public function validate(string $vatNumber): bool
62 | {
63 | if (strlen($vatNumber) != 11) {
64 | return false;
65 | }
66 |
67 | if (strpos($this->alphabet, $vatNumber[0]) === false) {
68 | return false;
69 | }
70 |
71 | if (strpos($this->alphabet, $vatNumber[1]) === false) {
72 | return false;
73 | }
74 |
75 | $checksum = substr($vatNumber, 0, 2);
76 |
77 | if (ctype_digit($checksum)) {
78 | return $checksum == $this->validateOld($vatNumber);
79 | }
80 |
81 | return $checksum == $this->validateNew($vatNumber);
82 | }
83 |
84 | /**
85 | * @param string $vatNumber
86 | *
87 | * @return string
88 | */
89 | private function validateOld(string $vatNumber): string
90 | {
91 | $checkVal = substr($vatNumber, 2);
92 | if (! ctype_digit($checkVal)) {
93 | return "";
94 | }
95 | $checkVal .= "12";
96 | if (PHP_INT_SIZE === 4 && extension_loaded('bcmath')) {
97 | $checkVal = (int) bcmod($checkVal, "97");
98 | } else {
99 | $checkVal = intval($checkVal) % 97;
100 | }
101 |
102 | return $checkVal == 0 ? "00" : (string) $checkVal;
103 | }
104 |
105 | /**
106 | * @param string $vatNumber
107 | *
108 | * @return bool
109 | */
110 | private function validateNew(string $vatNumber): bool
111 | {
112 | $multiplier = 34;
113 | $subStractor = 100;
114 | if (ctype_digit($vatNumber[0])) {
115 | $multiplier = 24;
116 | $subStractor = 10;
117 | }
118 |
119 | $checkCharacter = array_flip(str_split($this->alphabet));
120 | $checkVal = ($checkCharacter[$vatNumber[0]] * $multiplier) + $checkCharacter[$vatNumber[1]] - $subStractor;
121 |
122 | if (PHP_INT_SIZE === 4 && extension_loaded("bcmath")) {
123 | return (int) bcmod(bcadd(substr($vatNumber, 2), strval(($checkVal / 11) + 1)), "11") === $checkVal % 11;
124 | } else {
125 | return ((int) (intval(substr($vatNumber, 2)) + ($checkVal / 11) + 1) % 11) == $checkVal % 11;
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorGB.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorGB
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5]
19 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9]
20 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12]
21 | *
22 | * Range:
23 | * C1 .. C2 Alphanumeric from A to Z or 0 to 9
24 | * C2 .. C11 Numeric from 0 to 9
25 | *
26 | * Rules:
27 | * Case 1:
28 | * [C1 C2] Alpha: “GD” or “HA”
29 | * C3 ... C5 Numeric from 0 to 9
30 | *
31 | * if [C1 C2] = “GD”
32 | * [C3 C4 C5] from 000 to 499
33 | *
34 | * If [C1 C2] = “HA”
35 | * [C3 C4 C5] from 500 to 999
36 | *
37 | * Case 2
38 | * [C1 C2 C3] from 000 to 009 are numbers for Isle of Man
39 | * [C10 C11 C12] > 000
40 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9] >000000000
41 | *
42 | * [C8 C9]
43 | * R1 = (8*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8C9) modulo 97
44 | * R2 = ((8*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8C9) + 55) modulo 97
45 | * Either R1 or R2 must equal to zero.
46 | *
47 | */
48 | class ValidatorGB extends ValidatorAbstract
49 | {
50 | /**
51 | * {@inheritdoc}
52 | */
53 | public function validate(string $vatNumber): bool
54 | {
55 | if (strlen($vatNumber) == 5) {
56 | return $this->validateGovernment($vatNumber);
57 | }
58 |
59 | if (strlen($vatNumber) != 9 && strlen($vatNumber) != 12) {
60 | return false;
61 | }
62 |
63 | $weights = [8, 7, 6, 5, 4, 3, 2];
64 | $checkVal = $this->sumWeights($weights, $vatNumber);
65 | $checkVal += (int)substr($vatNumber, 7, 2);
66 |
67 | $Result1 = $checkVal % 97;
68 | $Result2 = ($Result1 + 55) % 97;
69 |
70 | return ! ($Result1 * $Result2);
71 | }
72 |
73 | /**
74 | * Validate Government VAT
75 | *
76 | * @param string $vatNumber
77 | *
78 | * @return bool
79 | */
80 | private function validateGovernment(string $vatNumber): bool
81 | {
82 | $prefix = strtoupper(substr($vatNumber, 0, 2));
83 | $number = (int) substr($vatNumber, 2, 3);
84 |
85 | // Government departments
86 | if ($prefix == 'GD') {
87 | return $number < 500;
88 | }
89 |
90 | // Health authorities
91 | if ($prefix == 'HA') {
92 | return $number > 499;
93 | }
94 |
95 | return false;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorHR.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorHR
16 | * @package DragonBe\Vies\Validator
17 | */
18 | class ValidatorHR extends ValidatorAbstract
19 | {
20 | /**
21 | * {@inheritdoc}
22 | */
23 | public function validate(string $vatNumber): bool
24 | {
25 | if (strlen($vatNumber) != 11) {
26 | return false;
27 | }
28 |
29 | if (! ctype_digit($vatNumber)) {
30 | return false;
31 | }
32 |
33 | $product = 10;
34 |
35 | for ($i = 0; $i < 10; $i++) {
36 | $sum = ($vatNumber[$i] + $product) % 10;
37 | $sum = ($sum == 0) ? 10 : $sum;
38 | $product = (2 * $sum) % 11;
39 | }
40 |
41 | return ($product + (int) $vatNumber[10]) % 10 == 1;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorHU.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorHU
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
19 | *
20 | * Range:
21 | * C1 ... C8 Numeric from 0 to 9
22 | *
23 | * Rules:
24 | * C8
25 | * A1 = 9*C1 + 7*C2 + 3*C3 + 1*C4 + 9*C5 + 7*C6 + 3*C7
26 | * If the number in the right hand column of A1 is zero then C8 = 0
27 | * Otherwise, subtract the number in the right hand column of A1 from 10
28 | * C8 = A1
29 | */
30 | class ValidatorHU extends ValidatorAbstract
31 | {
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function validate(string $vatNumber): bool
36 | {
37 | if (strlen($vatNumber) != 8) {
38 | return false;
39 | }
40 |
41 | $weights = [9, 7, 3, 1, 9, 7, 3];
42 | $checksum = (int) $vatNumber[7];
43 | $checkVal = $this->sumWeights($weights, $vatNumber);
44 | $checkVal = (int) substr((string) $checkVal, -1);
45 | $checkVal = ($checkVal > 0) ? 10 - $checkVal : 0;
46 |
47 | return $checksum == $checkVal;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorIE.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorIE
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
19 | *
20 | */
21 | class ValidatorIE extends ValidatorAbstract
22 | {
23 |
24 | protected $alphabet = 'WABCDEFGHIJKLMNOPQRSTUV';
25 |
26 | /**
27 | * {@inheritdoc}
28 | */
29 | public function validate(string $vatNumber): bool
30 | {
31 | if (strlen($vatNumber) != 8 && strlen($vatNumber) != 9) {
32 | return false;
33 | }
34 |
35 | return $this->validateIENew($vatNumber)
36 | || $this->validateIEOld($vatNumber);
37 | }
38 |
39 | /**
40 | * @param string $vatNumber
41 | *
42 | * @return bool
43 | */
44 | private function validateIEOld(string $vatNumber): bool
45 | {
46 | $transform = ['0', substr($vatNumber, 2, 5), $vatNumber[0], $vatNumber[7]];
47 | $vat_id = join('', $transform);
48 |
49 | return $this->validateIENew($vat_id);
50 | }
51 |
52 | /**
53 | * @param string $vatNumber
54 | *
55 | * @return bool
56 | */
57 | private function validateIENew(string $vatNumber): bool
58 | {
59 | $checksum = strtoupper(substr($vatNumber, 7, 1));
60 | $checkNumber = substr($vatNumber, 0, 8);
61 | $checkVal = 0;
62 |
63 | for ($i = 2; $i <= 8; $i++) {
64 | $checkVal += (int)$checkNumber[8 - $i] * $i;
65 | }
66 |
67 | if (strlen($vatNumber) == 9) {
68 | $checkVal += (9 * strpos($this->alphabet, $vatNumber[8]));
69 | }
70 |
71 | $checkVal = ($checkVal % 23);
72 |
73 | if ($checkVal == 0) {
74 | return $checksum == 'W';
75 | }
76 |
77 | $checkChar = 'A';
78 | for ($i = $checkVal - 1; $i > 0; $i--) {
79 | $checkChar++;
80 | }
81 |
82 | return $checkChar == $checksum;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorIT.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorIT
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11]
19 | *
20 | * Range:
21 | * C1 ... C11 Numeric from 0 to 9
22 | * [C8 C9 C10] (>000 and <101) or (=120) or (=121) or (=999) or (=888)
23 | *
24 | * Rules:
25 | * C11
26 | * S1 = C1 + C3 + C5 + C7 + C9
27 | * S2 = D2 + D4 + D6 + D8 + D10
28 | * where Di = int(Ci/5) + (2*Ci)modulo10
29 | * C11 = (10 – (S1+S2)modulo10)modulo10
30 | */
31 | class ValidatorIT extends ValidatorAbstract
32 | {
33 |
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public function validate(string $vatNumber): bool
38 | {
39 | if (strlen($vatNumber) != 11) {
40 | return false;
41 | }
42 |
43 | if (! ctype_digit($vatNumber)) {
44 | return false;
45 | }
46 |
47 | if (substr($vatNumber, 0, 7) == '0000000') {
48 | return false;
49 | }
50 |
51 | $checksum = (int) substr($vatNumber, -1);
52 | $Sum1 = 0;
53 | $Sum2 = 0;
54 | for ($i = 1; $i <= 10; $i++) {
55 | if (! $this->isEven($i)) {
56 | $Sum1 += $vatNumber[$i - 1];
57 | } else {
58 | $Sum2 += (int)($vatNumber[$i - 1] / 5) + ((2 * $vatNumber[$i - 1]) % 10);
59 | }
60 | }
61 |
62 | $checkVal = (10 - ($Sum1 + $Sum2) % 10) % 10;
63 |
64 | return $checksum == $checkVal;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorInterface.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | interface ValidatorInterface
15 | {
16 | /**
17 | * @param string $vatNumber
18 | *
19 | * @return bool
20 | */
21 | public function validate(string $vatNumber): bool;
22 | }
23 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorLT.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorLT
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12]
20 | *
21 | * Range:
22 | * C1 ... C12 Numeric from 0 to 9
23 | * C8 = 1
24 | *
25 | * Rules:
26 | * C8
27 | * A1 = 1*C1 + 2*C2 + 3*C3 + 4*C4 + 5*C5 + 6*C6 + 7*C7 + 8*C8 + 9*C9 + 1*C10 + 2*C11
28 | * R1 = A1 modulo 11
29 | *
30 | * If R1 <> 10, then C12 = R1
31 | * Else
32 | *
33 | * A2 = 3*C1 + 4*C2 + 5*C3 + 6*C4 + 7*C5 + 8*C6 + 9*C7 + 1*C8 + 2*C9 + 3*C10 + 4*C11
34 | * R2 = A2 modulo 11
35 | * If R2 = 10, then C12 = 0
36 | * Else C12 = R2
37 | */
38 | class ValidatorLT extends ValidatorAbstract
39 | {
40 | /**
41 | * {@inheritdoc}
42 | */
43 | public function validate(string $vatNumber): bool
44 | {
45 | if (strlen($vatNumber) == 12) {
46 | return $this->validateTemporaryTaxpayer($vatNumber);
47 | }
48 |
49 | if (strlen($vatNumber) == 9) {
50 | return $this->validateLegal($vatNumber);
51 | }
52 |
53 | return false;
54 | }
55 |
56 | /**
57 | * Validate Temporary Tax Payer
58 | *
59 | * @param string $vatNumber
60 | *
61 | * @return bool
62 | */
63 | private function validateTemporaryTaxpayer(string $vatNumber): bool
64 | {
65 | if ($vatNumber[10] != 1) {
66 | return false;
67 | }
68 |
69 | $weights = [1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2];
70 | $checksum = (int)$vatNumber[11];
71 | $checkVal = $this->sumWeights($weights, $vatNumber);
72 |
73 | if (($checkVal % 11) == 10) {
74 | $weights = [3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4];
75 | $checkVal = $this->sumWeights($weights, $vatNumber);
76 | $checkVal = ($checkVal % 11 == 10) ? 0 : $checkVal % 11;
77 |
78 | return $checkVal == $checksum;
79 | }
80 |
81 | return $checkVal % 11 == $checksum;
82 | }
83 |
84 | /**
85 | * Validate Legal
86 | *
87 | * @param string $vatNumber
88 | *
89 | * @return bool
90 | */
91 | private function validateLegal(string $vatNumber): bool
92 | {
93 | if ($vatNumber[7] != 1) {
94 | return false;
95 | }
96 |
97 | $weights = [1, 2, 3, 4, 5, 6, 7, 8];
98 | $checksum = (int) $vatNumber[8];
99 | $checkVal = $this->sumWeights($weights, $vatNumber);
100 |
101 | if (($checkVal % 11) == 10) {
102 | $weights = [3, 4, 5, 6, 7, 8, 9, 1];
103 | $checkVal = $this->sumWeights($weights, $vatNumber);
104 | $checkVal = ($checkVal % 11 == 10) ? 0 : $checkVal % 11;
105 |
106 | return $checkVal == $checksum;
107 | }
108 |
109 | return $checkVal % 11 == $checksum;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorLU.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorLU
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
19 | *
20 | * Range:
21 | * C1 ... C8 Numeric from 0 to 9
22 | *
23 | * Rules:
24 | * [C7 C8]
25 | * ([C1 C2 C3 C4 C5 C6]) Modulo 89
26 | */
27 | class ValidatorLU extends ValidatorAbstract
28 | {
29 | /**
30 | * {@inheritdoc}
31 | */
32 | public function validate(string $vatNumber): bool
33 | {
34 | if (strlen($vatNumber) != 8) {
35 | return false;
36 | }
37 |
38 | $checksum = (int)substr($vatNumber, -2);
39 | $checkVal = (int)substr($vatNumber, 0, 6);
40 |
41 | return ($checkVal % 89) == $checksum;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorLV.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorLV
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11]
19 | *
20 | * Range:
21 | * C1 ... C11 Numeric from 0 to 9
22 | * C1 > 3
23 | *
24 | * Rules:
25 | * C11
26 | * A1 = 9*C1 + 1*C2 + 4*C3 + 8*C4 + 3*C5 + 10*C6 + 2*C7 + 5*C8 + 7*C9 + 6*C1
27 | * R = 3 - (A1 modulo 11)
28 | * If R < -1, then C11 = R + 11
29 | * If R > -1, then C11 = R
30 | * If R = -1, then VAT number is invalid
31 | */
32 | class ValidatorLV extends ValidatorAbstract
33 | {
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public function validate(string $vatNumber): bool
38 | {
39 | if (strlen($vatNumber) != 11) {
40 | return false;
41 | }
42 |
43 | if ((int)$vatNumber[0] <= 3) {
44 | return false;
45 | }
46 |
47 | $weights = [9, 1, 4, 8, 3, 10, 2, 5, 7, 6];
48 | $checksum = (int)substr($vatNumber, -1);
49 | $checkVal = $this->sumWeights($weights, $vatNumber);
50 | $checkVal = 3 - ($checkVal % 11);
51 |
52 | if ($checkVal == -1) {
53 | return false;
54 | }
55 |
56 | if ($checkVal < -1) {
57 | $checkVal += 11;
58 | }
59 |
60 | return $checksum == $checkVal;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorMT.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorMT
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
19 | *
20 | * Range:
21 | * C1 ... C8 Numeric from 0 to 9
22 | * C1 ... C6 > 100000
23 | *
24 | * Rules:
25 | * [C7 C8]
26 | * A1 = 3*C1 + 4*C2 + 6*C3 + 7*C4 + 8*C5 + 9*C6
27 | * R = 37 - (A1 modulo 37)
28 | * If R = 00, then C7 C8 = 37
29 | * C7 C8 = R
30 | */
31 | class ValidatorMT extends ValidatorAbstract
32 | {
33 | /**
34 | * {@inheritdoc}
35 | */
36 | public function validate(string $vatNumber): bool
37 | {
38 | if (strlen($vatNumber) != 8) {
39 | return false;
40 | }
41 |
42 | if ((int)substr($vatNumber, 0, 6) <= 100000) {
43 | return false;
44 | }
45 |
46 | $weights = [3, 4, 6, 7, 8, 9];
47 | $checksum = (int)substr($vatNumber, -2, 2);
48 | $checkVal = $this->sumWeights($weights, $vatNumber);
49 | $checkVal = intval(37 - ($checkVal % 37));
50 |
51 | return $checkVal == $checksum;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorNL.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorNL
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12]
19 | */
20 | class ValidatorNL extends ValidatorAbstract
21 | {
22 | /**
23 | * Check Character: 10-A, 11-B .... 35-Z, 36-+, 37-*
24 | *
25 | * @var array
26 | */
27 | protected $checkCharacter = [
28 | 'A' => 10,
29 | 'B' => 11,
30 | 'C' => 12,
31 | 'D' => 13,
32 | 'E' => 14,
33 | 'F' => 15,
34 | 'G' => 16,
35 | 'H' => 17,
36 | 'I' => 18,
37 | 'J' => 19,
38 | 'K' => 20,
39 | 'L' => 21,
40 | 'M' => 22,
41 | 'N' => 23,
42 | 'O' => 24,
43 | 'P' => 25,
44 | 'Q' => 26,
45 | 'R' => 27,
46 | 'S' => 28,
47 | 'T' => 29,
48 | 'U' => 30,
49 | 'V' => 31,
50 | 'W' => 32,
51 | 'X' => 33,
52 | 'Y' => 34,
53 | 'Z' => 35,
54 | '+' => 36,
55 | '*' => 37,
56 | ];
57 |
58 | /**
59 | * {@inheritdoc}
60 | */
61 | public function validate(string $vatNumber): bool
62 | {
63 | if (strlen($vatNumber) != 12) {
64 | return false;
65 | }
66 |
67 | if (strtoupper($vatNumber[9]) != 'B') {
68 | return false;
69 | }
70 |
71 | return $this->validateCommercial($vatNumber) || $this->validateSoleProprietor($vatNumber);
72 | }
73 |
74 | /**
75 | * Range:
76 | * C1 ... C9 Numeric from 0 to 9
77 | * C10 Alphabetic “B”
78 | * C11 ... C12 Numeric from 0 to 9
79 | *
80 | * Rules:
81 | * C9
82 | * A1 = C1*9 + C2*8 + C3*7 + C4*6 + C5*5 + C6*4 + C7*3 + C8*2
83 | * A2 = A1 modulo 11
84 | * If A2 = 10 then number is invalid
85 | * else C9 = A2
86 | *
87 | * [C11 C12]
88 | * >00
89 | *
90 | * @param string $vatNumber
91 | * @return bool
92 | */
93 | protected function validateCommercial(string $vatNumber): bool
94 | {
95 | if ((int)substr($vatNumber, -2) == 0) {
96 | return false;
97 | }
98 |
99 | $checksum = (int)$vatNumber[8];
100 | $weights = [9, 8, 7, 6, 5, 4, 3, 2];
101 | $checkVal = $this->sumWeights($weights, $vatNumber);
102 | $checkVal = ($checkVal % 11) > 9 ? 0 : ($checkVal % 11);
103 |
104 | return $checkVal == $checksum;
105 | }
106 |
107 | /**
108 | * Range:
109 | * C1 ... C9 0-9 A-Z + *
110 | * C10 Alphabetic “B”
111 | * C11 ... C12 Numeric from 0 to 9
112 | *
113 | * [C11 C12]
114 | * 02 - 98
115 | *
116 | * @param string $vatNumber
117 | * @return bool
118 | */
119 | protected function validateSoleProprietor(string $vatNumber): bool
120 | {
121 | if (! preg_match("#^[A-Z0-9+*]{9}B[0-9]{2}$#u", $vatNumber)) {
122 | return false;
123 | }
124 |
125 | $sumBase = array_reduce(str_split($vatNumber), function ($acc, $e) {
126 | if (ctype_digit($e)) {
127 | return $acc.$e;
128 | }
129 |
130 | return $acc.$this->checkCharacter[$e];
131 | }, '2321');
132 |
133 | if (PHP_INT_SIZE === 4 && extension_loaded('bcmath')) {
134 | return bcmod($sumBase, '97') === '1';
135 | } else {
136 | return ((int) $sumBase % 97) === 1;
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorPL.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorPL
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10]
19 | *
20 | * Range:
21 | * C1 ... C9 Numeric from 0 to 9
22 | *
23 | * Rules:
24 | * C10
25 | * A1 = 6*C1 + 5*C2 + 7*C3 + 2*C4 + 3*C5 + 4*C6 + 5*C7 + 6*C8 + 7*C9
26 | * R = A1 modulo 11
27 | * If R = 10, then VAT number is invalid
28 | * C10 = R
29 | */
30 | class ValidatorPL extends ValidatorAbstract
31 | {
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function validate(string $vatNumber): bool
36 | {
37 | if (strlen($vatNumber) != 10) {
38 | return false;
39 | }
40 |
41 | $weights = [6, 5, 7, 2, 3, 4, 5, 6, 7];
42 | $checksum = (int)$vatNumber[9];
43 | $checkVal = $this->sumWeights($weights, $vatNumber);
44 |
45 | return $checkVal % 11 == $checksum;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorPT.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorPT
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9]
19 | *
20 | * Range:
21 | * C1 > 0
22 | *
23 | * Rules:
24 | * C9
25 | * R = 11 – (9*C1 + 8*C2 + 7*C3 + 6*C4 + 5*C5 + 4*C6 + 3*C7 + 2*C8) modulo 11
26 | * If R= 10 or R= 11, Then R = 0
27 | * C9 = R
28 | */
29 | class ValidatorPT extends ValidatorAbstract
30 | {
31 | /**
32 | * {@inheritdoc}
33 | */
34 | public function validate(string $vatNumber): bool
35 | {
36 | if (strlen($vatNumber) != 9) {
37 | return false;
38 | }
39 |
40 | $checksum = (int)$vatNumber[8];
41 | $weights = [9, 8, 7, 6, 5, 4, 3, 2];
42 | $checkVal = $this->sumWeights($weights, $vatNumber);
43 | $checkVal = (11 - ($checkVal % 11)) > 9 ? 0 : (11 - ($checkVal % 11));
44 |
45 | return $checksum == $checkVal;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorRO.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorRO
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10]
19 | *
20 | * Range:
21 | * C1 ... C10 Numeric
22 | * Note that if the length is less than 10 digits, leading zeros must be assumed to perform the computation.
23 | *
24 | * Rules:
25 | * C10
26 | * A1 = C1*7 + C2*5 + C3*3 + C4*2 + C5*1 + C6*7 + C7*5 + C8*3 + C9*2
27 | * A2 = A1 * 10
28 | * R1 = A2 modulo 11
29 | * If R1 = 10, then R = 0
30 | * Else R = R1
31 | * C10 = R
32 | */
33 | class ValidatorRO extends ValidatorAbstract
34 | {
35 | /**
36 | * {@inheritdoc}
37 | */
38 | public function validate(string $vatNumber): bool
39 | {
40 | if (strlen($vatNumber) < 2 || strlen($vatNumber) > 10) {
41 | return false;
42 | }
43 |
44 | $vatNumber = str_pad($vatNumber, 10, "0", STR_PAD_LEFT);
45 | $checksum = (int)$vatNumber[9];
46 | $weights = [7, 5, 3, 2, 1, 7, 5, 3, 2];
47 | $checkVal = $this->sumWeights($weights, $vatNumber);
48 | $checkVal = ($checkVal * 10) % 11;
49 | if ($checkVal == 10) {
50 | $checkVal = 0;
51 | }
52 |
53 | return $checkVal == $checksum;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorSE.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorSE
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12]
19 | *
20 | * Range:
21 | * C1 ... C12 Numeric
22 | * [C11 C12] >=01 and <= 94
23 | *
24 | * Rules:
25 | * C10
26 | * = (10 – (R + C2 + C4 + C6 + C8) modulo 10) modulo 10
27 | * Where R = S1 + S3 + S5 + S7 + S9
28 | * Where Si = INT(Ci/5) + (Ci*2)modulo 10
29 | */
30 | class ValidatorSE extends ValidatorAbstract
31 | {
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function validate(string $vatNumber): bool
36 | {
37 | if (strlen($vatNumber) != 12) {
38 | return false;
39 | }
40 |
41 | if ((int)substr($vatNumber, -2) < 1 || (int)substr($vatNumber, -2) > 94) {
42 | return false;
43 | }
44 |
45 | $checksum = (int)$vatNumber[9];
46 | $checkVal = 0;
47 |
48 | for ($i = 1; $i < 10; $i++) {
49 | $checkVal += $this->crossSum((int)$vatNumber[9 - $i] * ($this->isEven($i) ? 1 : 2));
50 | }
51 |
52 | return $checksum == (($checkVal % 10) == 0 ? 0 : 10 - ($checkVal % 10));
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorSI.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorSI
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8]
19 | *
20 | * Range:
21 | * C1 ... C8 Numeric
22 | * C1 ... C7 1000000 and <= 9999999
23 | *
24 | * Rules:
25 | * C8
26 | * A1 = C1*8 + C2*7 + C3*6 + C4*5 + C5*4 + C6*3 + C7*2
27 | * R = 11 - (A1 modulo 11)
28 | * If R = 10, then C8 = 0
29 | * else if R = 11 then number is invalid
30 | * else C8 = R
31 | */
32 | class ValidatorSI extends ValidatorAbstract
33 | {
34 | /**
35 | * {@inheritdoc}
36 | */
37 | public function validate(string $vatNumber): bool
38 | {
39 | if (strlen($vatNumber) != 8) {
40 | return false;
41 | }
42 |
43 | if (intval($vatNumber[0]) == 0) {
44 | return false;
45 | }
46 |
47 | $checksum = (int)$vatNumber[7];
48 | $weights = [8, 7, 6, 5, 4, 3, 2];
49 | $checkVal = $this->sumWeights($weights, $vatNumber);
50 |
51 | $mod = 11 - ($checkVal % 11);
52 | if ($mod === 11) {
53 | return false;
54 | }
55 |
56 | $checkVal = ($mod == 10) ? 0 : $mod;
57 |
58 | return $checksum == $checkVal;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorSK.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * Class ValidatorSK
16 | * @package DragonBe\Vies\Validator
17 | *
18 | * VAT format: [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10]
19 | *
20 | * Range:
21 | * C1 ... C10 Numeric
22 | * C1 In the range 1...9
23 | * C2, C4 ... C10 In the range 0...9
24 | * C3 One of 2, 3, 4, 7, 8, 9
25 | *
26 | * Rules:
27 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10]
28 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10] modulo 11 = 0
29 | */
30 | class ValidatorSK extends ValidatorAbstract
31 | {
32 | /**
33 | * {@inheritdoc}
34 | */
35 | public function validate(string $vatNumber): bool
36 | {
37 | if (strlen($vatNumber) != 10
38 | || intval($vatNumber[0]) == 0
39 | || ! in_array((int) $vatNumber[2], [2, 3, 4, 7, 8, 9])
40 | ) {
41 | return false;
42 | }
43 |
44 | if (PHP_INT_SIZE === 4 && extension_loaded("bcmath")) {
45 | return bcmod($vatNumber, '11') === '0';
46 | } else {
47 | return $vatNumber % 11 == 0;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Vies/Validator/ValidatorXI.php:
--------------------------------------------------------------------------------
1 |
9 | * @license MIT
10 | */
11 |
12 | namespace DragonBe\Vies\Validator;
13 |
14 | /**
15 | * This validator was derived from the "ValidatorGB" validator to validate the "XI" VAT numbers of
16 | * "United Kingdom (Northern Ireland)" following the end of the Brexit transition period on December, 31 2020.
17 | *
18 | * It is based on the information at:
19 | * https://www.avalara.com/vatlive/en/vat-news/brexit-northern-ireland-vat-and-eoro--xi--number.html
20 | *
21 | * As more information is published, this validator may be made more precise:
22 | *
23 | * - Remove the logic to validate Isle of Man numbers?
24 | * - Remove the logic to validate 'GD' and 'HA' prefixes?
25 | *
26 | */
27 |
28 | /**
29 | * Class ValidatorXI
30 | * @package DragonBe\Vies\Validator
31 | *
32 | * VAT format: [C1 C2 C3 C4 C5]
33 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9]
34 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 C11 C12]
35 | *
36 | * Range:
37 | * C1 .. C2 Alphanumeric from A to Z or 0 to 9
38 | * C2 .. C11 Numeric from 0 to 9
39 | *
40 | * Rules:
41 | * Case 1:
42 | * [C1 C2] Alpha: “GD” or “HA”
43 | * C3 ... C5 Numeric from 0 to 9
44 | *
45 | * if [C1 C2] = “GD”
46 | * [C3 C4 C5] from 000 to 499
47 | *
48 | * If [C1 C2] = “HA”
49 | * [C3 C4 C5] from 500 to 999
50 | *
51 | * Case 2
52 | * [C1 C2 C3] from 000 to 009 are numbers for Isle of Man
53 | * [C10 C11 C12] > 000
54 | * [C1 C2 C3 C4 C5 C6 C7 C8 C9] >000000000
55 | *
56 | * [C8 C9]
57 | * R1 = (8*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8C9) modulo 97
58 | * R2 = ((8*C1 + 7*C2 + 6*C3 + 5*C4 + 4*C5 + 3*C6 + 2*C7 + C8C9) + 55) modulo 97
59 | * Either R1 or R2 must equal to zero.
60 | *
61 | */
62 | class ValidatorXI extends ValidatorAbstract
63 | {
64 | /**
65 | * {@inheritdoc}
66 | */
67 | public function validate(string $vatNumber): bool
68 | {
69 | if (strlen($vatNumber) == 5) {
70 | return $this->validateGovernment($vatNumber);
71 | }
72 |
73 | if (strlen($vatNumber) != 9 && strlen($vatNumber) != 12) {
74 | return false;
75 | }
76 |
77 | $weights = [8, 7, 6, 5, 4, 3, 2];
78 | $checkVal = $this->sumWeights($weights, $vatNumber);
79 | $checkVal += (int)substr($vatNumber, 7, 2);
80 |
81 | $Result1 = $checkVal % 97;
82 | $Result2 = ($Result1 + 55) % 97;
83 |
84 | return ! ($Result1 * $Result2);
85 | }
86 |
87 | /**
88 | * Validate Government VAT
89 | *
90 | * @param string $vatNumber
91 | *
92 | * @return bool
93 | */
94 | private function validateGovernment(string $vatNumber): bool
95 | {
96 | $prefix = strtoupper(substr($vatNumber, 0, 2));
97 | $number = (int) substr($vatNumber, 2, 3);
98 |
99 | // Government departments
100 | if ($prefix == 'GD') {
101 | return $number < 500;
102 | }
103 |
104 | // Health authorities
105 | if ($prefix == 'HA') {
106 | return $number > 499;
107 | }
108 |
109 | return false;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Vies/ViesException.php:
--------------------------------------------------------------------------------
1 |
12 | * @license MIT
13 | *
14 | */
15 | namespace DragonBe\Vies;
16 |
17 | /**
18 | * ViesException
19 | *
20 | * This class provides an exception layer for usage of the VIES web service
21 | * provided by the European commission to validate VAT numbers of companies
22 | * registered within the European Union
23 | *
24 | * @see \Exception
25 | * @package \DragonBe\Vies
26 | */
27 | class ViesException extends \Exception
28 | {
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/Vies/ViesServiceException.php:
--------------------------------------------------------------------------------
1 |
12 | * @license MIT
13 | *
14 | */
15 | namespace DragonBe\Vies;
16 |
17 | /**
18 | * ViesServiceException
19 | *
20 | * This class provides an exception layer for usage of the VIES web service
21 | * provided by the European commission to validate VAT numbers of companies
22 | * registered within the European Union
23 | *
24 | * @see \Exception
25 | * @package \DragonBe\Vies
26 | */
27 | class ViesServiceException extends \Exception
28 | {
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/autoload.php:
--------------------------------------------------------------------------------
1 | 'BE',
29 | 'vatNumber' => '123456749',
30 | 'requestDate' => date_create(date('Y-m-dP')),
31 | 'valid' => $isValid,
32 | 'traderName' => 'Testing Corp N.V.',
33 | 'traderAddress' => 'MARKT 1' . PHP_EOL . '1000 BRUSSEL',
34 | 'requestIdentifier' => 'XYZ1234567890'
35 | ];
36 | }
37 |
38 | /**
39 | * @param bool $isValid
40 | *
41 | * @return stdClass
42 | */
43 | protected function createViesResponse($isValid = true)
44 | {
45 | return (object) $this->createViesResponseArray($isValid);
46 | }
47 |
48 | public function validationProvider()
49 | {
50 | return [
51 | [true],
52 | [false]
53 | ];
54 | }
55 |
56 | /**
57 | * Test that a VAT response can be created
58 | *
59 | * @covers ::__construct
60 | * @covers ::populate
61 | * @covers ::setCountryCode
62 | * @covers ::getCountryCode
63 | * @covers ::setVatNumber
64 | * @covers ::getVatNumber
65 | * @covers ::setRequestDate
66 | * @covers ::getRequestDate
67 | * @covers ::setValid
68 | * @covers ::isValid
69 | * @covers ::setName
70 | * @covers ::getName
71 | * @covers ::setAddress
72 | * @covers ::getAddress
73 | * @covers ::setIdentifier
74 | * @covers ::getIdentifier
75 | * @covers ::setNameMatch
76 | * @covers ::getNameMatch
77 | * @covers ::setCompanyTypeMatch
78 | * @covers ::getCompanyTypeMatch
79 | * @covers ::setStreetMatch
80 | * @covers ::getStreetMatch
81 | * @covers ::setPostcodeMatch
82 | * @covers ::getPostcodeMatch
83 | * @covers ::setCityMatch
84 | * @covers ::getCityMatch
85 | *
86 | * @dataProvider validationProvider
87 | */
88 | public function testCanCreateResponseAtConstruct($validCheck)
89 | {
90 | $response = $this->createViesResponse($validCheck);
91 | $checkVatResponse = new CheckVatResponse($response);
92 | $this->assertSame($response->countryCode, $checkVatResponse->getCountryCode());
93 | $this->assertSame($response->vatNumber, $checkVatResponse->getVatNumber());
94 | $this->assertSame($response->requestDate, $checkVatResponse->getRequestDate());
95 | $this->assertSame($response->valid, $checkVatResponse->isValid());
96 | $this->assertSame($response->traderName, $checkVatResponse->getName());
97 | $this->assertSame($response->traderAddress, $checkVatResponse->getAddress());
98 | $this->assertSame($response->requestIdentifier, $checkVatResponse->getIdentifier());
99 | }
100 |
101 | /**
102 | * @covers ::__construct
103 | * @covers ::populate
104 | * @covers ::setCountryCode
105 | * @covers ::getCountryCode
106 | * @covers ::setVatNumber
107 | * @covers ::getVatNumber
108 | * @covers ::setRequestDate
109 | * @covers ::getRequestDate
110 | * @covers ::setValid
111 | * @covers ::isValid
112 | * @covers ::setName
113 | * @covers ::getName
114 | * @covers ::setAddress
115 | * @covers ::getAddress
116 | * @covers ::setIdentifier
117 | * @covers ::getIdentifier
118 | * @covers ::setNameMatch
119 | * @covers ::getNameMatch
120 | * @covers ::setCompanyTypeMatch
121 | * @covers ::getCompanyTypeMatch
122 | * @covers ::setStreetMatch
123 | * @covers ::getStreetMatch
124 | * @covers ::setPostcodeMatch
125 | * @covers ::getPostcodeMatch
126 | * @covers ::setCityMatch
127 | * @covers ::getCityMatch
128 | *
129 | * @dataProvider validationProvider
130 | */
131 | public function testCanCreateResponseWithoutNameAndAddressAtConstruct($validCheck)
132 | {
133 | $response = $this->createViesResponse($validCheck);
134 | unset($response->traderName, $response->traderAddress);
135 | $checkVatResponse = new CheckVatResponse($response);
136 | $this->assertSame($response->countryCode, $checkVatResponse->getCountryCode());
137 | $this->assertSame($response->vatNumber, $checkVatResponse->getVatNumber());
138 | $this->assertSame($response->requestDate, $checkVatResponse->getRequestDate());
139 | $this->assertSame($response->valid, $checkVatResponse->isValid());
140 | $this->assertSame($response->requestIdentifier, $checkVatResponse->getIdentifier());
141 | $this->assertSame('---', $checkVatResponse->getName());
142 | $this->assertSame('---', $checkVatResponse->getAddress());
143 | }
144 |
145 | /**
146 | * @covers ::__construct
147 | * @covers ::populate
148 | * @covers ::setCountryCode
149 | * @covers ::getCountryCode
150 | * @covers ::setVatNumber
151 | * @covers ::getVatNumber
152 | * @covers ::setRequestDate
153 | * @covers ::getRequestDate
154 | * @covers ::setValid
155 | * @covers ::isValid
156 | * @covers ::setName
157 | * @covers ::getName
158 | * @covers ::setAddress
159 | * @covers ::getAddress
160 | * @covers ::setIdentifier
161 | * @covers ::getIdentifier
162 | * @covers ::setNameMatch
163 | * @covers ::getNameMatch
164 | * @covers ::setCompanyTypeMatch
165 | * @covers ::getCompanyTypeMatch
166 | * @covers ::setStreetMatch
167 | * @covers ::getStreetMatch
168 | * @covers ::setPostcodeMatch
169 | * @covers ::getPostcodeMatch
170 | * @covers ::setCityMatch
171 | * @covers ::getCityMatch
172 | *
173 | * @dataProvider validationProvider
174 | */
175 | public function testCanCreateResponseWithArrayAtConstruct($validCheck)
176 | {
177 | $response = $this->createViesResponseArray($validCheck);
178 | $checkVatResponse = new CheckVatResponse($response);
179 | $this->assertSame($response['countryCode'], $checkVatResponse->getCountryCode());
180 | $this->assertSame($response['vatNumber'], $checkVatResponse->getVatNumber());
181 | $this->assertSame($response['requestDate'], $checkVatResponse->getRequestDate());
182 | $this->assertSame($response['valid'], $checkVatResponse->isValid());
183 | $this->assertSame($response['traderName'], $checkVatResponse->getName());
184 | $this->assertSame($response['traderAddress'], $checkVatResponse->getAddress());
185 | $this->assertSame($response['requestIdentifier'], $checkVatResponse->getIdentifier());
186 | }
187 |
188 | /**
189 | * @covers ::__construct
190 | * @covers ::getRequestDate
191 | */
192 | public function testDefaultDateIsNow()
193 | {
194 | $vatResponse = new CheckVatResponse();
195 | $this->assertInstanceOf(DateTime::class, $vatResponse->getRequestDate());
196 | $this->assertSame(date('Y-m-dP'), $vatResponse->getRequestDate()->format('Y-m-dP'));
197 | }
198 |
199 | /**
200 | * @covers ::__construct
201 | * @covers ::populate
202 | */
203 | public function testExceptionIsThrownWhenRequiredParametersAreMissing()
204 | {
205 | $this->expectException(InvalidArgumentException::class);
206 | new CheckVatResponse([]);
207 | }
208 |
209 | public function requiredDataProvider()
210 | {
211 | return [
212 | ['DE', '123456749', date('Y-m-dP'), true],
213 | ['ES', '987654321', date('Y-m-dP'), false],
214 | ];
215 | }
216 |
217 | /**
218 | * @covers ::__construct
219 | * @covers ::populate
220 | * @covers ::setCountryCode
221 | * @covers ::getCountryCode
222 | * @covers ::setVatNumber
223 | * @covers ::getVatNumber
224 | * @covers ::setRequestDate
225 | * @covers ::getRequestDate
226 | * @covers ::setValid
227 | * @covers ::isValid
228 | * @covers ::setName
229 | * @covers ::getName
230 | * @covers ::setAddress
231 | * @covers ::getAddress
232 | * @covers ::setIdentifier
233 | * @covers ::getIdentifier
234 | * @covers ::setNameMatch
235 | * @covers ::getNameMatch
236 | * @covers ::setCompanyTypeMatch
237 | * @covers ::getCompanyTypeMatch
238 | * @covers ::setStreetMatch
239 | * @covers ::getStreetMatch
240 | * @covers ::setPostcodeMatch
241 | * @covers ::getPostcodeMatch
242 | * @covers ::setCityMatch
243 | * @covers ::getCityMatch
244 | *
245 | * @dataProvider requiredDataProvider
246 | */
247 | public function testResponseContainsEmptyValuesWithOnlyRequiredArguments(
248 | $countryCode,
249 | $vatNumber,
250 | $requestDate,
251 | $valid
252 | ) {
253 |
254 | $expectedResult = [
255 | 'countryCode' => $countryCode,
256 | 'vatNumber' => $vatNumber,
257 | 'requestDate' => substr($requestDate, 0, -6),
258 | 'valid' => $valid,
259 | 'name' => '---',
260 | 'address' => '---',
261 | 'identifier' => '',
262 | 'nameMatch' => '',
263 | 'companyTypeMatch' => '',
264 | 'streetMatch' => '',
265 | 'postcodeMatch' => '',
266 | 'cityMatch' => '',
267 | ];
268 |
269 | $vatResponse = new CheckVatResponse([
270 | 'countryCode' => $countryCode,
271 | 'vatNumber' => $vatNumber,
272 | 'requestDate' => date_create($requestDate),
273 | 'valid' => $valid,
274 | ]);
275 |
276 | $this->assertSame($expectedResult, $vatResponse->toArray());
277 | }
278 |
279 | /**
280 | * @covers ::__construct
281 | * @covers ::populate
282 | * @covers ::setCountryCode
283 | * @covers ::getCountryCode
284 | * @covers ::setVatNumber
285 | * @covers ::getVatNumber
286 | * @covers ::setRequestDate
287 | * @covers ::getRequestDate
288 | * @covers ::setValid
289 | * @covers ::isValid
290 | * @covers ::setName
291 | * @covers ::getName
292 | * @covers ::setAddress
293 | * @covers ::getAddress
294 | * @covers ::setIdentifier
295 | * @covers ::getIdentifier
296 | * @covers ::setNameMatch
297 | * @covers ::getNameMatch
298 | * @covers ::setCompanyTypeMatch
299 | * @covers ::getCompanyTypeMatch
300 | * @covers ::setStreetMatch
301 | * @covers ::getStreetMatch
302 | * @covers ::setPostcodeMatch
303 | * @covers ::getPostcodeMatch
304 | * @covers ::setCityMatch
305 | * @covers ::getCityMatch
306 | *
307 | * @dataProvider requiredDataProvider
308 | */
309 | public function testResponseAcceptsStringDates(
310 | $countryCode,
311 | $vatNumber,
312 | $requestDate,
313 | $valid
314 | ) {
315 |
316 | $expectedResult = [
317 | 'countryCode' => $countryCode,
318 | 'vatNumber' => $vatNumber,
319 | 'requestDate' => substr($requestDate, 0, -6),
320 | 'valid' => $valid,
321 | 'name' => '---',
322 | 'address' => '---',
323 | 'identifier' => '',
324 | 'nameMatch' => '',
325 | 'companyTypeMatch' => '',
326 | 'streetMatch' => '',
327 | 'postcodeMatch' => '',
328 | 'cityMatch' => '',
329 | ];
330 |
331 | $vatResponse = new CheckVatResponse([
332 | 'countryCode' => $countryCode,
333 | 'vatNumber' => $vatNumber,
334 | 'requestDate' => $requestDate,
335 | 'valid' => $valid,
336 | ]);
337 |
338 | $this->assertSame($expectedResult, $vatResponse->toArray());
339 | }
340 |
341 | /**
342 | * Generates trader details that can be submitted to VIES
343 | * as an additional check
344 | *
345 | * @return array
346 | */
347 | public function traderDetailsProvider(): array
348 | {
349 | return [
350 | [
351 | 'BE',
352 | '0123456789',
353 | 'FooBar',
354 | 'bvba',
355 | 'Kerkstraat 1234',
356 | '2000',
357 | 'Antwerpen',
358 | ],
359 | [
360 | 'NL',
361 | '0123456789',
362 | 'De vrolijke testers',
363 | 'BV',
364 | 'Kerkstraat 12',
365 | '1017 GC',
366 | 'Amsterdam',
367 | ],
368 | [
369 | 'DE',
370 | '0123456789',
371 | 'Die fröhlichen Tester',
372 | 'GmbH',
373 | 'Kaiserstraße 14',
374 | '53113',
375 | 'Bonn',
376 | ],
377 |
378 | ];
379 | }
380 |
381 | /**
382 | * @param string $countryCode
383 | * @param string $vatNumber
384 | * @param string $companyName
385 | * @param string $companyType
386 | * @param string $companyStreet
387 | * @param string $companyPostcode
388 | * @param string $companyCity
389 | *
390 | * @dataProvider traderDetailsProvider
391 | * @covers ::toArray
392 | * @covers ::populate
393 | * @covers ::setCountryCode
394 | * @covers ::getCountryCode
395 | * @covers ::setVatNumber
396 | * @covers ::getVatNumber
397 | * @covers ::setRequestDate
398 | * @covers ::getRequestDate
399 | * @covers ::setValid
400 | * @covers ::isValid
401 | * @covers ::setName
402 | * @covers ::getName
403 | * @covers ::setAddress
404 | * @covers ::getAddress
405 | * @covers ::setIdentifier
406 | * @covers ::getIdentifier
407 | * @covers ::setNameMatch
408 | * @covers ::getNameMatch
409 | * @covers ::setCompanyTypeMatch
410 | * @covers ::getCompanyTypeMatch
411 | * @covers ::setStreetMatch
412 | * @covers ::getStreetMatch
413 | * @covers ::setPostcodeMatch
414 | * @covers ::getPostcodeMatch
415 | * @covers ::setCityMatch
416 | * @covers ::getCityMatch
417 | */
418 | public function testValidatingTraderDetails(
419 | string $countryCode,
420 | string $vatNumber,
421 | string $companyName,
422 | string $companyType,
423 | string $companyStreet,
424 | string $companyPostcode,
425 | string $companyCity
426 | ) {
427 | $requestDate = date('Y-m-dP');
428 | $valid = true;
429 | $identifier = substr(md5('The world is not enough...'), 0, 16);
430 |
431 | $expectedResult = [
432 | 'countryCode' => $countryCode,
433 | 'vatNumber' => $vatNumber,
434 | 'requestDate' => substr($requestDate, 0, -6),
435 | 'valid' => $valid,
436 | 'name' => strtoupper($companyType . ' ' . $companyName),
437 | 'address' => strtoupper($companyStreet . ' ' . $companyPostcode . ' ' . $companyCity),
438 | 'identifier' => $identifier,
439 | 'nameMatch' => '',
440 | 'companyTypeMatch' => '',
441 | 'streetMatch' => '',
442 | 'postcodeMatch' => '',
443 | 'cityMatch' => '',
444 | ];
445 |
446 | $vatResponse = new CheckVatResponse([
447 | 'countryCode' => $countryCode,
448 | 'vatNumber' => $vatNumber,
449 | 'requestDate' => date_create($requestDate),
450 | 'valid' => $valid,
451 | 'traderName' => strtoupper($companyType . ' ' . $companyName),
452 | 'traderAddress' => strtoupper($companyStreet . ' ' . $companyPostcode . ' ' . $companyCity),
453 | 'requestIdentifier' => $identifier,
454 | ]);
455 |
456 | $this->assertSame($expectedResult, $vatResponse->toArray());
457 | }
458 | }
459 |
--------------------------------------------------------------------------------
/tests/Vies/HeartBeatTest.php:
--------------------------------------------------------------------------------
1 | expectException(DomainException::class);
25 | (new HeartBeat())->getHost();
26 | }
27 |
28 | /**
29 | * @covers ::getPort
30 | */
31 | public function testDefaultPortIsHttp()
32 | {
33 | $hb = new HeartBeat();
34 | $port = $hb->getPort();
35 | $this->assertSame(443, $port);
36 | }
37 |
38 | /**
39 | * @covers ::setHost
40 | * @covers ::getHost
41 | */
42 | public function testCanSetHost()
43 | {
44 | $host = 'www.example.com';
45 | $hb = new HeartBeat();
46 | $hb->setHost($host);
47 | $this->assertSame($host, $hb->getHost());
48 | }
49 |
50 | /**
51 | * @covers ::setPort
52 | * @covers ::getPort
53 | */
54 | public function testCanSetPort()
55 | {
56 | $port = 443;
57 | $hb = new HeartBeat();
58 | $hb->setPort($port);
59 | $this->assertSame($port, $hb->getPort());
60 | }
61 |
62 | /**
63 | * @covers ::setTimeout
64 | * @covers ::getTimeout
65 | */
66 | public function testCanSetTimeout()
67 | {
68 | $timeout = 300;
69 | $hb = new HeartBeat();
70 | $hb->setTimeout($timeout);
71 | $this->assertSame($timeout, $hb->getTimeout());
72 | }
73 |
74 | /**
75 | * @covers ::__construct
76 | */
77 | public function testCanOverrideSettingsAtConstruct()
78 | {
79 | $host = 'www.example.com';
80 | $port = 8080;
81 | $hb = new HeartBeat($host, $port);
82 | $this->assertSame($host, $hb->getHost());
83 | $this->assertSame($port, $hb->getPort());
84 | }
85 |
86 | /**
87 | * @covers ::isAlive
88 | */
89 | public function testVerifyServicesIsAlive()
90 | {
91 | $host = '127.0.0.1';
92 | $port = -1;
93 | HeartBeat::$testingEnabled = true;
94 | HeartBeat::$testingServiceIsUp = true;
95 | $hb = new HeartBeat($host, $port);
96 | $this->assertTrue($hb->isAlive());
97 | }
98 |
99 | /**
100 | * @covers ::isAlive
101 | */
102 | public function testVerifyServicesIsDown()
103 | {
104 | $host = '127.0.0.1';
105 | $port = -1;
106 | HeartBeat::$testingEnabled = true;
107 | HeartBeat::$testingServiceIsUp = false;
108 | $hb = new HeartBeat($host, $port);
109 | $this->assertFalse($hb->isAlive());
110 | }
111 |
112 | public function socketProvider(): array
113 | {
114 | return [
115 | 'Non-existing socket on localhost' => ['127.0.0.1', -1, 10, null, false],
116 | 'Socket 443 on ec.europe.eu' => [Vies::VIES_DOMAIN, Vies::VIES_PORT, 10, null, false],
117 | 'Socket 443 on ec.europe.eu'.Vies::VIES_PATH => [
118 | Vies::VIES_DOMAIN,
119 | Vies::VIES_PORT,
120 | 10,
121 | Vies::VIES_PATH,
122 | true
123 | ],
124 | ];
125 | }
126 |
127 | /**
128 | * @dataProvider socketProvider
129 | * @covers ::isAlive
130 | * @covers ::reachOut
131 | * @covers ::getSecuredResponse
132 | * @covers ::readContents
133 | */
134 | public function testIsAliveUsingSockets($host, $port, $timeout, $path, $expectedResult)
135 | {
136 | HeartBeat::$testingEnabled = false;
137 | $heartBeat = new HeartBeat($host, $port, $timeout, $path);
138 | $actualResult = $heartBeat->isAlive();
139 | $this->assertSame($expectedResult, $actualResult);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/AbstractValidatorTest.php:
--------------------------------------------------------------------------------
1 | assertSame($state, (new Vies())->validateVatSum($country, $vatNumber));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorATTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('AT', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['U10223006', true],
22 | ['U1022300', false],
23 | ['A10223006', false],
24 | ['U10223005', false],
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorBETest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('BE', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['776091951', false],
22 | ['0776091952', false],
23 | ['07760919', false],
24 | ['0417710407', true],
25 | ['0627515170', true],
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorBGTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('BG', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['301004503', true],
22 | ['10100450', false],
23 | ['301004502', false],
24 | ['8311046307', true],
25 | ['3002779909', true],
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorCYTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('CY', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['00532445O', true],
22 | ['005324451', false],
23 | ['0053244511', false],
24 | ['12000139V', false],
25 | ['72000139V', false],
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorCZTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('CZ', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['46505334', true],
22 | ['7103192745', true],
23 | ['640903926', true],
24 | ['395601439', true],
25 | ['630903928', true],
26 | ['27082440', true],
27 | ['4650533', false],
28 | ['96505334', false],
29 | ['46505333', false],
30 | ['7103192743', false],
31 | ['5103192743', false],
32 | ['1903192745', false],
33 | ['7133192745', false],
34 | ['395632439', false],
35 | ['396301439', false],
36 | ['545601439', false],
37 | ['640903927', false],
38 | ['7103322745', false],
39 | ];
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorDETest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('DE', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['111111125', true],
22 | ['111111124', false],
23 | ['1234567', false],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorDKTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('DK', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['88146328', true],
22 | ['88146327', false],
23 | ['1234567', false],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorEETest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('EE', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['100207415', true],
22 | ['1002074', false],
23 | ['A12345678', false],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorELTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('EL', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['040127797', true],
22 | ['040127796', false],
23 | ['1234567', false],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorESTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('ES', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['A0011012B', true],
22 | ['A78304516', true],
23 | ['X5910266W', true],
24 | ['K0011012B', false],
25 | ['12345678', false],
26 | ['K001A012B', false],
27 | ['A0011012C', false],
28 | ['Z5910266W', false],
29 | ['J5910266W', false],
30 | ];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorEUTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('EU', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['372009975', false],
22 | ['826409867', false],
23 | ['528003555', false],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorFITest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('FI', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['09853608', true],
22 | ['09853607', false],
23 | ['1234567', false],
24 | ['01089940', true],
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorFRTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('FR', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['00300076965', true],
22 | ['K7399859412', true],
23 | ['4Z123456782', true],
24 | ['0030007696A', false],
25 | ['1234567890', false],
26 | ['K6399859412', false],
27 | ['KO399859412', false],
28 | ['IO399859412', false],
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorGBTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('GB', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['434031494', true],
22 | ['GD001', true],
23 | ['HA500', true],
24 | ['434031493', false],
25 | ['12345', false],
26 | ['GD500', false],
27 | ['HA100', false],
28 | ['12345678', false],
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorHRTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('HR', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['38192148118', true],
22 | ['3819214811', false],
23 | ['1234567890A', false],
24 | ['AA123456789', false],
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorHUTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('HU', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['21376414', true],
22 | ['10597190', true],
23 | ['2137641', false],
24 | ['1234567A', false],
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorIETest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('IE', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['8Z49289F', true],
22 | ['3628739L', true],
23 | ['5343381W', true],
24 | ['6433435OA', true],
25 | ['8Z49389F', false],
26 | ['1234567', false],
27 | ['6433435OB', false],
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorITTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('IT', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['00000010215', true],
22 | ['00000010214', false],
23 | ['1234567890', false],
24 | ['00000001234', false],
25 | ['AA123456789', false],
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorLTTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('LT', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['210061371310', true],
22 | ['213179412', true],
23 | ['290061371314', true],
24 | ['208640716', true],
25 | ['213179422', false],
26 | ['21317941', false],
27 | ['1234567890', false],
28 | ['1234567890AB', false],
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorLUTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('LU', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['10000356', true],
22 | ['10000355', false],
23 | ['1234567', false],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorLVTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('LV', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['40003009497', true],
22 | ['40013009497', false],
23 | ['40003009496', false],
24 | ['1234567890', false],
25 | ['00212345678', false],
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorMTTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('MT', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['15121333', true],
22 | ['15121332', false],
23 | ['1234567', false],
24 | ['05121333', false],
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorNLTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('NL', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['010000446B01', true],
22 | ['010000436B01', false],
23 | ['12345678901', false],
24 | ['123456789A12', false],
25 | ['123456789B00', false],
26 | ['002342672B42', true],
27 | ];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorPLTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('PL', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['5260001246', true],
22 | ['12342678090', false],
23 | ['1212121212', false],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorPTTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('PT', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['502757191', true],
22 | ['502757192', false],
23 | ['12345678', false],
24 | ];
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorROTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('RO', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['11198699', true],
22 | ['14186770', true],
23 | ['11198698', false],
24 | ['1', false],
25 | ['12345678902', false],
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorSETest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('SE', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['556188840401', true],
22 | ['556188840400', false],
23 | ['1234567890', false],
24 | ['556181140401', false],
25 | ];
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorSITest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('SI', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['15012557', true],
22 | ['15012556', false],
23 | ['12345670', false],
24 | ['01234567', false],
25 | ['1234567', false],
26 | ['95796550', true],
27 | ['95736220', false],
28 | ];
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorSKTest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('SK', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['4030000007', true],
22 | ['4030000006', false],
23 | ['123456789', false],
24 | ['0123456789', false],
25 | ['4060000007', false],
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/Vies/Validator/ValidatorXITest.php:
--------------------------------------------------------------------------------
1 | validateVatNumber('XI', $vatNumber, $state);
16 | }
17 |
18 | public function vatNumberProvider()
19 | {
20 | return [
21 | ['925901618', true],
22 | ['GD001', true],
23 | ['HA500', true],
24 | ['434031493', false],
25 | ['12345', false],
26 | ['GD500', false],
27 | ['HA100', false],
28 | ['12345678', false],
29 | ];
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/Vies/ValidatorTest.php:
--------------------------------------------------------------------------------
1 | ['U10223006', ['U1022300', 'A10223006', 'U10223005']],
16 | 'BE' => ['0776091951', ['0776091952', '07760919']],
17 | 'BG' => [['204514061', '301004503'], ['10100450', '301004502']],
18 | 'CY' => ['00532445O', ['005324451', '0053244511', '12000139V', '72000139V']],
19 | 'CZ' => [
20 | ['46505334', '7103192745', '640903926', '395601439', '630903928', '27082440'],
21 | [
22 | '4650533', '96505334', '46505333', '7103192743', '1903192745', '7133192745',
23 | '395632439', '396301439', '545601439', '640903927', '7103322745'
24 | ]
25 | ],
26 | 'DE' => ['111111125', ['111111124', '1234567']],
27 | 'DK' => ['88146328', ['88146327', '1234567']],
28 | 'EE' => ['100207415', ['1002074', 'A12345678']],
29 | 'EL' => ['040127797', ['040127796', '1234567']],
30 | 'ES' => [['A0011012B', 'A78304516'], ['K0011012B', '12345678', 'K001A012B', 'A0011012C']],
31 | 'FI' => ['09853608', ['09853607', '1234567']],
32 | 'FR' => [
33 | ['00300076965', 'K7399859412', '4Z123456782'],
34 | ['0030007696A', '1234567890', 'K6399859412', 'KO399859412', 'IO399859412']
35 | ],
36 | 'GB' => [['434031494', 'GD001', 'HA500'], ['434031493', '12345', 'GD500', 'HA100', '12345678']],
37 | 'HR' => ['38192148118', ['3819214811', '1234567890A']],
38 | 'HU' => [['21376414', '10597190'], ['2137641', '1234567A']],
39 | 'IE' => [['8Z49289F', '3628739L', '5343381W', '6433435OA'], ['8Z49389F', '1234567', '6433435OB']],
40 | 'IT' => ['00000010215', ['00000010214', '1234567890', '00000001234']],
41 | 'LT' => [
42 | ['210061371310', '213179412', '290061371314', '208640716'],
43 | ['213179422', '21317941', '1234567890', '1234567890AB']
44 | ],
45 | 'LU' => ['10000356', ['10000355', '1234567']],
46 | 'LV' => ['40003009497', ['40013009497', '40003009496', '1234567890', '00212345678']],
47 | 'MT' => ['15121333', ['15121332', '1234567', '05121333']],
48 | 'NL' => [
49 | ['010000446B01', '000099998B57'],
50 | ['010000436B01', '12345678901', '123456789A12', '123456789B00', '0$0099998B57']],
51 | 'PL' => ['5260001246', ['12342678090', '1212121212']],
52 | 'PT' => ['502757191', ['502757192', '12345678']],
53 | 'RO' => [['11198699', '14186770'], ['11198698', '1', '12345678902']],
54 | 'SE' => ['556188840401', ['556188840400', '1234567890', '556181140401']],
55 | 'SI' => ['15012557', ['15012556', '12345670', '01234567', '1234567']],
56 | 'SK' => ['4030000007', ['4030000006', '123456789', '0123456789', '4060000007']]
57 | ];
58 | }
59 |
60 | public function testVatNumberChecksumSuccess()
61 | {
62 | $vies = new Vies();
63 |
64 | foreach ($this->vatNumberProvider() as $country => $numbers) {
65 | if (! is_array($numbers[0])) {
66 | $numbers[0] = [$numbers[0]];
67 | }
68 | foreach ($numbers[0] as $number) {
69 | $result = $vies->validateVatSum($country, $number);
70 | $this->assertTrue(
71 | $result,
72 | 'VAT ID ' . $country . $number . ' should validate, but is not valid'
73 | );
74 | }
75 | }
76 | }
77 |
78 | public function testVatNumberChecksumFailure()
79 | {
80 | $vies = new Vies();
81 |
82 | foreach ($this->vatNumberProvider() as $country => $numbers) {
83 | foreach ($numbers[1] as $number) {
84 | $result = $vies->validateVatSum($country, $number);
85 | $this->assertFalse($result);
86 | }
87 | }
88 | }
89 |
90 | public function traderDataProvider()
91 | {
92 | return [
93 | 'Belgian Trader Name' => [
94 | [
95 | 'countryCode' => 'BE',
96 | 'vatNumber' => '0203430576',
97 | 'requesterCountryCode' => 'BE',
98 | 'requesterVatNumber' => '0203430576',
99 | 'traderName' => 'B-Rail',
100 | 'traderCompanyType' => 'NV',
101 | 'traderStreet' => 'Frankrijkstraat 65',
102 | 'traderPostcode' => '1060',
103 | 'traderCity' => 'Sint-Gillis',
104 | ],
105 | ],
106 | 'German Trader Name' => [
107 | [
108 | 'countryCode' => 'DE',
109 | 'vatNumber' => '811569869',
110 | 'requesterCountryCode' => 'DE',
111 | 'requesterVatNumber' => '811569869',
112 | 'traderName' => 'Deutsche Bahn',
113 | 'traderCompanyType' => 'AG',
114 | 'traderStreet' => 'Potsdamer Platz 2',
115 | 'traderPostcode' => '10785',
116 | 'traderCity' => 'Berlin',
117 | ],
118 | ],
119 | 'Greek Trader Name' => [
120 | [
121 | 'countryCode' => 'EL',
122 | 'vatNumber' => '999645865',
123 | 'requesterCountryCode' => 'EL',
124 | 'requesterVatNumber' => '999645865',
125 | 'traderName' => 'ΤΡΑΙΝΟΣΕ',
126 | 'traderCompanyType' => 'AE',
127 | 'traderStreet' => 'ΚΑΡΟΛΟΥ 1-3',
128 | 'traderPostcode' => '10437',
129 | 'traderCity' => 'ΑΘΗΝΑ',
130 | ],
131 | ],
132 | 'Polish Trader Name' => [
133 | [
134 | 'countryCode' => 'PL',
135 | 'vatNumber' => '1132316427',
136 | 'requesterCountryCode' => 'PL',
137 | 'requesterVatNumber' => '1132316427',
138 | 'traderName' => 'PKP POLSKIE LINIE KOLEJOWE SPÓŁKA AKCYJNA',
139 | 'traderCompanyType' => '',
140 | 'traderStreet' => 'TARGOWA 74',
141 | 'traderPostcode' => '03-734',
142 | 'traderCity' => 'WARSZAWA',
143 | ],
144 | ],
145 | 'Ampesant Trader Name' => [
146 | [
147 | 'countryCode' => 'BE',
148 | 'vatNumber' => '0458591947',
149 | 'requesterCountryCode' => 'BE',
150 | 'requesterVatNumber' => '0458591947',
151 | 'traderName' => 'VAN AERDE & PARTNERS',
152 | 'traderCompanyType' => 'BVBA',
153 | 'traderStreet' => 'RIJSELSTRAAT 274',
154 | 'traderPostcode' => '8200',
155 | 'traderCity' => 'BRUGGE',
156 | ],
157 | ],
158 | 'Dot-dash Trader Name' => [
159 | [
160 | 'countryCode' => 'BE',
161 | 'vatNumber' => '0467609086',
162 | 'requesterCountryCode' => 'BE',
163 | 'requesterVatNumber' => '0467609086',
164 | 'traderName' => 'HAELTERMAN C.V.-KLIMA',
165 | 'traderCompanyType' => 'BVBA',
166 | 'traderStreet' => 'GERAARDSBERGSESTEENWEG 307',
167 | 'traderPostcode' => '9404',
168 | 'traderCity' => 'NINOVE',
169 | ],
170 | ],
171 | 'Accent Trader Name' => [
172 | [
173 | 'countryCode' => 'BE',
174 | 'vatNumber' => '0873284862',
175 | 'requesterCountryCode' => 'BE',
176 | 'requesterVatNumber' => '0873284862',
177 | 'traderName' => '\'t GERIEF',
178 | 'traderCompanyType' => 'CVBA',
179 | 'traderStreet' => 'LICHTAARTSEWEG(HRT) 22',
180 | 'traderPostcode' => '2200',
181 | 'traderCity' => 'HERENTALS',
182 | ],
183 | ],
184 | 'Plus Trader Name' => [
185 | [
186 | 'countryCode' => 'BE',
187 | 'vatNumber' => '0629758840',
188 | 'requesterCountryCode' => 'BE',
189 | 'requesterVatNumber' => '0629758840',
190 | 'traderName' => 'ARCHITECTUUR+',
191 | 'traderCompanyType' => 'BVBA',
192 | 'traderStreet' => 'STATIONSSTRAAT 28',
193 | 'traderPostcode' => '3930',
194 | 'traderCity' => 'HAMONT-ACHEL',
195 | ],
196 | ],
197 | ];
198 | }
199 |
200 | /**
201 | * Testing that arguments that contain non-latin values are still
202 | * validated correctly
203 | *
204 | * @group issue-99
205 | * @covers \DragonBe\Vies\Vies::validateVat
206 | * @covers \DragonBe\Vies\Vies::validateArgument
207 | * @dataProvider TraderDataProvider
208 | */
209 | public function testArgumentValidationSucceedsForNonLatinArgumentValues(array $traderData)
210 | {
211 | $vies = new Vies();
212 | try {
213 | $vatResponse = $vies->validateVat(
214 | $traderData['countryCode'],
215 | $traderData['vatNumber'],
216 | $traderData['requesterCountryCode'],
217 | $traderData['requesterVatNumber'],
218 | $traderData['traderName'],
219 | $traderData['traderCompanyType'],
220 | $traderData['traderStreet'],
221 | $traderData['traderPostcode'],
222 | $traderData['traderCity']
223 | );
224 | $this->assertTrue($vatResponse->isValid());
225 | } catch (ViesServiceException $viesServiceException) {
226 | $this->markTestSkipped('Service unavailable at the moment');
227 | }
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/tests/Vies/_files/checkVatService.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
3 | Specific disclaimer for this service ----------------------------------------- The
4 | objective of this Internet site is to allow persons involved in the intra-Community supply of
5 | goods or of services to obtain confirmation of the validity of the VAT identification number of
6 | any specified person, in accordance to article 27 of Council Regulation (EC) No. 1798/2003 of 7
7 | October 2003. Any other use and any extraction and use of the data which is not in conformity
8 | with the objective of this site is strictly forbidden. Any retransmission of the contents of
9 | this site, whether for a commercial purpose or otherwise, as well as any more general use other
10 | than as far as is necessary to support the activity of a legitimate user (for example: to draw
11 | up their own invoices) is expressly forbidden. In addition, any copying or reproduction of the
12 | contents of this site is strictly forbidden. The European Commission maintains this website to
13 | enhance the access by taxable persons making intra-Community supplies to verification of their
14 | customers VAT identification numbers. Our goal is to supply instantaneous and accurate
15 | information. However the Commission accepts no responsibility or liability whatsoever with
16 | regard to the information obtained using this site. This information: - is obtained from Member
17 | States databases over which the Commission services have no control and for which the Commission
18 | assumes no responsibility; it is the responsibility of the Member States to keep their databases
19 | complete, accurate and up to date; - is not professional or legal advice (if you need specific
20 | advice, you should always consult a suitably qualified professional); - does not in itself give
21 | a right to exempt intra-Community supplies from Value Added Tax; - does not change any
22 | obligations imposed on taxable persons in relation to intra-Community supplies. It is our goal
23 | to minimise disruption caused by technical errors. However some data or information on our site
24 | may have been created or structured in files or formats which are not error-free and we cannot
25 | guarantee that our service will not be interrupted or otherwise affected by such problems. The
26 | Commission accepts no responsibility with regard to such problems incurred as a result of using
27 | this site or any linked external sites. This disclaimer is not intended to limit the liability
28 | of the Commission in contravention of any requirements laid down in applicable national law nor
29 | to exclude its liability for matters which may not be excluded under that law. Usage: The
30 | countryCode input parameter must follow the pattern [A-Z]{2} The vatNumber input parameter must
31 | follow the [0-9A-Za-z\+\*\.]{2,12} In case of problem, the returned FaultString can take the
32 | following specific values: - INVALID_INPUT: The provided CountryCode is invalid or the VAT
33 | number is empty; - SERVICE_UNAVAILABLE: The SOAP service is unavailable, try again later; -
34 | MS_UNAVAILABLE: The Member State service is unavailable, try again later or with another Member
35 | State; - TIMEOUT: The Member State service could not be reach in time, try again later or with
36 | another Member State; - SERVER_BUSY: The service can't process your request. Try again latter.
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | VALID
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | INVALID
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
--------------------------------------------------------------------------------
/tests/Vies/_files/checkVatTestService.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Specific disclaimer for this service -----------------------------------------
5 | Here is the list of VAT Number to use to receive each kind of answer :
6 | 100 = Valid request with Valid VAT Number
7 | 200 = Valid request with an Invalid VAT Number
8 | 201 = Error : INVALID_INPUT
9 | 202 = Error : INVALID_REQUESTER_INFO
10 | 300 = Error : SERVICE_UNAVAILABLE
11 | 301 = Error : MS_UNAVAILABLE
12 | 302 = Error : TIMEOUT
13 | 400 = Error : VAT_BLOCKED
14 | 401 = Error : IP_BLOCKED
15 | 500 = Error : GLOBAL_MAX_CONCURRENT_REQ
16 | 501 = Error : GLOBAL_MAX_CONCURRENT_REQ_TIME
17 | 600 = Error : MS_MAX_CONCURRENT_REQ
18 | 601 = Error : MS_MAX_CONCURRENT_REQ_TIME
19 |
20 | For all the other cases, The web service will responds with a "SERVICE_UNAVAILABLE" error.
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | VALID
92 |
93 |
94 |
95 |
96 | INVALID
97 |
98 |
99 |
100 |
101 | NOT_PROCESSED
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
--------------------------------------------------------------------------------
/tests/Vies/_files/soapVersionCheck.code:
--------------------------------------------------------------------------------
1 | error_reporting(E_ALL|E_NOTICE|E_DEPRECATED);
2 | ini_set('display_errors', 1);
3 | return var_export([SOAP_1_1, SOAP_1_2], true);
--------------------------------------------------------------------------------