What does it takes to calculate a sales tax?
Lately a few people have pointed out at sales tax calculation as a simple business logic that can be done in the database.
Let us consider what is involved in such a task, shall we?
Well, on the first iteration we have: The sales tax is 10% of the listed price.
On the second iteration, we learn that we now need to support more than a single location, so we need to keep an association of location to sale tax.
CalcSalesTax(price, location):
salesTax = locationsToSalesTax[location]
return price * salesTax
On the third iteration we learn that the business is paying 50% of the sales tax for preferred customers customers:
CalcSalesTax(price, location, customer):
salesTax = locationsToSalesTax[location]
salesTax /= 2 if customer.IsPrferred
return price * salesTax
(Note that this ignores the need to record that the business is paying the other half).
On the forth iteration we learn that we have the time dimension as well, since calculating a sales tax in the future need to take into account changes in the law:
CalcSalesTax(price, location, customer, calculationDate):
salesTax = locationsToSalesTax[location] salesTaxValue = salesTax.GetTaxRateAt(calculationDate)
salesTaxValue/= 2 if customer.IsPrferred return price * salesTaxValue
On the fifth iteration we learn that country Xyz is using a system where you pay sales tax based on your earning (why not, that would make as much sense as anything else in tax law):
CalcSalesTax(price, location, customer, calculationDate): salesTax = locationsToSalesTax[location] if location == specialCaseForCountryXyz: salesTax = CountryXyzWebService.GetTaxRateFor(customer) salesTaxValue = salesTax.GetTaxRateAt(calculationDate)
salesTaxValue/= 2 if customer.IsPrferred return price * salesTaxValue
On the sixth iteration you break down in tears and write the whole thing in XML.
There is no such thing as simple business logic beyond the username's field length,
Comments
And on the 10th iteration you realize that you need to calculate tax (in the US anyway) based on jurisdiction, and that there are up to 4 different jurisdictions in a given zipcode.
And that one of your clients, the University of Texas at Austin is in a tax-exempt jurisdiction, which just happens to be next to a jurisdiction that charges 6.3% - and they are both in the same zipcode, one block from each other.
Yes, this issue is a supreme illustration of spiralling logic :).
And in tennesse, we have the ocassional "tax holiday" where sales tax is not collected. In other states, food does not have sales tax (Florida?). In other states, labor is not taxed (Missouri).
Sales Tax is the perfect example of business logic that should never sit anywhere near a database.
Do these people ever develop real world applications? And do they ever have to support them?
Seriously ... a slaes tax caluclation that is not properly testable? that cannot be reused across systems? That relies on a database call to tell the user what the tax would be on a product?
I despair sometimes :)
In Norway (where I live) we've had massive changes in sales taxes during the last few years.
First there was a fixed 19 % sales tax on goods and no tax on services. Then tax on services outside the cultural sector was introduced, a year later the tax on groceries was reduced by 50 %. This tax reduction also applies to take out meals served by restaurants, but eat-in meals still get full taxation. Then transportation taxes (bus fares etc.) where set at ~5 %. Then the common sales tax was increased, but the grocery tax stayed the same - changing the 50 % reduction rule.
After a supreme court ruling, all performing arts where allowed to use the cultural sales tax of 0% introducing even more models into the mix.
This happened over the course of five years.
From the get-go, this has been a huge challenge for anyone writing software that has to deal with sales taxes. Those who managed to keep it out of the database have had the most success - and believe me; I've seen some "simple" stored procs turn quite ugly during the last five years.
Comment preview