gewebe / sylius-vat-plugin
VAT number address field with validation, EU VAT rates plugin for Sylius
Package info
github.com/gewebe/SyliusVATPlugin
Type:sylius-plugin
pkg:composer/gewebe/sylius-vat-plugin
Requires
- php: ^8.2
- ibericode/vat: ^2.1
- sylius/sylius: ^2.1
- symfony/http-client: ^6.4 || ^7.4
Requires (Dev)
- behat/behat: ^3.16
- dbrekelmans/bdi: ^1.4
- dmore/behat-chrome-extension: ^1.4
- dmore/chrome-mink-driver: ^2.9
- friends-of-behat/mink: ^1.11
- friends-of-behat/mink-browserkit-driver: ^1.6
- friends-of-behat/mink-debug-extension: ^2.1
- friends-of-behat/mink-extension: ^2.7
- friends-of-behat/page-object-extension: ^0.3
- friends-of-behat/suite-settings-extension: ^1.1
- friends-of-behat/symfony-extension: ^2.6
- friends-of-behat/variadic-extension: ^1.6
- nyholm/psr7: ^1.8
- phpstan/phpstan: ^1.12
- phpstan/phpstan-doctrine: ^1.3
- phpstan/phpstan-webmozart-assert: ^1.2
- phpunit/phpunit: ^10.5
- sylius-labs/coding-standard: ^4.4
- sylius-labs/suite-tags-extension: ~0.2
- sylius/sylius-rector: ^2.0
- sylius/test-application: ^2.0.0@alpha
- symfony/browser-kit: ^6.4 || ^7.4
- symfony/debug-bundle: ^6.4 || ^7.4
- symfony/dotenv: ^6.4 || ^7.4
- symfony/intl: ^6.4 || ^7.4
- symfony/runtime: ^6.4 || ^7.4
- symfony/web-profiler-bundle: ^6.4 || ^7.4
- symfony/webpack-encore-bundle: ^2.2
Suggests
- ext-soap: Needed to support VIES VAT number validation
Provides
None
Conflicts
None
Replaces
None
README
Features
- Installer for EU VAT rates with countries and zones
- New fields for VAT number at
AddressandShopBillingDataentity - Configure VAT number field requirement:
- Optional / Required
- Required if customer filled “Company” field
- Required in selected countries
- Validate VAT number:
- Revalidate customers VAT numbers after a given time
- Optionally show the VAT number validation status in the customer address book, checkout summary and order history
- Placing an order without VAT in the EU, if
- VAT number validation was successful
- Customers taxation country is different from shop billing country
Installation
Download the plugin via composer
composer require gewebe/sylius-vat-plugin
Enable the plugin in bundles.php
# config/bundles.php return [ # ... Gewebe\SyliusVATPlugin\GewebeSyliusVATPlugin::class => ['all' => true], ];
Import the plugin configurations
# config/packages/_sylius.yaml imports: # ... - { resource: '@GewebeSyliusVATPlugin/config/config.yaml'}
Configure taxation address
For EU VAT, the address for taxation should be set to the shipping address in the Sylius configuration.
# config/packages/_sylius.yaml sylius_core: shipping_address_based_taxation: true
Extend Address entity
# src/Entity/Addressing/Address.php namespace App\Entity\Addressing; use Doctrine\ORM\Mapping as ORM; use Gewebe\SyliusVATPlugin\Entity\VatNumberAddressInterface; use Gewebe\SyliusVATPlugin\Entity\VatNumberAwareTrait; use Sylius\Component\Core\Model\Address as BaseAddress; #[ORM\Entity] #[ORM\Table(name: 'sylius_address')] class Address extends BaseAddress implements VatNumberAddressInterface { use VatNumberAwareTrait;
If you use yaml mapping add also:
# config/doctrine/Address.orm.yaml App\Entity\Addressing\Address: type: entity table: sylius_address fields: vatNumber: type: string column: vat_number nullable: true vatValid: type: boolean column: vat_valid vatValidatedAt: type: datetime column: vat_validated_at nullable: true
Add or Extend ShopBillingData entity
# src/Entity/Channel/ShopBillingData.php namespace App\Entity\Channel; use Doctrine\ORM\Mapping as ORM; use Gewebe\SyliusVATPlugin\Entity\ShopBillingDataVatNumberAwareTrait; use Gewebe\SyliusVATPlugin\Entity\ShopBillingDataVatNumberInterface; use Sylius\Component\Core\Model\ShopBillingData as BaseShopBillingData; #[ORM\Entity] #[ORM\Table(name: 'sylius_shop_billing_data')] class ShopBillingData extends BaseShopBillingData implements ShopBillingDataVatNumberInterface { use ShopBillingDataVatNumberAwareTrait;
If you use yaml mapping add also:
# config/doctrine/ShopBillingData.orm.yaml App\Entity\Channel\ShopBillingData: type: entity table: sylius_shop_billing_data fields: vatNumber: type: string column: vat_number nullable: true
Override the resource for shop_billing_data in your sylius config:
# config/packages/_sylius.yaml sylius_core: resources: shop_billing_data: classes: model: App\Entity\Channel\ShopBillingData
Update your database schema
bin/console doctrine:migrations:diff bin/console doctrine:migrations:migrate
Usage
Install EU countries and VAT rates
# EU VAT on digital services (MOSS scheme) bin/console vat:install:eu # EU with French VAT (cross-border) bin/console vat:install:eu FR # EU with French VAT and passed threshold in Spain and Portugal (cross-border) bin/console vat:install:eu FR -t ES,PT # EU with French VAT included in price bin/console vat:install:eu FR -i # EU with German standard and reduced VAT categories bin/console vat:install:eu DE -c standard,reduced
Validate customers VAT number
1. Create new order with VAT number at shipping address
2. Show VAT number and validation status at admin orders
Show the validation status in the customer account and checkout
The address book and the address cards in the checkout summary and customer order history can display whether a VAT
number is valid, invalid, or not yet validated. The address book and checkout summary also show whether a validation
has expired according to revalidate.expiration_days, while the order history preserves the status at the time the
order was placed.
The display is disabled by default and can be enabled with:
# config/packages/_sylius.yaml gewebe_sylius_vat: customer_account: show_validation_status: true
VAT number normalization
VAT numbers are converted to uppercase and whitespace, dots and hyphens are removed before they are
stored or validated. For example, de 123.456-789 is stored as DE123456789.
Special EU VAT prefixes
Greek VAT numbers use the EL prefix even though the address country code is GR. The plugin
accepts this mapping for country and VIES registration validation.
Northern Ireland VAT numbers use the XI prefix (for example XI123456789). For an address in the
United Kingdom (GB), these numbers are validated through VIES and are treated as EU VAT numbers
when determining whether VAT can be removed from a cross-border order.
Validate UK VAT numbers with the HMRC API
VAT numbers of addresses in the United Kingdom (country code GB) are validated against the
HMRC "Check a UK VAT number" API
Version 2 of the API.
Configure the credentials and, optionally, the API base URL in the application config:
# config/packages/_sylius.yaml gewebe_sylius_vat: hmrc: base_url: 'https://api.service.hmrc.gov.uk' # https://test-api.service.hmrc.gov.uk for the sandbox client_id: '%env(HMRC_CLIENT_ID)%' client_secret: '%env(HMRC_CLIENT_SECRET)%'
Accepted UK VAT number formats are standard (GB123456789), branch traders (GB123456789001), government
departments (GBGD001) and health authorities (GBHA599); the GB prefix is optional.
Government department and health authority numbers cannot be looked up online and are therefore
only checked for their format.
Testing
Traditional
-
From the plugin skeleton root directory, run the following commands:
(cd vendor/sylius/test-application && yarn install) (cd vendor/sylius/test-application && yarn build) vendor/bin/console assets:install vendor/bin/console doctrine:database:create vendor/bin/console doctrine:migrations:migrate -n # Optionally load data fixtures vendor/bin/console sylius:fixtures:load -n
To be able to set up a plugin's database, remember to configure your database credentials in tests/TestApplication/.env and tests/TestApplication/.env.test.
-
Run your local server:
symfony server:ca:install symfony server:start -d
-
Open your browser and navigate to
https://localhost:8000.
Docker
-
Execute
make initto initialize the container and install the dependencies. -
Execute
make database-initto create the database and run migrations. -
(Optional) Execute
make load-fixturesto load the fixtures. -
Your app is available at
http://localhost.
Usage
Running plugin tests
-
PHPUnit
vendor/bin/phpunit
-
Behat (non-JS scenarios)
vendor/bin/behat --strict --tags="~@javascript&&~@mink:chromedriver" -
PHPStan - Static Analysis
vendor/bin/phpstan analyse -c phpstan.neon -l max src/
-
Coding Standard
vendor/bin/ecs check

