Design an Online Shopping Application
Design and implement an in-memory online shopping application. Customers can search for products, add products to a shopping cart, place orders, update payment statuses, and fetch their 10 most recent orders.
Product inventory and actual payment processing are not required.
Constructor
OnlineShoppingApplication(List<String> productDetails)
productDetails contains the complete product catalogue.
- Each string describes one product using
"productId,productName,category,priceInCents".
- Product names and categories never contain commas.
- Product IDs are unique, and prices are non-negative integers.
For example, "P12,Running Shoes,Footwear,6500" represents a product with ID P12, name Running Shoes, category Footwear, and price 6500 cents.
Invalid Product Rows
Ignore a product row when:
- It does not contain exactly four comma-separated values.
- Its product ID, product name, or category is empty.
- Its price is not a valid non-negative integer.
- Its product ID was already used by an earlier valid row. Keep the first valid product and ignore later duplicates.
For example, "P15,Chair,Furniture", "P16,Table,Furniture,invalid", and "P17,,Furniture,5000" are invalid rows and must be ignored.
Method Signatures
Search Products
List<String> searchProducts(String keyword)
- Return products whose names or categories contain
keyword.
- Matching is case-insensitive.
- Return each product using
"productId,productName,category,priceInCents".
- Return matches in their original constructor order.
- An empty keyword matches every valid product.
- Return an empty list when no product matches.
Add Product to Cart
List<String> addToCart(String customerId, String productId, int quantity)
- Add the specified product and quantity to the customer's active cart.
- Create a cart automatically when the customer adds their first product.
- If the product is already in the cart, increase its existing quantity.
- Return the complete updated cart.
The first returned string describes the cart using "CART,customerId,totalInCents". Each remaining string describes one cart item using "ITEM,productId,productName,quantity,unitPriceInCents,itemTotalInCents".
Cart items must be returned in the order in which their products were first added. For an invalid operation, return exactly one applicable error string and follow below priority order as to when to display which error:
"ERROR,EMPTY_CUSTOMER_ID"
"ERROR,PRODUCT_NOT_FOUND"
"ERROR,INVALID_QUANTITY"
Place Order
List<String> placeOrder(String customerId, String orderId)
- Create an order from all products currently present in the customer's cart.
- The supplied
orderId must be used for the order.
- Order IDs must be unique across all customers.
- Copy each product's name, price, and quantity into the order.
- Set the payment status to
PENDING.
- Set the order status to
PENDING_PAYMENT.
- Clear the cart only after the order is successfully created.
The first returned string describes the order using "ORDER,orderId,customerId,totalInCents,paymentStatus,orderStatus". Each remaining string describes one purchased item using "ITEM,productId,productName,quantity,unitPriceInCents,itemTotalInCents".
Order items must follow their cart order. If the order cannot be created, leave the cart unchanged and return exactly one applicable error string and use below priority order to return error strings:
"ERROR,EMPTY_CUSTOMER_ID"
"ERROR,EMPTY_ORDER_ID"
"ERROR,DUPLICATE_ORDER_ID"
"ERROR,EMPTY_CART"
Update Payment Status
List<String> updatePaymentStatus(String orderId, String paymentStatus)
paymentStatus must be PENDING, SUCCESSFUL, or FAILED.
- Set the order status to
PENDING_PAYMENT for PENDING.
- Set the order status to
CONFIRMED for SUCCESSFUL.
- Set the order status to
PAYMENT_FAILED for FAILED.
- A failed payment may subsequently be updated to
SUCCESSFUL.
- Once payment becomes
SUCCESSFUL, it cannot be changed again.
- Return the complete updated order in the order format defined above.
If the status cannot be updated, return exactly one applicable error string. Use below priority order to decide which error string to return:
"ERROR,ORDER_NOT_FOUND"
"ERROR,UNSUPPORTED_PAYMENT_STATUS"
"ERROR,PAYMENT_ALREADY_SUCCESSFUL"
Fetch Recent Orders
List<String> getRecentOrders(String customerId)
- Return at most the 10 most recently placed orders of the customer.
- If the customer has fewer than 10 orders, return all their orders.
- Return the most recent order first.
- Represent each order using
"ORDER,orderId,customerId,totalInCents,paymentStatus,orderStatus".
- The returned summaries must reflect the latest payment and order statuses.
- Return an empty list if
customerId is empty, the customer does not exist, or the customer has not placed any orders.
Constraints
1 ≤ productDetails.size() ≤ 10,000
- Every valid product row contains exactly four comma-separated values.
1 ≤ productId.length(), productName.length(), category.length() ≤ 100
- customerId, orderId, Product names and categories never contain commas.
- Valid product IDs are unique and never contain commas.
0 ≤ priceInCents ≤ 1,000,000,000
0 ≤ keyword.length() ≤ 100
0 ≤ customerId.length(), orderId.length() ≤ 100
1 ≤ quantity ≤ 1,000,000 for valid quantities.
- Every cart and order total fits in a signed 64-bit integer.
- All information is stored in memory.
- No parameter passed to the constructor or any method will be
null.
- The constructor and methods must never throw exceptions.
Examples
Example 1: Invalid Products, Search, and Cart
new OnlineShoppingApplication(productDetails = List.of("P10,Smart Watch,Wearables,12500", "BROKEN,Only Two Fields", "P20,Noise Cancelling Earbuds,Audio,7500", "P10,Duplicate Watch,Wearables,9999", "P30,Coffee Mug,Kitchen,invalid", "P40,Coffee Mug,Kitchen,1200"))
The malformed row, duplicate P10, and invalid P30 row are ignored. Products P10, P20, and P40 are stored.
searchProducts(keyword = "audio")
Output: ["P20,Noise Cancelling Earbuds,Audio,7500"]
addToCart(customerId = "C7", productId = "P20", quantity = 2)
Output: ["CART,C7,15000", "ITEM,P20,Noise Cancelling Earbuds,2,7500,15000"]
addToCart(customerId = "C7", productId = "P40", quantity = 1)
Output: ["CART,C7,16200", "ITEM,P20,Noise Cancelling Earbuds,2,7500,15000", "ITEM,P40,Coffee Mug,1,1200,1200"]
Example 2: Orders and Payment Status
Continuing with the cart from Example 1:
placeOrder(customerId = "C7", orderId = "O700")
Output: ["ORDER,O700,C7,16200,PENDING,PENDING_PAYMENT", "ITEM,P20,Noise Cancelling Earbuds,2,7500,15000", "ITEM,P40,Coffee Mug,1,1200,1200"]
updatePaymentStatus(orderId = "O700", paymentStatus = "SUCCESSFUL")
Output: ["ORDER,O700,C7,16200,SUCCESSFUL,CONFIRMED", "ITEM,P20,Noise Cancelling Earbuds,2,7500,15000", "ITEM,P40,Coffee Mug,1,1200,1200"]
addToCart(customerId = "C7", productId = "P10", quantity = 1)
Output: ["CART,C7,12500", "ITEM,P10,Smart Watch,1,12500,12500"]
placeOrder(customerId = "C7", orderId = "O701")
Output: ["ORDER,O701,C7,12500,PENDING,PENDING_PAYMENT", "ITEM,P10,Smart Watch,1,12500,12500"]
Example 3: Fetching Recent Orders
getRecentOrders(customerId = "C7")
Output: ["ORDER,O701,C7,12500,PENDING,PENDING_PAYMENT", "ORDER,O700,C7,16200,SUCCESSFUL,CONFIRMED"]
Customer C7 has only two orders, so both are returned with the most recent order first.