ADOBE COMMERCE

VAT Management in Adobe Commerce

Oleg Blinnikov

vat_management_in_adobe_commerce VAT Management in Adobe Commerce

During last years I worked quite a lot with different Commerce B2B projects, and every of them had a different requirements for taxation processes. One of the most important parts always was VAT management. And after answering same questions again and again I came up with a small overview how Adobe Commerce / Magento manage VAT.

What is VAT?

A value added tax identification number or VAT identification number is an identifier used in many countries, including the countries of the European Union, for value added tax purposes.

In the EU, a VAT identification number can be verified online at the EU's official VIES website. It confirms that the number is currently allocated and can provide the name or other identifying details of the entity to whom the identifier has been allocated. However, many national governments will not give out VAT identification numbers due to data protection laws.

(https://en.wikipedia.org/wiki/VAT_identification_number)

Why is it important to validate the Tax Number of customers before a transaction takes place?

When selling products or services, you need to issue an invoice and send it to your customer. In it, you need to specify if your customer is a business customer or an end consumer (consumer). This is because transactions with business customers (B2B) typically have a different tax treatment compared to transactions with consumers (B2C). Some transactions, like cross-border services to business customers, often do not incur indirect taxes at all.

In order to determine if you need to charge indirect taxes (like VAT) to your customers in cross-border situations, you need to check if you’re dealing with a business entity or with a private individual. For this, you need to check (“validate”) the tax identification number of your customer. (https://www.fonoa.com/blog/why-is-it-essential-to-validate-the-tax-number-of-your-customers-before-a-transaction-takes-place)

Doing this wrong means you either charge tax when you shouldn’t and add unnecessary costs to your product, or that you don’t charge tax when you should which means you are not collecting the tax you should but still need to remit to the tax authorities. Both obvious situations that any business wants to avoid.

That’s why it is important to verify if your customers are business customers or consumers. One simple way of checking your customer’s tax status is to validate if your customer is VAT registered in VIES.

What is VIES?

VIES (the VAT Information Exchange System) is an online system developed for this purpose by the European Commission. Through VIES, businesses can verify individual VAT numbers across the EU online quickly and in a simple way.

(https://www.fonoa.com/blog/what-is-vies)

VAT ID Validation in Magento

By default, Adobe Commerce uses the EU VIES service to validate VAT.

As any 3rd party service may happen, that API response time is slow or service is not available. But this is not influence general user experience. In this case validation will be marked as Failed and Admin can repeat it again later on.

VAT ID Validation automatically assigns one of the four default customer groups to customers according to VAT ID validation results:

You can create new customer groups for VAT ID Validation or use existing groups, if they comply with your business logic. When configuring VAT ID Validation, you must assign each of the created customer groups as a default for customers with appropriate VAT ID validation results. (https://docs.magento.com/user-guide/v2.3/tax/vat-validation-configure.html)

If VAT validation is enabled, this may affect the Order Placement time for different countries, because the response time from VIES varies from country to country.

There are 2 fields for the VAT ID in Magento. The first one is related to the customer entity, which won't be checked against the VAT validation service "VIES". It has only some information character, but it has no impact to the customer group assignment.

adobe_commerce_vat_settings Adobe Commerce VAT Settings

The second VAT ID field is related to the customer address entity, which will be checked against the VIES service. If the VAT ID is valid, customer is assigned to defined customer group (e.g. "Valid VAT ID").

adobe_commerce_vat_number Adobe Commerce VAT Number

VAT ID Format

The full identifier starts with an ISO 3166-1 alpha-2 (2 letters) country code (except for Greece, which uses the ISO 639-1 language code EL for the Greek language, instead of its ISO 3166-1 alpha-2 country code GR, and Northern Ireland, which uses the code XI when trading with the EU) and then has between 2 and 13 characters. The identifiers are composed of numeric digits in most countries, but in some countries they may contain letters.

Foreign companies that trade with private individuals and non-business organisations in the EU may have a VATIN starting with "EU" instead of a country code, e.g. Godaddy EU826010755 and Amazon (AWS) EU826009064.

If user enters VAT ID with dashes, Magento escapes dashes before it sends customer VAT number to the validation service. Magento also escapes country code from the VAT number if country is in EU. For example, if customer enters one of the following VAT:

After sanitizing, Magento will transform all of them to the following format before sending: 01234567. And all of them will be valid all in all.

vendor/magento/module-customer/Model/Vat.php:190
$vatNumberSanitized = $this->isCountryInEU($countryCode)
                 ? str_replace([' ', '-', $countryCodeForVatNumber], ['', '', ''], $vatNumber)
                 : str_replace([' ', '-'], ['', ''], $vatNumber);

Adobe Commerce (Magento) Code

The following method is the main extension point of the VAT ID validation:

vendor/magento/module-customer/Model/Vat.php:162
   /**
     * Send request to VAT validation service and return validation result
     *
     * @param string $countryCode
     * @param string $vatNumber
     * @param string $requesterCountryCode
     * @param string $requesterVatNumber
     *
     * @return DataObject
     */
    public function checkVatNumber($countryCode, $vatNumber, $requesterCountryCode = '', $requesterVatNumber = '')

Vat Validation URL for EU Vat numbers is stored as a constant:

vendor/magento/module-customer/Model/Vat.php:47
/**
 * WSDL of VAT validation service
 *
 */
const VAT_VALIDATION_WSDL_URL = 'https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl';

Theoretically this may lead to situation that URL will be changed some time in the future and service will not be active anymore. Also that is the first entry point, where you, as developer, have to start to check if service is available.

Main cases when VAT ID validation is performed:

vendor/magento/module-customer/Observer/AfterAddressSaveObserver.php:152
   /**
      * Address after save event handler
      *
      * @param Observer $observer
      * @return void
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function execute(Observer $observer)
     {
         ...
         $result = $this->_customerVat->checkVatNumber(
             $customerAddress->getCountryId(),
             $customerAddress->getVatId()
         );
         ...
     }
vendor/magento/module-quote/Observer/Frontend/Quote/Address/VatValidator.php:43
   /**
      * Validate VAT number
      *
      * @param \Magento\Quote\Model\Quote\Address $quoteAddress
      * @param \Magento\Store\Model\Store|int $store
      * @return \Magento\Framework\DataObject
      */
     public function validate(\Magento\Quote\Model\Quote\Address $quoteAddress, $store)

GraphQL

mutation {
   setBillingAddressOnCart(
     input: {
       cart_id: "{{cart_id}}"
       billing_address: {
         customer_address_id: {{address_id}}
         same_as_shipping: true
       }
     }
   ) {
     cart {
       billing_address {
         firstname
         lastname
         company
         street
         city
         region{
           code
           label
         }
         postcode
         telephone
         country {
           code
           label
         }
       }
     }
   }
 }

REST

/V1/guest-carts/:cartId/payment-information
   /**
     * Set payment information and place order for a specified cart.
     *
     * @param string $cartId
     * @param string $email
     * @param \Magento\Quote\Api\Data\PaymentInterface $paymentMethod
     * @param \Magento\Quote\Api\Data\AddressInterface|null $billingAddress
     * @throws \Magento\Framework\Exception\CouldNotSaveException
     * @return int Order ID.
     */
    public function savePaymentInformationAndPlaceOrder(
        $cartId,
        $email,
        \Magento\Quote\Api\Data\PaymentInterface $paymentMethod,
        \Magento\Quote\Api\Data\AddressInterface $billingAddress = null
    );

Conclusion

I really hope that I helped somebody in understanding how VAT validation process works. If you need a support in Magento configuration, then please follow this documentation: VAT ID Validation | Adobe Commerce 2.4 User Guide

Photo by Jon Tyson on Unsplash