Ubercart European VAT Compatibility

Posts: 3207
Joined: 08/07/2007
AdministratorHead Code Monkey - I eat bugs.

I got this image in an e-mail from Dries' blog, a basic flowchart for understanding VAT in Europe: http://www.buytaert.net/images/blog/vat-in-europe.jpg

He has a disclaimer, but it seems to be a good visual understanding of what must be possible for Ubercart to be a viable e-commerce solution in Europe. The two things we don't easily facilitate at the moment, by my reckoning, are allowing customers to enter their own VAT number (do we need to do a checksum on these to validate them?) and making it easy to apply taxes only to EU member states.

I believe zmove's VAT contrib can handle accepting a customer's VAT through a checkout pane, though I haven't tested it myself. Perhaps we should focus our efforts on making this module solid for that use and then building into it a workflow-ng condition that will check an order to see if the customer is in an EU member state with a single condition. Right now you'd have to have the countries enabled and add individual conditions to the tax configuration for each country... a single condition could make this super simple. Since we're using ISO-3166-1 number for country IDs, it won't be a problem to build this into a single condition check. (in_array() anyone? Smiling)

Once this is polished up, I think we also need to address the product price display concerns. I'm sure there are a range of things countries require, but we can work towards total flexibility.

As soon as this action happens, or even during, I propose opening a project on drupal.org for the VAT module that we can direct people to. I'm happy to open this for us and provide CVS access to anyone interested in contributing. We simply can't ignore such an important task, and at the moment core just doesn't cut it.

Please respond if I'm missing anything or if you have other feedback. Perhaps the module should be a more general International Tax module to accommodate the PST, GST, and whatever other taxes exist in places like Australia, Canada, etc. Puzzled

Posts: 27
Joined: 02/14/2008
Bug Finder

Hello Ryan,

thank you very much for taking care for this topic! Just a few short thoughts on this topic. The flowchart is really good, probably just missing the difference between professional and private customers, but there I am now also not sure.

VAT contrib: IMO there is missing that just professional customers have to provide their VAT number, so the additional condition should be if the customer fills the Company field. This one I still was not in, so more I can't tell ATM.

IMO this should be definitely also the way for Australia, Canada and probably others.

zmoves uc_taxes_alter is a good starting point to achieve most of the things on a module base, but it is far from being complete.

A module's base should be 2 main configurations:
- Are taxes calculated on per order base (like it is) or on per product base (like e.g. the EU needs). This is a rounding issue and just 3 lines somewhere in uc_taxes need to be packed in a if/else statement.
- Display taxes: Show taxes just on checkout or always? I mean really always, e.g. products, teasers, cart, order pages, invoice template, shipping, ... all displayed incl. VAT.
The rest can work through Workflow-ng (and that a "Display Tax" module checks theses settings)

I am looking forward to contribute whatever is useful from the code I produced up to now, best regards,

Al

Posts: 3207
Joined: 08/07/2007
AdministratorHead Code Monkey - I eat bugs.

Thanks for the input, Al. It sounds like we may need to make some simple core improvements, then, to display prices w/ VAT included. I wouldn't be opposed to that for Ubercart 1.1. Have you setup a European Ubercart store yet, and if so, do you have a link to the snippets you patched in in the forums? I know there's discussion in several places about the topic, so I'd love to bring it all together. I'll ping zmove about this thread so we can get his input. Smiling

Posts: 410
Joined: 08/13/2007
Bug FinderEarly adopter... addicted to alphas.Getting busy with the Ubercode.Internationalizationizer

Hi,

I'm very happy to see that the European case will be a major point for the next Ubercart releases Eye-wink. I spent a lot of time to think about the best way to implement the European needs and I think, now, I have a pretty strong opinion about the question.

As Ryan said, and I'm totally agree, it's not just a VAT number concern. Provide a Store VAT number (set up in the store setting) and a customer VAT number (set up in the checkout page via a checkout pane) as my VAT contrib do is just anecdotic. There is a price display issue too.

So the ideal "European Friendly" module would merge 2 modules : VAT contrib and Add tax to product price contrib but ATM, this 2 modules need a lot of work to be usable by most users.

See below what the module should do in a perfect world :

The VAT module

This module have to know 2 informations about the user :

  • His status (individual or professionnel)
  • His country (in European Union or not)

If the status is professionnal and the country is in European Union, the store have to show a required VAT number field. To make these conditions, I think workflow is a good solution. As the module already provide a "check the customer delivery address", it would provide a "check the customer billing address". In addition, the country select list is multiple, so it's easy to check all european countries in one rules.

I would add that, for usability, that the VAT number should not be in a separate pane. It should be in the customer billing information pane, and appear or disapear if the customer change his country for an european country or not. As you have to use javascript to make the condition (because the country is not asked before the checkout pane) I think it can be done using javascript too. (see the screenshot 1)

For the condition about the user status, I think the best way to dissociate an individual customer than a professionnal is to create 2 different roles in drupal, it's what I done for my Kalys gastronomie website There are a lot of advantages to make it via roles :

See in my screenshot that the company field become required if the user role is professionnal, so it means the core can provide optional/required field depending on user role

  • Its drupal core, so there are a lot of modules that extend functionnalities (example, ask different information depending on the role on registration, separate individual and professionnal statistics in google analytics, create coupons just for a selected role etc...)
  • Its easy to add a condition in workflow to check the user role, some actions to gives roles etc...
  • more, more, more...

And the module would provide 2 token for the invoice :

  • One to show the store VAT number
  • One to display the customer VAT number

One cool feature would be to check if the VAT number is correct on a European database, I know it's doable because there is one module for osCommerce that do it. the store admin would be able to choose if he want this option or not

The display price module

In an european store, all individual (all over the world) have to pay the VAT. For professionnals, only the professionnal of the country of the store pay the VAT, the others don't pay it. So you need to know 2 informations about your customer when showing price

  • His status (professionnal or individual)
  • His country (the same than the store or not)

As it's impossible to know the country of the customer before the checkout page, you cannot check the second condition on a product page but you can show both prices (with a bigger price includng VAT, because it's the more important). A cool feature would be to let the choice to the user, to show single price or both. If single price is checked, the store show price including VAT to individuals and price excluding VAT to professionnal.

The "including VAT" or "excluding VAT" have to be specified near the price to not confuse the user, so the module have to implement a kind of suffix after all prices.

In addition, the prices have to be managed excluding prices, because all calculation on product (example discount) are made on excluding price. Adding the tax to the price is only for display.

So to resume, in europe, it's better to show prices including prices to the user, but you have to manage them excluding price. One problem I encounter when I developped the add tax to product price contrib was that Ubercart calculate the subtotal by adding, for each product, the product price * quantity. So, as I wanted a subtotal excluding tax, I had to make a reverse calculation te remove the tax I added on sell price on the checkout page, which could bring some rounding problems. I think core have to change some things (don't know what) to make that more extensible.

Another things is that, the subtotal have to be displayed like that on the invoice :
- Subtotal excluding tax
- Shipping quote excluding tax
- Discount (if one) applied on the subtotal excluding price
- Total excluding price
- Tax
- Total including price

But this is already possible with the Lyle addition to show the Total excluding price before the tax if a tax is displayed (Thank you Lyle Eye-wink)

Voilà, I wish my post is complete enough.

About my work on that module, I'm not opposed to that, but maybe not as the main maintainer. Maybe as a co-maintainer or a consultate, because It's not my work, I'm not sponsored to only work on that so I don't often have the time for that. I could work on the 2 modules I develop because it was a need of a customer, now it's done, I'm on another project that don't need it ATM so I don't have much time to spend on it (and on my free time I'm developping a website for my eve online corporation ^^).

So maybe as a co maintainer or a consultate, I'm ok.

AttachmentSize
screenshot1.png37.04 KB
Posts: 3207
Joined: 08/07/2007
AdministratorHead Code Monkey - I eat bugs.

Thanks so much for taking the time to put this whole post together, zmove. Smiling

I'll chew on this for a while and we'll see where to go next. I'm sure we can put this all into one module that's usable for Ubercart 1.0 and then work it into core for 2.0. We'd be happy to have you on as a co-maintainer/adviser.

I may look into that osC contrib to figure out how they're validating VAT numbers, too.

Posts: 2
Joined: 02/22/2008

We've been working on the same problem, but threw in another one that seemed to be somewhat related: Different prices.

It seems a requirement/wish for a lot of customers to be able to have different prices depending on different criteria, some examples:

Role based prices for setting custom prices for 'Gold customers'.

Currency based prices, as pure rate based conversions isn't satisfactory for some customers.

Our, work in progress, solution moves prices out into a generalised module that allows add on modules to define hooks into the price finding process. In the finding process each hook can either change the price or add another 'price' as a property. An example of the latter could be a VAT calculating module that stores the VAT with the price without changing the price as such. The theming function can then decide whether to show the price with or without VAT, or with VAT as a separate item.

The idea is that a shop system (not limited to Ubercart) requests the price for an object (often node, though other types can be implemented), and uses the theme function to display it (by telling the theme function where the price is to be shown, which allows the themer to variate the display depending on context), and an 'getter' function for getting the price that should be ultimately charged for this object (allowing for more hooks).

Also the price object contains the currency of the price, which allows for both exchange rate based modifiers as well as add-on modules that store prices for different currencies.

This allows for considerable control over how prices and their display.

Posts: 2
Joined: 05/08/2008

Hi Ryan,

I'm working as a product manager on a rather biggish drupal project in Germany which plans to utilize your wonderful shop module. Currently we are stuck at the precise point this thread is about: the correct display of tax rates.

I'm really looking forward to the module you are planning. Great to see that you are taking on this issue. One observation I would like to make:
- The tax display issue is by far the most critical, since the current mode of adding taxes to the total of all ordered products is a complete dealbreaker for most european countries.
- Also a solution should not only be limited to diplaying orders and the cart but should also include the way orders are stored in the database, notifications mailed to customers and so forth. (I'm no drupal/ubercart expert so please forgive me if that sounds stupid...).
- Taxes should be calculated on a per-item-basis with the added capability of applying dfferent tax-rates to different product categories.
- The issue with the VAT-numbers is also important, but on the other hand there will be a majority of shops who only deal with private customers within their own country or at the most within the EU. And those shops wouldn't need this functionality.

My plea, therefore: If it would speed things up to seperate the two isues into two modules, by all means do it. And then push out the tax display module as soon as possible.

Thanks for your consideration.

Posts: 410
Joined: 08/13/2007
Bug FinderEarly adopter... addicted to alphas.Getting busy with the Ubercode.Internationalizationizer

Hmm I would precise that, even if you only sell to private customers, you have to show your shop VAT number in the invoice, so it's equally important that the Tax price display issue.

I agree that the tax should be calculated per item basis, or we will have rounding issue on the checkout page (as I have on my shop). The problem is that we have to store the price excluding tax somewhere because this is the base of all discount calculation.

The major problem with tax is that the tax have to be calculated at the very end in the invoice (and checkout page) but, at the same time, each product must be showed including tax.

And the way ubercart calculate the subtotal ATM make this not possible.

Posts: 2
Joined: 05/08/2008

Quote:
even if you only sell to private customers, you have to show your shop VAT number in the invoice, so it's equally important that the Tax price display issue.

The shop VAT number can very easily be placed in the template for the invoice, and also in the footer of pages or an "about"-page since it never changes. The really problematic VAT numbers we would need a module for are those of customers from other EU-countries which you have to somehow store in order to report the taxes you received correctly to the local IRS...

Posts: 27
Joined: 02/14/2008
Bug Finder

@xen.dk@drupal.org: How far are you? This development sounds very interesting to me.

My opinion about what we really need to display taxes:

  1. First issue is about rounding on a per product/item base, so this means in uc_taxes_workflow.inc 3 if/else statements. That simple if you know where it happens. To get an idea what about it should look like see the attached patch
  2. Next is for discussion: To get the taxed Subtotal for the checkout process I added 3 lines in uc_cart_checkout_pane.inc. Target is to collect the subtotal where I already have the values taxed (through my module) and save it in a $_SESSION['taxed_subtotal']. This works now already 2 or 3 weeks without any issues for me. Maybe this could be done by a module also, but not in 3 lines.
  3. Probably not a much bigger thing, but I still didn't have time to look into it how it could be done: In the order we need for every product and every line-item the tax rate(s) at time the order was submitted. Tax rates are no diamonds, so this is needed to get old orders displayed right if tax rates changed.
  4. Where I am totally lost are the 2 Javascripts on /checkout: Both should save the values without tax (as is), but call Workflow-ng for the tax rules and then display the taxed values. This any solution will need. If someone has a better relationship with JS than me and wants to help out - you are warmly welcome!!!
  5. If we talk about Europe I would like to mention that currencies still are a very big issue, so my +1 for xen.dk@drupal.org's efforts or I start in a couple of weeks a thread about "opening uc_currency_formt()". Smiling

To get things finally started independent on which module base this are the basic requirements. More core support or a more sophisticated approach would make our life easier for keeping our module up to date, but only the above things are the real show stoppers.

Ok, from whatever reason the second patch doesn't generate, so inline. Sorry. Base is uc_taxes_workflow.inc, v 1.1.2.5 2008/04/23 19:38:13

line 89

<?php
        $amount
+= $item->price * $item->qty * $tax->rate;
?>

gets line 89-95
<?php
       
// EU support
       
if (variable_get('uc_taxes_per_item', '0')) {
         
$amount += round($item->price * $tax->rate, variable_get('uc_currency_prec', '2')) * $item->qty;
        }
        else {
         
$amount += $item->price * $item->qty * $tax->rate;
        }
?>

line 101

<?php
        $amount
+= $line_item['amount'] * $tax->rate;
?>

gets line 108-114
<?php
       
// EU support
       
if (variable_get('uc_taxes_per_item', '0')) {
         
$amount += round($line_item['amount'] * $tax->rate, variable_get('uc_currency_prec', '2'));
        }
        else {
         
$amount += $line_item['amount'] * $tax->rate;
        }
?>

line 107

<?php
      $amount
+= $other_tax['amount'] * $tax->rate;
?>

gets line 122-128
<?php
     
// EU support
     
if (variable_get('uc_taxes_per_item', '0')) {
       
$amount += round($other_tax['amount'] * $tax->rate, variable_get('uc_currency_prec', '2'));
      }
      else {
       
$amount += $other_tax['amount'] * $tax->rate;
      }
?>

AttachmentSize
uc_cart_checkout_pane.inc_.patch1.08 KB