You are here

class EuropeanUnionVat in Commerce Core 8.2

Same name in this branch
  1. 8.2 modules/tax/src/Plugin/Commerce/TaxType/EuropeanUnionVat.php \Drupal\commerce_tax\Plugin\Commerce\TaxType\EuropeanUnionVat
  2. 8.2 modules/tax/src/Plugin/Commerce/TaxNumberType/EuropeanUnionVat.php \Drupal\commerce_tax\Plugin\Commerce\TaxNumberType\EuropeanUnionVat

Provides the European Union VAT tax number type.

Note that in addition to EU members, the country list also includes Isle of Man (IM), which uses GB VAT, and Monaco (MC), which uses FR VAT.

Plugin annotation


@CommerceTaxNumberType(
  id = "european_union_vat",
  label = "European Union VAT",
  countries = {
    "EU",
    "AT", "BE", "BG", "CY", "CZ", "DE", "DK", "EE", "ES", "FI",
    "FR", "GR", "HR", "HU", "IE", "IM", "IT", "LT", "LU",
    "LV", "MC", "MT", "NL", "PL", "PT", "RO", "SE", "SI", "SK",
  },
  examples = {"DE123456789", "HU12345678"}
)

Hierarchy

Expanded class hierarchy of EuropeanUnionVat

1 file declares its use of EuropeanUnionVat
EuropeanUnionVatTest.php in modules/tax/tests/src/Kernel/Plugin/Commerce/TaxNumberType/EuropeanUnionVatTest.php

File

modules/tax/src/Plugin/Commerce/TaxNumberType/EuropeanUnionVat.php, line 23

Namespace

Drupal\commerce_tax\Plugin\Commerce\TaxNumberType
View source
class EuropeanUnionVat extends TaxNumberTypeWithVerificationBase {

  /**
   * The SOAP client for VIES (VAT Information Exchange System).
   *
   * @var \SoapClient
   */
  protected $soapClient;

  /**
   * {@inheritdoc}
   */
  public function validate($tax_number) {
    $patterns = $this
      ->getValidationPatterns();
    $prefix = substr($tax_number, 0, 2);
    if (!isset($patterns[$prefix])) {
      return FALSE;
    }
    $number = substr($tax_number, 2);
    if (!preg_match('/^' . $patterns[$prefix] . '$/', $number)) {
      return FALSE;
    }
    return TRUE;
  }

  /**
   * {@inheritdoc}
   */
  protected function doVerify($tax_number) {
    $time = $this->time
      ->getRequestTime();

    // The SOAP extension is not a Commerce requirement, since only this
    // plugin needs it. The check is skipped in test environments because
    // a mock client will be used instead.
    if (!extension_loaded('soap') && !drupal_valid_test_ua()) {
      return VerificationResult::failure($time, [
        'error' => 'no_extension',
      ]);
    }
    $patterns = $this
      ->getValidationPatterns();
    $prefix = substr($tax_number, 0, 2);
    if (!isset($patterns[$prefix])) {
      return VerificationResult::failure($time, [
        'error' => 'invalid_number',
      ]);
    }
    $number = substr($tax_number, 2);
    try {
      $parameters = [
        'countryCode' => $prefix,
        'vatNumber' => $number,
      ];
      $soap_client = $this
        ->getSoapClient();
      $result = $soap_client
        ->__soapCall('checkVat', [
        $parameters,
      ]);
    } catch (\SoapFault $e) {
      return VerificationResult::unknown($time, [
        'error' => $e->faultstring,
      ]);
    }
    if ($result->valid) {
      return VerificationResult::success($time, [
        'name' => $result->name,
        'address' => $result->address,
      ]);
    }
    else {
      return VerificationResult::failure($time);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function renderVerificationResult(VerificationResult $result) {
    $errors = [
      // Plugin errors.
      'no_extension' => $this
        ->t('The SOAP PHP extension is missing from the server.'),
      'invalid_number' => $this
        ->t('The tax number is not in the right format.'),
      // VIES errors, as defined in the WSDL.
      'INVALID_INPUT' => $this
        ->t('The tax number is not in the right format.'),
      'GLOBAL_MAX_CONCURRENT_REQ' => $this
        ->t('The remote service is temporarily busy. Error code: GLOBAL_MAX_CONCURRENT_REQ.'),
      'MS_MAX_CONCURRENT_REQ' => $this
        ->t('The remote service is temporarily busy. Error code: MS_MAX_CONCURRENT_REQ.'),
      'SERVICE_UNAVAILABLE' => $this
        ->t('The remote service is temporarily unavailable. Error code: SERVICE_UNAVAILABLE.'),
      'MS_UNAVAILABLE' => $this
        ->t('The remote service is temporarily unavailable. Error code: MS_UNAVAILABLE.'),
      'TIMEOUT' => $this
        ->t('The remote service did not reply within the allocated time period.'),
    ];
    $data = $result
      ->getData();
    $element = [];
    if (isset($data['error'])) {
      $error = $data['error'];
      $element['error'] = [
        '#type' => 'item',
        '#title' => $this
          ->t('Error'),
        '#plain_text' => isset($errors[$error]) ? $errors[$error] : $error,
      ];
    }
    if (isset($data['name'])) {
      $element['name'] = [
        '#type' => 'item',
        '#title' => $this
          ->t('Name'),
        '#plain_text' => $data['name'],
      ];
    }
    if (isset($data['address'])) {
      $element['address'] = [
        '#type' => 'item',
        '#title' => $this
          ->t('Address'),
        '#plain_text' => $data['address'],
      ];
    }
    return $element;
  }

  /**
   * Gets the validation patterns.
   *
   * Source: http://ec.europa.eu/taxation_customs/vies/faq.html#item_11
   *
   * @return array
   *   The validation patterns, keyed by prefix.
   *   The prefix is an ISO country code, except for Greece (EL instead of GR).
   */
  protected function getValidationPatterns() {
    $patterns = [
      'AT' => 'U[A-Z\\d]{8}',
      'BE' => '(0\\d{9}|\\d{10})',
      'BG' => '\\d{9,10}',
      'CY' => '\\d{8}[A-Z]',
      'CZ' => '\\d{8,10}',
      'DE' => '\\d{9}',
      'DK' => '\\d{8}',
      'EE' => '\\d{9}',
      'EL' => '\\d{9}',
      'ES' => '[A-Z]\\d{7}[A-Z]|\\d{8}[A-Z]|[A-Z]\\d{8}',
      'FI' => '\\d{8}',
      'FR' => '[0-9A-Z]{2}\\d{9}',
      'HR' => '\\d{11}',
      'HU' => '\\d{8}',
      'IE' => '[A-Z\\d]{8}|[A-Z\\d]{9}',
      'IT' => '\\d{11}',
      'LT' => '(\\d{9}|\\d{12})',
      'LU' => '\\d{8}',
      'LV' => '\\d{11}',
      'MT' => '\\d{8}',
      'NL' => '\\d{9}B\\d{2}',
      'PL' => '\\d{10}',
      'PT' => '\\d{9}',
      'RO' => '\\d{2,10}',
      'SE' => '\\d{12}',
      'SI' => '\\d{8}',
      'SK' => '\\d{10}',
    ];
    return $patterns;
  }

  /**
   * Gets the SOAP client for VIES.
   *
   * @return \SoapClient
   *   The SOAP client.
   */
  protected function getSoapClient() {
    if (!$this->soapClient) {
      ini_set('default_socket_timeout', 10);
      $wsdl = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl';
      $this->soapClient = new \SoapClient($wsdl, [
        'exceptions' => TRUE,
      ]);
    }
    return $this->soapClient;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
EuropeanUnionVat::$soapClient protected property The SOAP client for VIES (VAT Information Exchange System).
EuropeanUnionVat::doVerify protected function Performs the tax number verification. Overrides TaxNumberTypeWithVerificationBase::doVerify
EuropeanUnionVat::getSoapClient protected function Gets the SOAP client for VIES.
EuropeanUnionVat::getValidationPatterns protected function Gets the validation patterns.
EuropeanUnionVat::renderVerificationResult public function Renders the given verification result. Overrides SupportsVerificationInterface::renderVerificationResult
EuropeanUnionVat::validate public function Validates the given tax number. Overrides TaxNumberTypeInterface::validate
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::isConfigurable public function Determines if the plugin is configurable.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
TaxNumberTypeBase::canonicalize public function Canonicalizes the given tax number. Overrides TaxNumberTypeInterface::canonicalize
TaxNumberTypeBase::getCountries public function Gets the supported countries. Overrides TaxNumberTypeInterface::getCountries
TaxNumberTypeBase::getExamples public function Gets the tax number examples. Overrides TaxNumberTypeInterface::getExamples
TaxNumberTypeBase::getFormattedExamples public function Gets the tax number examples, formatted for display. Overrides TaxNumberTypeInterface::getFormattedExamples
TaxNumberTypeBase::getLabel public function Gets the tax number type label. Overrides TaxNumberTypeInterface::getLabel
TaxNumberTypeWithVerificationBase::$memoryCache protected property The memory cache.
TaxNumberTypeWithVerificationBase::$time protected property The time.
TaxNumberTypeWithVerificationBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create
TaxNumberTypeWithVerificationBase::verify public function Verifies the given tax number. Overrides SupportsVerificationInterface::verify
TaxNumberTypeWithVerificationBase::__construct public function Constructs a new TaxNumberTypeWithVerificationBase object. Overrides PluginBase::__construct