3

I've been given the task to design a system that has a product's price have different amounts of different taxes based on different factors.

For example in the US you would get a few - one based on region and another on state and such, while in the EU you get VAT. I'm trying to figure out a non-hardcoded way of different taxes being applied based on different factors for the customer and the product and the location or store.

Does anyone have an idea as to an exiting solution that would easily apply to this problem?

I also would accept general answers on how to learn to solve such design questions in general (like a book that guides you through creating a structured approach)

  • Take a look in the Strategy design pattern, it seems to be a good choice for your problem. If it is not, please provide more details about what you need – Emerson Cardoso Oct 30 '17 at 9:50
  • Ooh, nice! Yeah, that was kind of what I was looking for, an easy way to add new different kinds of calculating tax based on potentially random factors. I will see how I can adapt it to use this pattern. And I guess I'll have to read up on that Design Patterns book. I may return here to describe my final implementation – SpooXter Oct 30 '17 at 14:06
  • 1
    Don't forget the time aspect, tax rates change over time so the day of sale might affect the calculation too. – Lauri Laanti Oct 31 '17 at 22:35
2

Craig Larman's Applying UML and Patterns tackles the problem with an external tax service (real services do exist if you Google them) and a Gang-Of-Four object Adapter that converts the results into the format expected by the system.

I think Strategy might be OK, but it's ambitious to think that you're going to be able to maintain the code for all the tax algorithms that exist. At every election there's a chance your code will have to change and maybe even have to be validated with local government authorities (?).

As you noted, taxes are complex. You could have multiple lines in a sale (in Quebec there is TVQ and TPS, and at one time you were taxed on the tax!). In some states in the US there is no tax on clothing, or food, etc. To abstract these aspects, Larman's conceptual design used (see Section 26.3) a TaxLineItem in the domain model. The external service takes care of creating them (the logic is in the external service).

Here's a rough UML diagram of that idea:

enter image description here

For the Adapter, here's how it looks in 26.1:

enter image description here

The use of an adapter:

enter image description here

3

One solution is to make the various taxes be objects that you add to each product and which are used in calculating its price. For example, you might have an abstract base class or interface that looks like this:

class ITax {
    calculateTaxForPrice(Price amount);
};

and then specific subclasses would implement the calculation for different types of taxes, like this:

class VATTax : public ITax {
    calculateTaxForPrice(Price amount);
};

class StateSalesTax : public ITax {
    calculateTaxForPrice(Price amount);
};

Then your product would have a list of taxes that need to be added to it:

class Product {
    public:
        addTax(ITax someTax);
        Price getPrice();
        Price getPriceWithTaxes();

    private:
        array<ITax> taxes;
};

In getPriceWithTaxes() you'd take the price and add in the tax for each element of the taxes array.

This scenario lets you exempt specific products from specific taxes, for example. You can have just the ones that each product needs.

  • 1
    What about if I have taxes that are based on both location of the store/customer and the product type? – SpooXter Oct 30 '17 at 1:15
  • That should be fine. The process for adding the taxes will depend on a variety of factors. You'll need to determine for each product, which taxes are appropriate and add them at run time. But it can use the same mechanism as above. – user1118321 Oct 30 '17 at 2:21
  • It may be better to make Product an interface or abstract class, as different product categories will have different tax treatments. The structural challenge, IMO, is to coordinate the different factors that affect the tax: the state, product type, customer type (resale or end-customer), and the time of sale (you may need to backdate a sale and use the tax settings from a different year). The factors combine into a multi-dimensional matrix, but a language's lack of multiple inheritance can complicate the implementation by forcing it down to the 1D nature of single inheritance. – user3685427 Nov 1 '17 at 14:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.