The UK VAT system is changing from 17.5% to 15%. What strategies have you used in your code to store the VAT, and how will the change affect your applications. Do you store a history of vats so you can calculate old prices, or are old invoices stored in a separate table? Is it a simple config setting, or did you bodge it? What's the ideal way to store VAT?
We pull the VAT from a database table shared by all of our internal apps meaning it's not a big deal for us where our new code is concerned. Keeping it centralised like this has to be a smart move.
I found a table in the code last night that stored important configuration settings for the application.
Table tbl_config
config_id int
config_name varchar(255)
config_value varchar(255)
One of these settings was our main admin username and password combination for the server (unhashed). I guess the dev who created it always wanted access to it in case he forgot! Needless to say, it's disappeared now.
Don't store it. Calculate it!
My recommended way of storing %age based rates/interest is:
You should have a table 'VAT_param' like
Interest rate | Effective from (date) | Effective Till(date)
I believe,
"Anything that can be calculated, should not be saved"
Especially in such cases where you need to calculate values based on %age of others (like taxes, interest, etc.) Don't let the Time-Space trade-off dodge you. You'll bless yourself later for spending time over space.
Then the VAT should be neatly calculated based on the effective rate during the period, based on the Invoice date. It will
Ensure least redundancy (pls. never talk about old tables or new tables.. over a few years you'll start pulling your hairs if the interest rate changes once an year)
Have a centralised single-pivot to control the rate. Your VAT_param table.
I've a nasty feeling that 2 of the systems I've inherited have the rate hard-coded somewhere.
Worse than that is that if it is hard-coded, I will simply be replacing the hard-coded values as I don't have the time for properly changing it.
Even worse than that, I don't know where I'm going to get the time to actually do the change. So I imagine that it won't be done in time for Monday's change. Of course there are more interesting issues, such as that our £10 subscription is based on being £10 including 17.5% VAT (£8.515 or whatever it is). It'll now be £9.79 or so, making a complete mess of everything that advertises it at £10, and all the site calculations based on £10.
All this because the idiot in charge of the piggy-bank wanted a headline.
Don't calculate it. Store it!
HMRC are very fussy about getting paid the right amount of VAT. The rounding of VAT calculations is somewhat vaguely specified in the user guides, and leaving it up to future implementers to get it right is possibly asking for trouble. By storing the amount when the invoice/line-item is entered, this problem is avoided.
This seems like a waste of storage and a violation of redundancy principles, but the amount of storage involved is tiny and it could save a lot of trouble in the future. Of course, it goes without saying that the currency amounts (and potentially even VAT rates with a fractional part) should be stored as a multiplied integer to avoid binary fractional representation rounding errors creeping in too.
Central rate storage
You should absolutely use central rate storage. However, I would recommend that this only provides the current default rates used when entering new invoices. These can be stored with start and end dates to give automatic changeover if necessary. These rates can be stored for each invoice (or invoice line) along with the calculated VAT amounts at the time the invoice is raised to give an absolute snapshot of the situation at the time.
Don't forget to accommodate the different VAT rates too (e.g. standard, reduced, zero-rated, no-VAT) and the possibility of trading with VAT registered entities in other EU countries where you may have to no-VAT an invoice that would normally be subject to VAT.
You could end up with a table like this (example):
id | Rate name | VAT rate | Start date | End date --------------------------------------------------- 1 | Standard | 1750 | 01/01/1991 | 30/11/2008 2 | Standard | 1500 | 01/12/2008 | 31/12/2009 etc
The above table is only an example. The VAT rate is stored as an integer of "basis points" (e.g. hundredths of a percentage point), but does assume that the VAT rate will never be to more than 2 decimal places. You could obviously extend this with an extra column to relieve this problem, but it would seem possibly a step too far!
We have our VAT rates stored in a database table so it's not too big a deal for us although I do have to hold my hand up and say that due to the nature of some of the modifications we made to the code VAT was hard-coded in a couple places (my bad!) which I've managed to re-fudge in another more exciting manner!
My thoughts ...
a- I generally prefer calc over store, but in this case the calculated VAT (and the rate & codes used to calc) should be stored with every transaction. This is because it will be source data for documents that must be repeatedly generated. You also want to be able to match the VAT amount from a sale to the VAT amount in a financial ledger. You do not want to risk the possibility of not being able to re-generate a document like an invoice or VAT report identically every time.
b- The VAT (or other tax) values should absolutely be stored in a table, with effective dates and rates. If it is hard-coded, do the work now to soft-code it, because it is likely to change again in the near future.
c- This is a huge (and solved) deal in the US, because sales tax varies between states, counties, and even cities. I live and work in Los Angeles County, and the sales tax rate is 8.25%. 10 miles south, in Orange County, the sales tax rate is 7.75%. Internet and catalog retailers have to know the correct rate, because it is determined by delivery location!
Good luck.
I am just working on something to do this for when the rate changes back.
Which ever way you do it, there's no need to record a start and an end date in your vat table since the vat periods run directly after each other.
You can access the correct vat by doing a query like the one below, where vat_date is the start date for the VAT rate.
SELECT * FROM vat WHERE NOW() > vat_date ORDER BY vat_date DESC LIMIT 1
In regards to the store vs calc argument. If you store it, you can always calculate it later -if you change your mind ;)