Handle all the hard stuff related to EU MOSS tax/vat regulations, the way it should be.

Overview

VatCalculator

Tests Code Style Latest Stable Version Total Downloads

Handle all the hard stuff related to EU MOSS tax/vat regulations, the way it should be. Integrates with Laravel and Cashier — or in a standalone PHP application. Originally created by Marcel Pociot.

// Easy to use!
VatCalculator::calculate(24.00, $countryCode = 'DE');
VatCalculator::calculate(24.00, $countryCode, $postalCode);
VatCalculator::calculate(71.00, 'DE', '41352', $isCompany = true);
VatCalculator::getTaxRateForLocation('NL');

// Check validity of a VAT number
VatCalculator::isValidVATNumber('NL123456789B01');

Requirements

  • PHP 7.3 or higher
  • (optional) Laravel 6.0 or higher

Installation

Install the package with composer:

composer require mpociot/vat-calculator

Standalone

You can also use this package without Laravel. Simply create a new instance of the VatCalculator and use it. All documentation examples use the Laravel Facade code, so make sure not to call the methods as if they were static methods.

use Mpociot\VatCalculator\VatCalculator;

$vatCalculator = new VatCalculator();
$vatCalculator->setBusinessCountryCode('DE');
$grossPrice = $vatCalculator->calculate(49.99, $countryCode = 'LU');

Upgrading

Please refer to the upgrade guide when upgrading the library.

Usage

Calculate the gross price

To calculate the gross price use the calculate method with a net price and a country code as parameters.

$grossPrice = VatCalculator::calculate(24.00, 'DE');

The third parameter is the postal code of the customer.

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.

$grossPrice = VatCalculator::calculate(24.00, 'DE', '12345', $isCompany = true);

Receive more information

After calculating the gross price you can extract more information from the VatCalculator.

$grossPrice = VatCalculator::calculate(24.00, 'DE'); // 28.56
$taxRate = VatCalculator::getTaxRate(); // 0.19
$netPrice = VatCalculator::getNetPrice(); // 24.00
$taxValue = VatCalculator::getTaxValue(); // 4.56

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.

if (VatCalculator::shouldCollectVAT('DE')) {
    // This country code requires VAT collection...
}

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.

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.

try {
    $validVAT = VatCalculator::isValidVATNumber('NL 123456789 B01');
} catch (VATCheckUnavailableException $e) {
    // The VAT check API is unavailable...
}

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.

try {
    $vat_details = VatCalculator::getVATDetails('NL 123456789 B01');
    print_r($vat_details);
    /* Outputs
    stdClass Object
    (
        [countryCode] => NL
        [vatNumber] => 123456789B01
        [requestDate] => 2017-04-06+02:00
        [valid] => false
        [name] => Name of the company
        [address] => Address of the company
    )
    */
} catch (VATCheckUnavailableException $e) {
    // The VAT check API is unavailable...
}

UK VAT Numbers

UK VAT numbers are formatted a little differently:

string(26) "Credite Sberger Donal Inc." ["vatNumber"]=> string(9) "553557881" ["address"]=> array(3) { ["line1"]=> string(18) "131B Barton Hamlet" ["postcode"]=> string(8) "SW97 5CK" ["countryCode"]=> string(2) "GB" } } */ } catch (VATCheckUnavailableException $e) { // The VAT check API is unavailable... } ">
try {
    $vat_details = VatCalculator::getVATDetails('GB 553557881');
    print_r($vat_details);
    /* Outputs
    array(3) {
        ["name"]=>
            string(26) "Credite Sberger Donal Inc."
        ["vatNumber"]=>
            string(9) "553557881"
        ["address"]=>
            array(3) {
                ["line1"]=>
                    string(18) "131B Barton Hamlet"
                ["postcode"]=>
                    string(8) "SW97 5CK"
                ["countryCode"]=>
                    string(2) "GB"
            }
    }
    */
} catch (VATCheckUnavailableException $e) {
    // The VAT check API is unavailable...
}

Laravel

Configuration

By default, the VatCalculator has all EU VAT rules predefined, so that it can easily be updated, if it changes for a specific country.

If you need to define other VAT rates, you can do so by publishing the configuration and add more rules.

⚠️ Be sure to set your business country code in the configuration file, to get correct VAT calculation when selling to business customers in your own country.

To publish the configuration files, run the vendor:publish command

php artisan vendor:publish --provider="Mpociot\VatCalculator\VatCalculatorServiceProvider"

This will create a vat_calculator.php in your config directory.

ValidVatNumber Validation Rule

VatCalculator also ships with a ValidVatNumber validation rule for VAT Numbers. You can use this when validation input from a form request or a standalone validator instance:

use Mpociot\VatCalculator\Rules\ValidVatNumber;

$validator = Validator::make(Input::all(), [
    'first_name' => 'required',
    'last_name' => 'required',
    'company_vat' => ['required', new ValidVatNumber],
]);

if ($validator->passes()) {
    // Input is correct...
}

⚠️ The validator extension returns false when the VAT ID Check SOAP API is unavailable.

Cashier Stripe Integration

⚠️ Note that at the moment this package is not compatible with Cashier Stripe v13 because it still relies on the old taxPercentage method which has been removed from Cashier v13. You can still use it on older Cashier Stripe versions in the meantime.

If you want to use this package in combination with Laravel Cashier Stripe you can let your billable model use the BillableWithinTheEU trait. Because this trait overrides the taxPercentage method of the Billable trait, we have to explicitly tell our model to do so.

use Laravel\Cashier\Billable;
use Mpociot\VatCalculator\Traits\BillableWithinTheEU;
use Laravel\Cashier\Contracts\Billable as BillableContract;

class User extends Model implements BillableContract
{
    use Billable, BillableWithinTheEU {
        BillableWithinTheEU::taxPercentage insteadof Billable;
    }

    protected $dates = ['trial_ends_at', 'subscription_ends_at'];
}

By using the BillableWithinTheEU trait, your billable model has new methods to set the tax rate for the billable model.

Set everything in one command:

  • setTaxForCountry($countryCode, $company = false)

Or use the more readable, chainable approach:

  • useTaxFrom($countryCode) — Use the given countries tax rate
  • asIndividual() — The billable model is not a company (default)
  • asBusiness() — The billable model is a valid company

So in order to set the correct tax percentage prior to subscribing your customer, consider the following workflow:

$user = User::find(1);

// For individuals use:
$user->useTaxFrom('NL');

// For business customers with a valid VAT ID, use:
$user->useTaxFrom('NL')->asBusiness();

$user->subscription('monthly')->create($creditCardToken);

Changelog

Check out the CHANGELOG in this repository for all the recent changes.

Maintainers

VatCalculator is maintained by Dries Vints. Originally created by Marcel Pociot.

License

VatCalculator is open-sourced software licensed under the MIT license.

Comments
  • Incorrect handling of Norway?

    Incorrect handling of Norway?

    Hi,

    Thanks for your great vat-calculator, we use it as part of spark.laravel.com. And now run into an issue with a customer from Norway (outside EU) and we are in The Netherlands (within EU). The customer is being charged VAT but says that he shouldn't. And as far as I can see he's correct, regardless if he's a business or individual. Does this need to be changed in the code?

    Thanks in advance!

    bug 
    opened by sxdj 15
  • 504 Gateway Time-out: What can I do against this?

    504 Gateway Time-out: What can I do against this?

    How do you handle a request that leads to a 504 Gateway Time-out? Probably because VIES is down.

    This issue thread speaks about a timeout, but does it even work? https://github.com/driesvints/vat-calculator/issues/36

    Because when the user starts a request, the website just loads for 30 seconds and throws me a 504 Gateway Time-out error. Not so satisfying for a user.

    opened by pmochine 8
  • Every VAT-ID is invalid?

    Every VAT-ID is invalid?

    Hello,

    I am using Laravel Spark with Stripe. Now I mentioned that every VAT-ID seems to be invalid? That's too bad, I even used my own address.

    At least, I am getting the error:

    The provided VAT number is invalid

    bug 
    opened by ahoiroman 8
  • Added functionality for high and low tax types

    Added functionality for high and low tax types

    In the Netherlands we have more than one tax rate.

    High: 21% and Low: 6%.

    https://www.belastingdienst.nl/wps/wcm/connect/bldcontentnl/belastingdienst/zakelijk/internationaal/btw_voor_buitenlandse_ondernemers/btw_berekenen/btw_tarieven/

    I've added this functionality to this repository to help Dutch users.

    opened by SebastiaanKloos 8
  • Setting own company's country?

    Setting own company's country?

    Hi Marcel,

    First, thank you for this very useful package.

    One feature that seems to be missing, is having the possibility to set your 'home' country. If I understand the EU VAT rules correctly, VAT should be charged to companies based in your own country. So, if my company is based in Belgium and I sell to another Belgian company, I have to charge VAT. Right?

    How should I handle this situation with this package? It seems VAT 0% is applied to all companies, regardless of the country. If it's not in there yet, I can see if I can make a pull request one of the coming days if you like.

    opened by webcraft 8
  • Support date-based VAT rates

    Support date-based VAT rates

    Support date-based VAT rates in calculate(), calculateNet(), getTaxRateForLocation()

    Pass a DateTime/DateTimeImmutable object and the lib will find a rate for that date, or for current date if not specified.

    From now on, new or changed VAT rates should be added using the since key which has the same structure as the "parent" key (rate, rates keys). No existing values should be changed unless they're wrong.

    Reverts #92, the default DE rate is back to 0.19 and the new rate (0.16) is valid only for the interval specified.

    Fix #94

    This is backported from my "standalone" and "modernized" fork https://github.com/spaze/vat-calculator/pull/5

    opened by spaze 7
  • Method [validateVatNumber] does not exist.

    Method [validateVatNumber] does not exist.

    Hello,

    I just installed the package, added the service provider and alias to the app.php config file.

    I would like to validate an input with the vat_number validation rule. For this I added 'required|vat_number' in the rules for that field.

    However with this I'm getting the following error:

    Method [validateVatNumber] does not exist.
    

    When checking the VatCalculatorServiceProvider class, the registerValidatorExtension method get's called, however the VatCalculatorValidatorExtension@validateVatNumber does not.

    I'm using laravel 5.1.32, with package version 1.6.3.

    Did I miss something ?

    Thank you,

    Edit:

    I've found that when I comment the following:

    private function registerMaxFolderSizeValidator()
        {
            Validator::resolver(function ($translator, $data, $rules, $messages, $attributes) {
                return new MaxFolderSizeValidator($translator, $data, $rules, $messages, $attributes);
            });
        }
    

    here: https://github.com/AsgardCms/Media/blob/master/Providers/MediaServiceProvider.php#L80

    The Vat Validation rules works. Somehow laravel doesn't like multiple resolvers ?

    opened by nWidart 7
  • Calculate net from gross amount?

    Calculate net from gross amount?

    We'd like to make sure that all of our customers are billed a fixed amount, regardless of their country. This means we'd need to take the gross subscription cost and calculate the net amount from it. Is there any way to do it or plans to support it? AFAIK, this should be a fairly standard practice in EU - you always display the price with VAT.

    Let's say I have a subscription plan that's priced at gross 15€/month, and my business is located in Germany. Since VAT rate in Germany is 19%, the net price would be 15€ - 2,39€ = 12,61€.

    1. Customer is from Germany - price is 15€ (including 19% or 2,39€ VAT)
    2. Customer is from Finland, does not have a VAT number - price is 15€ (including 24% or 2,9€ VAT)
    3. Customer is from outside of EU - price is 12,61€ (VAT is always 0% when exporting)
    4. Customer is from any EU country (except from Germany), and has a valid VAT number - price is 12,61€ (VAT is always 0% in this case)

    The above calculations are based on the input we've had from our accountant. They are basically the same as your library already does, with one exception - the base price is a gross price, not a net price. This does, admittedly, make the calculation a bit trickier, but then again is fair and easier to understand for customers.

    opened by ragulka 6
  • Timeout option

    Timeout option

    Hello,

    Yesterday the VIES service was down and I had my website blocked on loading when I was using the class VatCalculator. It appear that the SoapClient was in kind of timeout as the VIES service was down.

    Any luck to add a timeout param?

    enhancement 
    opened by deStrO 6
  • Question regarding MOSS thresholds

    Question regarding MOSS thresholds

    I make reference to https://ec.europa.eu/taxation_customs/business/vat/modernising-vat-cross-border-ecommerce_en#heading_2, specifically the first threshold which states that:

    [business having an annual turnover of] up to EUR 10 000 TBE supplies remain subject to the VAT rules of the Member State of the supplier.

    Is this accounted for anywhere in the calculator? As I found no way to specify what my turnover is, or if this threshold should apply. Alternatively, is there a way to identify whether a country is part of the MOSS system or not? Eg. UK, while still having 20% VAT, is no longer part of MOSS and therefore I cannot apply this threshold to UK customers.

    Thanks!

    opened by caruanas 5
  • SoapClient in the __construct()?

    SoapClient in the __construct()?

    Is that really necessary to init SoapClient in the constructor? I mean, if I need vat calculator for other reasons (check vat rate) do i really have to load 'wsdl' all the time? What about to use setSoapClient() for that reason?

    opened by galexth 5
  • Cashier v13 support

    Cashier v13 support

    Cashier Stripe v13 has removed the taxPercentage because it bumps to the latest Stripe API version which has removed all support of tax_percentage in favor of its new Tax Rate API.

    Migrating to the new API will be quite an undertaking and some design decisions would need to be made. Will we auto-create/retrieve Tax Rates?

    enhancement 
    opened by driesvints 0
  • Include requestor VAT number

    Include requestor VAT number

    Hi,

    I would like to be able to pass along our own VAT number to the VIES validation service. When doing so, the VIES validation service returns a reference of the check. This reference can be kept by us to 'proof' we validated the VAT number with VIES, in case we ever have an issue with the tax officers.

    It would be nice that we can optionally send the $requestorVAT and get that reference as return.

    THank you for considering this.

    enhancement 
    opened by denjaland 1
Releases(3.1.1)
Owner
Dries Vints
I work for @laravel, maintain @laravelio and organise @fullstackbelgium & @fullstackeurope. Created @blade-ui-kit.
Dries Vints
the network of free stuff

home Free Net get free stuff give away free stuff ask for help help people out tell a story about free net hear a story about free net replicate and s

Trash Robot 1 Oct 31, 2021
Kyle is a web application built with Laravel for web developers and small companies to efficiently track and stay on top of yearly expenses related to services

Kyle Kyle is a web application built with Laravel for web developers and small companies to efficiently track and stay on top of yearly expenses relat

Laravelista 36 Jul 15, 2022
:panda_face: Jitamin is a free software written in PHP, intended to handle the project management over the web. QQ群: 656868

Jitamin Jitamin (pronounced /ˈdʒɪtəmɪn/) is a free software written in PHP, intended to handle the project management over the web. Jitamin is inspire

jitamin 916 Dec 14, 2022
Handle GitHub webhooks in a Laravel application

GitHub can notify your application of events using webhooks. This package can help you handle those webhooks.

Spatie 71 Nov 5, 2022
All in one ban system web (light version for all)

All in one - Ban system web (light version) All in one ban system web (light version for all) This database of players who violate or use third-party

Awesomium Team LLC 1 May 3, 2022
Engintron for cPanel/WHM is the easiest way to integrate Nginx on your cPanel/WHM server.

Engintron for cPanel/WHM is the easiest way to integrate Nginx on your cPanel/WHM server. Engintron will improve the performance & web serving capacity of your server, while reducing CPU/RAM load at the same time. It does that by installing & configuring the popular Nginx webserver to act as a reverse caching proxy for static files (like CSS, JS, images etc.) with an additional micro-cache layer to significantly improve performance of dynamic content generated by CMSs like WordPress, Joomla or Drupal as well as forum software like vBulletin, phpBB, SMF or e-commerce solutions like Magento, OpenCart, PrestaShop and others.

Engintron 632 Dec 14, 2022
A simple wrapper for PHP Intervention Library to provide a more simple interface and convenient way to convert images to webp

This package is a simple wrapper for PHP Intervention Library to provide a more simple interface and convenient way to convert images to webp - next generation format - extension, and resize them to render only needed sizes.

eyad hamza 18 Jun 28, 2022
The simplest, most intuitive way to host your photos on your website.

Gallery 3.1+ (development version) About Gallery 3 is a web based software product that lets you manage your photos on your own website. You must have

Brad Dutton 103 Dec 22, 2022
This Laracast Blog is built with Laravel 8.x taught by Jeffery Way on Laracasts

This Laracast Blog is built with Laravel 8.x taught by Jeffery Way on Laracasts. I followed his tutorial videos and added new features as he mentioned on his Github.

Wai Yan Kyaw 1 Dec 7, 2021
Unified sample web app. The easy way to learn web frameworks.

Notejam The easy way to learn web frameworks Do you know framework X and want to try framework Y? The easy way to start with a new framework is to com

Sergey Komar 1.1k Dec 21, 2022
Simple-podcast-generator - 👉 A very simple way to host your podcast files and generate the RSS Podcast feed 🎙

Podcast RSS Feed Generator A very simple way to host your podcast files and generate the RSS Podcast feed ?? ?? Contents Summary Requirements Installa

♚ PH⑦ de Soria™♛ 11 Dec 2, 2022
Mini is a small Laravel application with 2 modules to go with the book Laravel: The Modular Way

Mini Mini is a small Laravel application with 2 modules to go with the book Laravel: The Modular Way Install Clone this repo git clone [email protected]:

David Carr 5 Dec 4, 2022
Now Introducing a new and easy way to manage your clients and MyOwnFreeHost hosting accounts.

Warning This is a beta version of Xera. Use it for testing purpose only. You are be responsible for any loss or damages that may occor from using this

Mahtab Hassan 23 Dec 15, 2022
Codsletter: turn your website into a periodical newsletter, all automatically!

About Codsletter With Codsletter, you can turn your blog into a periodical newsletter with few clicks and some configuration. In particular, you can:

Mario Linguito 11 Nov 24, 2022
Online All in One Video & Audio Downloader From YouTube,Facebook,Twitter,Pinterest,Instagram,MXtakatak,IPL, Tiktok and 1000+ More Sites too

DLhut Contact me If You Find ANy Bug ... PHP Search and Download any Videos from any site. Online All in One Video & Audio Downloader From YouTube,Fac

Vijay Kumar 6 Oct 11, 2021
Online All in One PHP Video & Audio Downloader From YouTube,Facebook,Twitter,Pinterest,Instagram,MXtakatak,IPL, Tiktok and 1000+ More Sites too

DLhut Contact me If You Find ANy Bug ... PHP Search and Download any Videos from any site. Online All in One Video & Audio Downloader From YouTube,Fac

Vijay Kumar 4 Nov 8, 2021
DLvidHUT Online All in One PHP Video Downloader

DLvidHUT Online All in One PHP Video Downloader API based PHP Video Downloader from YouTube, Instagram, Twitter, Facebook, Tiktok and many more (More Than YouTube DL)

Vijay Kumar 2 Dec 31, 2021
A fully responsive and dynamic web app to present all products for a start-up called Zarafah

A fully responsive and dynamic web app to present all products for a start-up called Zarafah. Made of HTML, CSS, TailwindCss, Vanilla JavaScript, AlpineJS, Laravelphp, Laravel Breeze, Jotform Api for forms submissions and Mailchimp Api for Newsletter.

Mostafa Said 7 Dec 11, 2022
Full symfony website application cms + app all in one

Symfony Web App All in one cms website + Inventori Invoice Accounting Application A new modern web app with content management system for build websit

Mesin Kasir 5 Sep 22, 2022