One of the budding wholesale retailers in Capitalville, Mr. Rich Fairsell, has been looking at ways of boosting the sale numbers for his new online grocery store, Sabzi For Good (SFG). SFG's inventory has around 1MM products with prices mentioned inclusive of 20% VAT. He decided to run a marketing campaign sending out limited time unique discount codes to all ~50MM citizens of Capitalville. The customers will be able to put in the discount code on the checkout page and get 40% off.
Mr. Rich Fairsell needs your help in building an API which accepts the shopping cart with order items, coupon code and return the final discounted value to be displayed.
- Each discount code can be used only once
- All order items are discountable
- VAT cannot be discounted
https://reenz-discount-api.herokuapp.com
Try in your command line , no need to clone the repo to test it:
curl -X POST -d '{"cart":[{"itemId": 1, "itemQty": 2, "itemPrice": 5}, {"itemId": 2, "itemQty": 4, "itemPrice": 2.5}], "discountCode":"7ch8bhj77wws"}' -H "Content-Type: application/json" https://reenz-discount-api.herokuapp.com
First to understand the challenge I drew a diagram of the requirements, then solved below example request to get clear picture of the problem.
cart = [{"itemId": 1, "itemQty": 2, "itemPrice": 5}, {"itemId": 2, "itemQty": 4, "itemPrice": 2.5}]
cartTotal = (2 * 5 ) + (4 * 2.5)
= 20 (this price is inclusive of 20% VAT)
totalValidForDiscount = cartTotal - (20% VAT on cartTotal)
= 20 - 4
= 16
couponDiscount = 40%
discountedValue = totalValidForDiscount - (couponDiscount on totalValidForDiscount)
= 16 -(16 * 0.40)
= 9.60
finalDiscountedValue = discountedValue + 20% VAT on discountedValue
= 9.60 + 1.92
= 11.52
Once I was clear how to go about it I made a sample http request
request:
curl -X POST -d '{"cart":[{"itemId": 1, "itemQty": 2, "itemPrice": 5}, {"itemId": 2, "itemQty": 4, "itemPrice": 2.5}], "discountCode":"7ch83829oup"}' -H "Content-Type: application/json" http://localhost:8080
response:
{"finalDiscountedValue": 11.52 }
To calculate the discount I have decided to make DiscountCalculator class as I don't want to have business logic in my router.
Handle invalid request and respond with helpful error message.
Use PostgreSQL to store discount code so that it cannot be used again.
I made separate class for database interaction.
I want to keep it simple so I did not use ORM but this decision resulted in one more challenge where I need to clean the database after each test and that seemed tough without ORM. To tackle this challenge I used universal unique id package to generate unique discount code during tests to handle the error that is raised when same discount code is used again.
Made a setup file to automatically create coupon table in heroku.
git clone git@github.com:reenz/discount-api.git
- run
npm install
- set environment variable
exportDATABASE_URL="postgresql://dbuser:password@database.server.com:5432/databasename"
- open terminal and type
curl -X POST -d '{"cart":[{"itemId": 1, "itemQty": 2, "itemPrice": 5}, {"itemId": 2, "itemQty": 4, "itemPrice": 2.5}], "discountCode":"7ch83829oup"}' -H "Content-Type: application/json" http://localhost:8080
npm test
to run tests
- I would have used database cleaner to clean the database after each test.
- Refactor the server file ,there is lot of code in my route
- More database testing
- Tests for errors thrown
- Due to less time and less familarity with node postgres interaction I was not able to create different databases for production, test and development environment.