Skip to content

Commit

Permalink
Added services for verifying the validity of a VAT number.
Browse files Browse the repository at this point in the history
Αναζήτηση Βασικών Στοιχείων Μητρώου Επιχειρήσεων
- TaxisNet
- Vies

For more information please visit [our documentation](/docs/http/search-vat)
  • Loading branch information
firebed committed Feb 28, 2024
1 parent 55b21ac commit 3d4281b
Show file tree
Hide file tree
Showing 14 changed files with 561 additions and 13 deletions.
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"require": {
"php": "^8.1",
"ext-dom": "*",
"ext-soap": "*",
"guzzlehttp/guzzle": "^7.0.1"
},
"require-dev": {
Expand All @@ -28,7 +29,8 @@
"autoload": {
"psr-4": {
"Firebed\\AadeMyData\\": "src/"
}
},
"files": ["src/helpers.php"]
},
"autoload-dev": {
"psr-4": {
Expand Down
139 changes: 139 additions & 0 deletions docs/http/search-vat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Αναζήτηση Βασικών Στοιχείων Μητρώου Επιχειρήσεων

Με τη χρήση αυτής της υπηρεσίας, τα νομικά πρόσωπα, οι νομικές οντότητες,
και τα φυσικά πρόσωπα με εισόδημα από επιχειρηματική δραστηριότητα μπορούν
να αναζητήσουν βασικές πληροφορίες, προκειμένου να διακριβώσουν τη φορολογική
ή την επαγγελματική υπόσταση άλλων νομικών προσώπων ή νομικών οντοτήτων ή
φορολογουμένων/φυσικών προσώπων που ασκούν επιχειρηματική δραστηριότητα.

Το σύστημα παρέχει 2 τρόπους αναζήτησης βασικών στοιχείων μητρώου επιχειρήσεων:

- Μέσω της Υπηρεσίας Αναζήτησης Βασικών Στοιχείων Μητρώου Επιχειρήσεων
- Μέσω της Υπηρεσίας Vat Information Exchange System (VIES)

## Μέσω της Υπηρεσίας Αναζήτησης Βασικών Στοιχείων Μητρώου Επιχειρήσεων

Η υπηρεσία αυτή επιτρέπει την αναζήτηση όλων των Ελληνικών ΑΦΜ. Για την αναζήτηση
θα χρειαστείτε ένα `username` και ένα `password`.

Διαδικασία εγγραφής:

- Εγγραφή στην [υπηρεσία](https://www1.aade.gr/webtax/wspublicreg/faces/pages/wspublicreg/menu.xhtml) κάνοντας χρήση των κωδικών TAXISnet.
- Απόκτηση ειδικών κωδικών πρόσβασης μέσω της εφαρμογής [Διαχείριση Ειδικών Κωδικών](https://www1.aade.gr/sgsisapps/tokenservices/protected/displayConsole.htm).

Για περισσότερες λεπτομέρειες και για την εγγραφή επισκεφτείτε
την [Επίσημη Σελίδα του ΑΑΔΕ](https://www.aade.gr/anazitisi-basikon-stoiheion-mitrooy-epiheiriseon).

Μετά την εγγραφή, θα έχετε τα `username` και `password` που θα χρειαστείτε για την
χρήση της υπηρεσίας.

```php
use Firebed\AadeMyData\Services\Vat\TaxisNet;
use Firebed\AadeMyData\Services\Vat\VatException;

$username = 'your-username';
$password = 'your-password';

$taxis = new TaxisNet($username, $password);

try {
$response = $taxis->handle('094014201');

dd($response);
} catch (VatException $exception) {
echo "Σφάλμα: " . $exception->getMessage();
}
```

Το αποτέλεσμα της παραπάνω κλήσης:

```php
Firebed\AadeMyData\Services\Vat\VatEntity {
+vatNumber: "094014201"
+tax_authority_id: "1159"
+tax_authority_name: "ΦΑΕ ΑΘΗΝΩΝ"
+flag_description: "ΜΗ ΦΠ"
+valid: true
+validity_description: "ΕΝΕΡΓΟΣ ΑΦΜ"
+firm_flag_description: "ΕΠΙΤΗΔΕΥΜΑΤΙΑΣ"
+legalName: "ΤΡΑΠΕΖΑ ΕΘΝΙΚΗ ΤΗΣ ΕΛΛΑΔΟΣ ΑΝΩΝΥΜΗ ΕΤΑΙΡΕΙΑ"
+commerce_title: ""
+legal_status_description: "ΑΕ"
+street: "ΑΙΟΛΟΥ"
+street_number: "86"
+postcode: "10559"
+city: "ΑΘΗΝΑ"
+registration_date: "1900-01-01"
+stop_date: ""
+normal_vat: true
+firms: array:2 [
0 => array:4 [
"code" => "64191204"
"description" => "ΥΠΗΡΕΣΙΕΣ ΤΡΑΠΕΖΩΝ"
"kind" => "1"
"kind_description" => "ΚΥΡΙΑ"
]
1 => array:4 [
"code" => "66221001"
"description" => "ΥΠΗΡΕΣΙΕΣ ΑΣΦΑΛΙΣΤΙΚΟΥ ΠΡΑΚΤΟΡΑ ΚΑΙ ΑΣΦΑΛΙΣΤΙΚΟΥ ΣΥΜΒΟΥΛΟΥ"
"kind" => "2"
"kind_description" => "ΔΕΥΤΕΡΕΥΟΥΣΑ"
]
]
}
```

Σε περίπτωση που το ΑΦΜ δεν είναι έγκυρο επιστρέφεται τιμή `null`. Αν υπήρξε κάποιο άλλο πρόβλημα το `VatException` θα
περιέχει το σχετικό μήνυμα σφάλματος.

## Μέσω της Υπηρεσίας Vat Information Exchange System (VIES)

Με τη χρήση της Υπηρεσία VIES μπορείτε να επαληθεύσετε την εγκυρότητα του ΑΦΜ,
που χορηγείται απο οποιοδήποτε κράτος μέλος της Ευρωπαϊκής Ένωσης. Οι λεπτομέρειες
που παρέχει είναι πιο περιορισμένες σε σχέση με την υπηρεσία της ΑΑΔΕ.

Η Υπηρεσία παρέχεται δωρεάν χωρίς εγγραφή σε κάποιο φορέα. Δέχεται 2 παραμέτρους:
- Τον κωδικό της χώρας (π.χ. EL για Ελλάδα)
- Τον ΑΦΜ που θέλετε να επαληθεύσετε.

```php
use Firebed\AadeMyData\Services\Vat\VIES;
use Firebed\AadeMyData\Services\Vat\VatException;

$taxis = new VIES();

try {
$response = $taxis->handle('EL', '094014201');

dd($response);
} catch (VatException $exception) {
echo "Σφάλμα: " . $exception->getMessage();
}
```

Το αποτέλεσμα της παραπάνω κλήσης:

```php
Firebed\AadeMyData\Services\Vat\VatEntity {
+vatNumber: "094014201"
+tax_authority_id: null
+tax_authority_name: null
+flag_description: null
+valid: true
+validity_description: null
+firm_flag_description: null
+legalName: "ΤΡΑΠΕΖΑ ΕΘΝΙΚΗ ΤΗΣ ΕΛΛΑΔΟΣ ΑΝΩΝΥΜΗ ΕΤΑΙΡΕΙΑ"
+commerce_title: null
+legal_status_description: null
+street: "ΑΙΟΛΟΥ"
+street_number: "86"
+postcode: "10559"
+city: "ΑΘΗΝΑ"
+registration_date: null
+stop_date: null
+normal_vat: null
+firms: []
}
```

Σε περίπτωση που το ΑΦΜ δεν είναι έγκυρο, η υπηρεσία επιστρέφει `null`.
4 changes: 0 additions & 4 deletions docs/http/send-invoices.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ $doc->add(new Invoice())
$request = new SendInvoices();
$response = $request->handle($doc);

// Alternatively
$doc = new InvoicesDoc([new Invoice(), new Invoice()]);
$request = new SendInvoices();

try {
$response = $request->handle($doc);
} catch (MyDataException $e) {
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
| Εισαγωγή | Αναβάθμιση | upgrade-guide |
| Εισαγωγή | Σφάλματα | exceptions |
| Εισαγωγή | Contributing | contributing |
| Περιγραφή λειτουργιών | Αναζήτηση ΑΦΜ | http/search-vat |
| Περιγραφή λειτουργιών | SendInvoices | http/send-invoices |
| Περιγραφή λειτουργιών | CancelInvoice | http/cancel-invoice |
| Περιγραφή λειτουργιών | RequestDocs | http/request-docs |
Expand Down
6 changes: 2 additions & 4 deletions src/Http/MyDataRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use Psr\Http\Message\ResponseInterface;
use ReflectionClass;

abstract class MyDataRequest
{
Expand Down Expand Up @@ -180,9 +181,6 @@ private function getUrl(): string

private function getAction(): string
{
$action = get_class($this);
$action = substr($action, strrpos($action, '\\') + 1);

return $this->action ?? $action;
return $this->action ?? (new ReflectionClass($this))->getShortName();
}
}
15 changes: 15 additions & 0 deletions src/Http/Traits/HasRequestDom.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,19 @@ public function getRequestDom(): ?DOMDocument
{
return $this->requestDom;
}

public function getRequestXml(): ?string
{
return $this->requestDom?->saveXML();
}

public function getRequestElement(string $localName, int $index): ?string
{
if ($this->requestDom === null) {
return null;
}

$element = $this->requestDom->getElementsByTagName($localName)->item($index);
return $this->requestDom->saveXML($element);
}
}
15 changes: 15 additions & 0 deletions src/Http/Traits/HasResponseDom.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,19 @@ public function getResponseDom(): ?DOMDocument
{
return $this->responseDom;
}

public function getResponseXML(): ?string
{
return $this->responseDom?->saveXML();
}

public function getResponseElement(string $localName, int $index): ?string
{
if ($this->responseDom === null) {
return null;
}

$element = $this->responseDom->getElementsByTagName($localName)->item($index);
return $this->responseDom->saveXML($element);
}
}
4 changes: 3 additions & 1 deletion src/Models/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ protected function castValue(string $key, $value)
}

// Cast value to enum if it is not already an enum
// If the value doesn't correspond to an enum, it
// will return null.
if ($this->isEnum($key) && !is_object($value)) {
return $cast::from($value);
return $cast::tryFrom($value);
}

return $value;
Expand Down
131 changes: 131 additions & 0 deletions src/Services/Vat/TaxisNet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php

namespace Firebed\AadeMyData\Services\Vat;

use SoapClient;
use SoapFault;
use SoapHeader;
use stdClass;
use Throwable;

class TaxisNet
{
private const WSDL = 'https://www1.gsis.gr/wsaade/RgWsPublic2/RgWsPublic2?WSDL';
private const XSD = 'https://www1.gsis.gr/wsaade/RgWsPublic2/RgWsPublic2?xsd=1';

private string $username;
private string $password;

public function __construct(string $username, string $password)
{
$this->username = $username;
$this->password = $password;
}

/**
* @throws VatException
*/
public function handle(string $vatToSearch, string $vatCalledBy = null): ?VatEntity
{
if (blank($vatToSearch)) {
throw new VatException("Please provide a VAT number");
}

try {
$response = $this->request($vatToSearch, $vatCalledBy);

$error = $response->error_rec;
if (filled($error->error_code)) {
if ($error->error_code === "RG_WS_PUBLIC_WRONG_AFM") {
return null;
}

throw new VatException(trim($error->error_descr));
}

return $this->parseResponse($response);
} catch (Throwable $e) {
throw new VatException($e->getMessage());
}
}

/**
* @throws VatException|SoapFault
* @noinspection PhpUndefinedMethodInspection
*/
protected function request(string $vatToSearch, string $vatCalledBy = null)
{
$headers = $this->prepareHeaders($this->username, $this->password);

$client = new SoapClient(self::WSDL, ['soap_version' => SOAP_1_2]);
$client->__setSoapHeaders($headers);

$response = $client->rgWsPublic2AfmMethod([
'INPUT_REC' => [
'afm_called_by' => $vatCalledBy,
'afm_called_for' => $vatToSearch
]
]);

if (!isset($response->result->rg_ws_public2_result_rtType)) {
$this->invalidResponse();
}

return $response->result->rg_ws_public2_result_rtType;
}

/**
* @throws VatException
*/
protected function invalidResponse()
{
throw new VatException("Invalid response from TaxisNet");
}

protected function prepareHeaders(string $username, string $password): SoapHeader
{
$header = new stdClass();
$header->UsernameToken = new stdClass();
$header->UsernameToken->Username = $username;
$header->UsernameToken->Password = $password;

return new SoapHeader(self::XSD, 'Security', $header);
}

protected function parseResponse(object $data): VatEntity
{
$rec = $data->basic_rec;

$vat = new VatEntity();
$vat->vatNumber = trim($rec->afm);
$vat->tax_authority_id = trim($rec->doy);
$vat->tax_authority_name = trim($rec->doy_descr);
$vat->flag_description = trim($rec->i_ni_flag_descr);
$vat->valid = trim($rec->deactivation_flag) === "1";
$vat->validity_description = trim($rec->deactivation_flag_descr);
$vat->firm_flag_description = trim($rec->firm_flag_descr);
$vat->legalName = preg_replace('!\s+!', ' ', trim($rec->onomasia));
$vat->commerce_title = trim($rec->commer_title);
$vat->legal_status_description = trim($rec->legal_status_descr);
$vat->street = trim($rec->postal_address);
$vat->street_number = trim($rec->postal_address_no);
$vat->postcode = trim($rec->postal_zip_code);
$vat->city = trim($rec->postal_area_description);
$vat->registration_date = trim($rec->regist_date);
$vat->stop_date = trim($rec->stop_date);
$vat->normal_vat = trim($rec->normal_vat_system_flag) === 'Y';

$firms = wrapArray($data->firm_act_tab->item);

foreach ($firms as $firm) {
$vat->firms[] = [
'code' => trim($firm->firm_act_code),
'description' => trim($firm->firm_act_descr),
'kind' => trim($firm->firm_act_kind),
'kind_description' => trim($firm->firm_act_kind_descr),
];
}

return $vat;
}
}
Loading

0 comments on commit 3d4281b

Please sign in to comment.