Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Impossible to implement new European tax law for digital goods (as of 1/1/2015) #6154

Closed
mamhoff opened this issue Mar 11, 2015 · 8 comments
Closed

Comments

@mamhoff
Copy link
Contributor

mamhoff commented Mar 11, 2015

As of the 1st of Jan, 2015, the European Commission has blessed us with the following fine piece of legislation:

Key regulatory changes

  • Taking effect on 1 January 2015, EU VAT regulatory changes impact companies supplying telecommunications, broadcasting and electronic services to EU customers.
  • Member States must allow suppliers to register on a MOSS from 1 October 2014.
  • Instead of companies applying VAT according to VAT rates for the country in which they are registered, the VAT on these services becomes payable where their end customer belongs.

This is currently almost, but not quite possible with Spree's zone-based taxation system. We have to output prices including VAT, and depending on which type of good (digital vs physical), different VAT rules apply:

  • Physical goods: Regardless of destination, all prices carry the VAT of the origin country.
  • Digital goods: If sold to consumers, all prices carry the VAT rate of the destination country.

Example:

A cart containing a shirt and a music file to be downloaded ordered from Denmark in a web store based in Germany has to apply two different VATs:

  • 19% German VAT on the shirt, as it is a physical good
  • 25% Danish VAT on the downloaded music file.

Difficulties with Spree's current taxation model

In order to achieve correct taxation, we created tax rates and corresponding zones for each individual EU member state (for digital goods). We also created a tax rate and zone for all EU countries with the German VAT (as our client is based in Germany).

This works, but only as long as we display prices excluding VAT, which is not allowed in the EU. If we switch to prices including tax, Spree has difficulty calculating the correct tax rate: Because we can only set one "default tax zone" (EU for physical goods), with digital goods the net price changes depending on which country you order from, which can not possibly be correct (a download with a gross price of 10 EUR would have a net price of 8.10 when ordered from Germany and of 7.50 when ordered from Denmark.

We need Spree to calculate the net price always from the zone in which the retailer is based. To achieve this, we propose the following:

The default tax zone should be a belongs_to relation on the TaxCategory model. This way, Spree should be able to correctly assess which TaxRate to use to calculate the net price for different kinds of products.

This only makes sense for VATs which have to be displayed as included in the price. Thus, if it is not set, that would mean the tax is normal ('Sales') tax which is applied additionally.

As you would expect, this is a big change deep in Spree's taxation code. This is the only way we could think of to solve this difficult problem so far, we'd love to have your feedback on this issue.

We started work on a branch, and will publish a (probably breaking) PR shortly to illustrate our proposal and work this out collaboratively.

@JDutil
Copy link
Member

JDutil commented Mar 11, 2015

I ❤️ Taxes :-/

@tvdeyen
Copy link
Contributor

tvdeyen commented Mar 12, 2015

@JDutil especially in the EU!

@JDutil
Copy link
Member

JDutil commented Mar 12, 2015

I'm actually in favor of the EU approach over US our sales tax system is a mess, and makes VAT look easy peasy.

@tvdeyen
Copy link
Contributor

tvdeyen commented Mar 12, 2015

Ah, tax sucks everywhere ;)

The problem is, that we currently focus on some other features in our next sprint. So, sadly this has to wait until the week after next. If someone has some great ideas on how to refactor this, please feel free to put in some advices in here, so we can respect them.

BTW: Magento (the shop system we are replacing right now) DOES NOT make it right either. It is actually a big mess here in Europe, that nearly no shopping system can handle this messy law correctly.

So, if we (the spree community) get this right, this is a real advantage over lots of shopping systems!

@jpmacca
Copy link

jpmacca commented Mar 13, 2015

@mamhoff Try our Taxamo solution.

Repo here.

@tvdeyen we have just released a Magento module to handle EU VAT compliance.

Available from Magento Connect here.

@tvdeyen
Copy link
Contributor

tvdeyen commented Mar 16, 2015

@jpmacca Wow, this is a whole new level of marketing! Scanning GitHub issues? Thanks for mentioning your product, but I think you are wrong here....

@mamhoff
Copy link
Contributor Author

mamhoff commented Mar 17, 2015

I've been spending quite some time over the last couple of days in looking at the tax calculation code in Spree, and I've found some issues. I now think that the solution we outlined above, that of having different default_tax_zones for item categories, would be a hacky way of dealing with Spree's current handling of taxes that are "included in price".

Current situation

The fundamental issue is that the pre_tax_amount - which is the shop's base price for an item - is calculated dynamically every time an order is updated, using whatever Spree::TaxRate is set as included_in_price. Included tax rates then generate an adjustment which does not change the (gross) price, unless the order's zone is outside the default zone, in which case the following happens:

Desired situation

VATs, in real life, do not change how much a merchant charges. VATs change what prices look like. More technically: TaxRate.adjust should change the price of a line item depending on which TaxRates are included in price for that Zone. The price of the line item should then be calculated as the pre_tax_amount plus whatever included_in_price rates apply.

This should fulfil the following requirements:
An order with one line item (a download) priced at 100 € to Germany should cost 100€ if sent to Germany. At 19% German VAT, that means a price of 100 Euros, a pre_tax_amount of 84,03 Euros, and 15,97 Euros VAT as an included adjustment.

If the same order is ordered from the US, the price of the CD on the invoice should simply be 84,03 Euros, with no adjustments (as no taxes apply for that transaction). Currently, Spree handles this as 100 Euros _minus_ a 15,97 VAT refund adjustment. No need.

If that same order would be now sent to a country with a different VAT of, say, 25%, we should have again: a price of 84,03 * 1,25 = 105,04 with an included adjustment of 21,01 Euros. The pre_tax_amount for this line item does not, and should not, change.

Configuring Spree for MOSS with this setup

If things were implemented like this, the MOSS mess could be accommodated for with the following set-up:

You have zones for all EU countries, including the shop's residence country.
The shop's residence zone is the default zone.

Now, for different tax categories to be taxed with different VATs you simply create TaxRates that apply to digital products, are included_in_price, and have an amount reflecting VAT rates in this country.

For all normal products, you create TaxRates with the German VAT and zones inside the EU, but outside Germany.

Call for community participation

While we believe that this is correct, we do not know what the requirements of other shops are. Can you reach out to people and find out whether our reading of what VAT is would fulfill their needs?

Implementation details

Currently, TaxRate.potential_rates_for_zone always includes (zone.rb also plays a role here) the default_tax_zone rate for that product category. I believe it's easier if we just do this:

    def self.potential_rates_for_zone(zone)
      self.where(zone_id:
        Spree::Zone.potential_matching_zones(zone).pluck(:id))
    end

The default_zone should only be used for

  1. showing prices in the front-end to users without an address (those prices have to include VAT, so they'll have to be calculated dynamically)
  2. (optional) If in the backend prices have to be _entered_ including VAT, it should be used to calculate the pre_tax_amount on line items. Once, when they're created. Spree's input label translations hint at that being the default anyway.

I did look at the threads #4397 and #4327, as well as at #4318 (comment)

Stuff that will need changes:
https://github.com/spree/spree/blob/master/core/app/models/spree/adjustable/adjustments_updater.rb#L43

@mamhoff
Copy link
Contributor Author

mamhoff commented Mar 24, 2015

We will now start to implement something along the lines of the stuff I mentioned above. The idea is the following:

  • Prices, discounts, shipping rates, etc. will always be entered without VAT (just like in the US).
  • Variants and Line items both will get a method that presents the price including VAT for the default zone or the order's user zone.
  • In the course of this, we'll be have to be changing some tests, too.

The difference between VAT and sales tax is really an issue of displaying prices, discounts and shipping rates to users. In terms of how calculation is done, it is actually very similar to sales tax - especially for the merchant herself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants