Problem Specification: SALES TAXES
Basic sales tax is applicable at a rate of 10% on all goods, except books, food, and medical products that are exempt. Import duty is an additional sales tax applicable on all imported goods at a rate of 5%, with no exemptions.
When I purchase items I receive a receipt which lists the name of all the items and their price (including tax), finishing with the total cost of the items, and the total amounts of sales taxes paid. The rounding rules for sales tax are that for a tax rate of n%, a shelf price of p contains (np/100 rounded up to the nearest 0.05) amount of sales tax.
A receipt can be viewed as a collection of sold items (hereinafter referred to as receipt-items) which contribute to the receipt’s characteristics like the total amount and the total amount of sales-tax.
Figure 1 – Receipt: Collection Of Receipt-Items
In the application, a receipt has to be generated and displayed. The steps involved would be:
- Create a receipt-item.
- Add it to the receipt.
- Repeat 1 and 2 for all items to be added to receipt.
- Display the receipt.
The required attributes of the receipt (from the problem-specification) are an item-listing, total amount and total sales tax. All these are dependent on the individual receipt-items and hence must be characteristics of receipt-items.
A receipt-item must provide the following information:
- Sales Tax (varies according to sales-tax policy)
- Price (The shelf-price depends on the sales-tax)
Figure 2 - Receipt Item
Since Sales-Tax and Price are dependent on extrinsic factors, we implement them as methods (the exact implementation-strategy will be detailed in the following sections). Items 1 to 3 may be implemented as attributes of the Receipt-Item abstraction.
There are two types of sales-tax defined in the problem– Import Sales Tax and Standard Sales Tax - any or both or none of these may be applicable on an item. But essentially both imply an amount to be added as tax.
Figure 3 - Sales Taxes
Both these types of sales-tax have to be rounded up to the nearest 0.05, but at a rate defined by the specific type of sales-tax.
Computing the Price of a Receipt-Item
Essentially, the Price of a Receipt-Item = Cost + Sales-Tax(es)
The price of a receipt-item will depend on the sales-taxes applicable on it. But the tax-policy can vary widely (and wildly!). The implementation of a receipt-item should, ideally, not vary based on such an obviously extrinsic factor, if it can be avoided.
Hence we delegate the responsibility of calculating tax to Sales-Tax entities. And since the number of sales-taxes to be applied may vary from none to many, this entity needs to be a list that could vary. This can be achieved by having the Sales-Tax entity point to the next Sales-Tax entity (if any) and so on.
Figure 4 - Sales Tax Computation: Chain of Responsibility
The price of a receipt-item can be easily determined after sales-tax computation.
Thus, the receipt-item would be able to provide information about both its price and its sales-tax.
Receipt-Item Creation: Sales-tax policy isolation
As mentioned earlier, the sales-tax could vary from time to time. It would be beneficial if we could abstract it from the receipt-generation application. Indeed, why need a cashier be required to know the intricacies of taxation and idiosyncrasies of politicians? J The application shouldn’t change each time the policy does!
What this means in the context of our arrived-at design, where each Receipt-Item will be equipped with a Sales-Tax entity, is that we will need to fit it with different kinds of Sales-Tax entities based on the taxation-policy.
We move such taxation-policy dependent logic/functionality into a separate class (Receipt-Item-Creator) which can create an appropriately built Receipt-Item, once it is given basic intrinsic characteristics of the item being sold. (Surely, it is reasonable to expect the cashier to know things like whether an item is imported, whether it is a food-item, its cost etc.)
Figure 5 - Receipt Item Generation: Builder
Displaying the receipt
We can have a function in the application to display (say, displayReceipt) a receipt. This function is not made a part of Receipt itself because having it so would tie the Receipt class to the Application mechanism (console/window/printer for starters).
We are now capable of implementing the steps of the application to demonstrate receipt-generation.
- Create a receipt-item === ReceiptItemCreator.create
- Add it to the receipt. === Receipt.add
- Repeat 1 and 2 for all items to be added to receipt.
- Display the receipt. === Function in the application === Receipt.*,
The consolidated class-diagram for the system is given on the following page. Please note that it does not comprehensively list all the methods and attributes in each of the classes.
Figure 6 - Biller System Class Overview
Design Assumptions and Choices
- The primary objective of the system is sales-tax computation.
- Sales-tax is calculated per item. In the case where the quantity of the item is more than 1, this makes a difference, whether the sales-tax is applicable on the total cost or on the cost of each item individually. The data in the problem-definition is insufficient to come to a conclusion. Choosing to go with per-item sales-tax.
- Items have not been classified as Taxable and Non-Taxable. Instead, we choose to embed a suitable Sales-Tax entity via the Receipt-Item-Creator.
- A similar strategy for modifying the description of the item was also considered. But such modification would have been complex (“Imported box of chocolates” or “Box of imported chocolates”?). For the same reason, “imported” was not chosen as a modifier which would append “imported” to the description and Imported-Tax to the Sales-Tax.
- It was possible to have a separate class for each Receipt-Item type. The resulting “class-explosion” would not have added much value to the system since we are primarily interested only in sales-tax. In the context of the system, there was not enough difference in the treatment of items based on such type to justify separate classes. The only drawback is that we lose the type (whether it was a book or food etc) in the Receipt.
- The operation of the system, as mentioned in the algorithm, is simple enough that sequence diagrams are not needed.
- New types of taxes may be applied by sub-classing Sales-Tax.
- Major changes in taxation-policy can be handled by sub-classing Receipt-Item-Creator. Slight variations in the taxation-policy can be accommodated by modifying it.
- If the type of the item (book/medicine/other) becomes of interest, the behavior can be added to the system by sub-classing Receipt-Item.
- Changes will be localized to Receipt-Item-Creator. The application can remain mostly unchanged.