Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
50.85% covered (warning)
50.85%
60 / 118
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
EUVATVies
50.85% covered (warning)
50.85%
60 / 118
0.00% covered (danger)
0.00%
0 / 3
199.57
0.00% covered (danger)
0.00%
0 / 1
 __construct
n/a
0 / 0
n/a
0 / 0
1
 validate
86.21% covered (warning)
86.21%
25 / 29
0.00% covered (danger)
0.00%
0 / 1
6.09
 validateQualified
43.55% covered (danger)
43.55%
27 / 62
0.00% covered (danger)
0.00%
0 / 1
100.34
 parseResponse
29.63% covered (danger)
29.63%
8 / 27
0.00% covered (danger)
0.00%
0 / 1
37.23
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Api\EUVAT
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Api\EUVAT;
16
17use phpOMS\Message\Http\HttpRequest;
18use phpOMS\Message\Http\RequestMethod;
19use phpOMS\Message\Http\Rest;
20use phpOMS\Uri\HttpUri;
21
22/**
23 * Check EU VAT.
24 *
25 * @package phpOMS\Api\EUVAT
26 * @license OMS License 2.0
27 * @link    https://jingga.app
28 * @since   1.0.0
29 */
30final class EUVATVies implements EUVATInterface
31{
32    /**
33     * Constructor.
34     *
35     * @since 1.0.0
36     * @codeCoverageIgnore
37     */
38    private function __construct()
39    {
40    }
41
42    /**
43     * {@inheritdoc}
44     */
45    public static function validate(string $otherVAT, string $ownVAT = '') : array
46    {
47        $result = [
48            'status'  => -1,
49            'vat'     => 'B',
50            'name'    => '',
51            'city'    => '',
52            'postal'  => '',
53            'address' => '',
54            'body'    => '',
55        ];
56
57        if (empty($otherVAT)) {
58            return $result;
59        }
60
61        $request = new HttpRequest(
62            new HttpUri(
63                'https://ec.europa.eu/taxation_customs/vies/rest-api/ms/' . \substr($otherVAT, 0, 2) . '/vat/' . \substr($otherVAT, 2) . (
64                    $ownVAT !== '' ? '?requesterMemberStateCode=' . \substr($ownVAT, 0, 2) . '&requesterNumber=' . \substr($ownVAT, 2) : ''
65                )
66            )
67        );
68        $request->setMethod(RequestMethod::GET);
69
70        try {
71            $body           = Rest::request($request)->getBody();
72            $result['body'] = $body;
73
74            /** @var array $json */
75            $json = \json_decode($body, true);
76            if ($json === false) {
77                return $result;
78            }
79
80            $result = \array_merge($result, self::parseResponse($json));
81
82            $result['status'] = $json['userError'] === 'VALID' ? 0 : -1;
83        } catch (\Throwable $_) {
84            return $result;
85        }
86
87        return $result;
88    }
89
90    /**
91     * {@inheritdoc}
92     */
93    public static function validateQualified(
94        string $otherVAT,
95        string $ownVAT,
96        string $otherName,
97        string $otherCity,
98        string $otherPostal,
99        string $otherStreet
100    ) : array
101    {
102        $result = [
103            'status'  => -1,
104            'vat'     => 'B',
105            'name'    => 'C',
106            'city'    => 'C',
107            'postal'  => 'C',
108            'address' => 'C',
109            'body'    => '',
110        ];
111
112        if (empty($otherVAT)) {
113            return $result;
114        }
115
116        $request = new HttpRequest(
117            new HttpUri(
118                'https://ec.europa.eu/taxation_customs/vies/rest-api/ms/' . \substr($otherVAT, 0, 2) . '/vat/' . \substr($otherVAT, 2) . (
119                    $ownVAT !== ''
120                        ? '?requesterMemberStateCode=' . \substr($ownVAT, 0, 2) . '&requesterNumber=' . \substr($ownVAT, 2)
121                        : ''
122                )
123            )
124        );
125        $request->setMethod(RequestMethod::GET);
126
127        try {
128            $body           = Rest::request($request)->getBody();
129            $result['body'] = $body;
130
131            /** @var array $json */
132            $json = \json_decode($body, true);
133            if ($json === false) {
134                return $result;
135            }
136
137            $result = \array_merge($result, self::parseResponse($json));
138
139            if ($otherName === '') {
140                $result['name'] = 'C';
141            } elseif ((\stripos($result['name'], $otherName) !== false
142                    && \strlen($otherName) / \strlen($result['name']) > 0.8)
143                || \levenshtein($otherName, $result['name']) / \strlen($result['name']) < 0.2
144            ) {
145                $result['name'] = 'A';
146            } elseif ($result['name'] === '') {
147                $result['name'] = 'C';
148            } else {
149                $result['name'] = 'B';
150            }
151
152            if ($otherCity === '') {
153                $result['city'] = 'D';
154            } elseif (\stripos($result['city'], $otherCity) !== false) {
155                $result['city'] = 'A';
156            } elseif ($result['city'] === '') {
157                $result['city'] = 'C';
158            } else {
159                $result['city'] = 'B';
160            }
161
162            if ($otherPostal === '') {
163                $result['postal'] = 'D';
164            } elseif (\stripos($result['postal'], $otherPostal) !== false) {
165                $result['postal'] = 'A';
166            } elseif ($result['postal'] === '') {
167                $result['postal'] = 'C';
168            } else {
169                $result['postal'] = 'B';
170            }
171
172            if ($otherStreet === '') {
173                $result['address'] = 'D';
174            } elseif (\stripos($result['address'], $otherStreet) !== false
175                && \levenshtein($otherStreet, $result['address'], 0) / \strlen($result['address']) < 0.2
176            ) {
177                $result['address'] = 'A';
178            } elseif ($result['address'] === '') {
179                $result['address'] = 'C';
180            } else {
181                $result['address'] = 'B';
182            }
183
184            $result['status'] = $json['userError'] === 'VALID' ? 0 : -1;
185        } catch (\Throwable $_) {
186            return $result;
187        }
188
189        return $result;
190    }
191
192    /**
193     * Parse response.
194     *
195     * @param array $json JSON response
196     *
197     * @return array
198     *
199     * @since 1.0.0
200     */
201    private static function parseResponse(array $json) : array
202    {
203        $result = [
204            'vat'     => '',
205            'name'    => '',
206            'city'    => '',
207            'postal'  => '',
208            'address' => '',
209        ];
210
211        $result['vat']  = $json['isValid'] ? 'A' : 'B';
212        $result['name'] = $json['isValid'];
213
214        $result['city'] = \stripos($json['address'], "\n") !== false
215            ? \substr($json['address'], \stripos($json['address'], "\n") + 1)
216            : '';
217
218        $result['postal'] = \stripos($json['address'], "\n") !== false
219            ? \substr(
220                $json['address'],
221                \stripos($json['address'], "\n") + 1,
222                \stripos($json['address'], ' ', \stripos($json['address'], "\n")) - \stripos($json['address'], "\n") - 1
223            )
224            : '';
225
226        $result['address'] = \stripos($json['address'], "\n") !== false
227            ? \substr($json['address'], 0, \stripos($json['address'], "\n") - 1)
228            : $json['address'];
229
230        $result['name']    = $result['name'] === '---' ? '' : $result['name'];
231        $result['city']    = $result['city'] === '---' ? '' : $result['city'];
232        $result['postal']  = $result['postal'] === '---' ? '' : $result['postal'];
233        $result['address'] = $result['address'] === '---' ? '' : $result['address'];
234
235        return $result;
236    }
237}