spaze/vat-calculator

This package is abandoned and no longer maintained. The author suggests using the driesvints/vat-calculator package instead.

EU VAT calculation, the way it should be. Standalone & modernized fork of mpociot/vat-calculator, with some new features.

v4.0.4 2023-11-28 01:26 UTC

README

Software License PHP Tests

Caution

EOL, use:

Warning

There won't be any new releases, version 4.0.4 is the final one of this package

Important

This repository will be archived at the end of 2023. Thank you all!

Handle all the hard stuff related to EU MOSS tax/vat regulations, the way it should be. This is a "modernized" fork of mpociot/vat-calculator without Laravel/Cashier support, with some new features, that requires PHP 7.3+.

// Easy to use!
use Spaze\VatCalculator\VatCalculator;

$vatRates = new VatRates();
$vatCalculator = new VatCalculator($vatRates);
$vatCalculator->calculate(71.00, 'DE' /* $countryCode */, '41352' /* $postalCode or null */,  true /* Whether the customer you're calculating the VAT for is a company */);
$vatCalculator->getTaxRateForLocation('NL');
// Check validity of a VAT number
$vatCalculator->isValidVatNumber('NL123456789B01');

Contents

Installation

In order to install the VAT Calculator, just run

$ composer require spaze/vat-calculator

Standalone

This package is designed for standalone usage. Simply create a new instance of the VAT calculator and use it.

Example:

use Spaze\VatCalculator\VatCalculator;

$vatRates = new VatRates();
$vatCalculator = new VatCalculator($vatRates);
$vatCalculator->setBusinessCountryCode('DE');  // Where your company is based in
$price = $vatCalculator->calculate(49.99, 'LU', null, false);
$price->getPrice();
$price->getNetPrice();
$price->getTaxValue();
$price->getTaxRate();

Usage

Calculate the gross price

To calculate the gross price (price with VAT added) use the calculate method with a net price, a country code, a postal code (null if unknown) and whether you're calculating VAT for a customer that's a company as parameters.

$grossPrice = $vatCalculator->calculate(24.00, 'DE', null, false /* [, $rateType [, $dateTime]] */);

The third parameter is the postal code of the customer, pass null if unknown.

As a fourth parameter, you can pass in a boolean indicating whether the customer is a company or a private person. If the customer is a company, which you should check by validating the VAT number, the net price gets returned.

Fifth optional parameter defines which VAT rate to use if there are more defined for the particular country (VatRates::HIGH, VatRates::LOW, VatRates::GENERAL is the default when just one rate is defined).

The sixth parameter, optional, specifies the date to use the VAT rate for. This is needed when a country changes its VAT rate and you want to calculate a price with the previous rate. Pass DateTime or DateTimeImmutable object. Current date used when not specified.

Returns VatPrice object:

$grossPrice->getPrice();
$grossPrice->getNetPrice();
$grossPrice->getTaxValue();
$grossPrice->getTaxRate();

Validate EU VAT numbers

Prior to validating your customers VAT numbers, you can use the shouldCollectVat method to check if the country code requires you to collect VAT in the first place. This method will return true even for non-EU countries added manually with addRateForCountry (see below).

To ignore those manually added non-EU countries and return true only for EU member states, you can use shouldCollectEuVat.

if ($vatCalculator->shouldCollectVat('DE')) {

}

if ($vatCalculator->shouldCollectEuVat('DE')) {

}

To validate your customers VAT numbers, you can use the isValidVatNumber method. The VAT number should be in a format specified by the VIES. The given VAT numbers will be truncated and non relevant characters (-, ., ,, whitespace) will automatically be removed. If there are any invalid characters left, like non-latin letters for example, InvalidCharsInVatNumberException will be thrown.

This service relies on a third party SOAP API provided by the EU. If, for whatever reason, this API is unavailable a VatCheckUnavailableException will be thrown.

If a VAT number from an unsupported/non-EU country is provided, UnsupportedCountryException will be thrown.

try {
	$validVat = $vatCalculator->isValidVatNumber('NL 123456789 B01');
} catch (VatCheckUnavailableException $e) {
	// Please handle me
}

Get EU VAT number details

To get the details of a VAT number, you can use the getVatDetails method. The VAT number should be in a format specified by the VIES. The given VAT numbers will be truncated and non relevant characters / whitespace will automatically be removed.

This service relies on a third party SOAP API provided by the EU. If, for whatever reason, this API is unavailable a VatCheckUnavailableException will be thrown.

If a VAT number from an unsupported/non-EU country is provided, UnsupportedCountryException will be thrown.

try {
	$vat_details = $vatCalculator->getVatDetails('NL 123456789 B01');
	print_r($vat_details);
	/* Outputs VatDetails object, use getters to access values
	VatDetails Object
	(
		[valid:VatDetails:private] => false
		[countryCode:VatDetails:private] => NL
		[vatNumber:VatDetails:private] => 123456789B01
		[requestId:VatDetails:private] => FOOBAR338
	)
	*/
} catch (VatCheckUnavailableException $e) {
	// Please handle me
}

Get all known rates for a country

Get all known rates (current, high & low, historical & future, exceptions) for a country by:

$vatRates = new VatRates();
$vatRates->getAllKnownRates('DE');

The returned array of rates is unsorted. This method can be useful when you want to prefill a selectbox with known VAT rates for a country for example, or when you want to validate user-provided rates.

Countries

EU countries are supported as well as some non-EU countries that use VAT. Some countries are not supported even though they also have VAT. Currently, that's the case for the following countries:

  • Switzerland (CH)
  • United Kingdom (GB)
  • Norway (NO)
  • Turkey (TR)

These can be added manually with VatRates::addRateForCountry():

$vatRates = new VatRates();
$vatRates->addRateForCountry('NO');
$vatCalculator = new VatCalculator($vatRates);

Please keep in mind that with these countries you cannot validate VAT ids with isValidVatNumber() because it uses VIES, the EU VAT number validation service, and as these countries are not part of the EU, it will always come back as invalid.

License

This library is licensed under the MIT license. Please see License file for more information.

Contributing

Run PHPUnit tests and static analysis with composer test, see scripts in composer.json. Tests are also run on GitHub with Actions on each push.