Back to js-datatype-intermediate
09-zomato-order-builder.js
JavaScript
1/**
2 * 🍕 Zomato Order Builder
3 *
4 * Zomato jaisa order summary banana hai! Cart mein items hain (with quantity
5 * aur addons), ek optional coupon code hai, aur tujhe final bill banana hai
6 * with itemwise breakdown, taxes, delivery fee, aur discount.
7 *
8 * Rules:
9 * - cart is array of items:
10 * [{ name: "Butter Chicken", price: 350, qty: 2, addons: ["Extra Butter:50", "Naan:40"] }, ...]
11 * - Each addon string format: "AddonName:Price" (split by ":" to get price)
12 * - Per item total = (price + sum of addon prices) * qty
13 * - Calculate:
14 * - items: array of { name, qty, basePrice, addonTotal, itemTotal }
15 * - subtotal: sum of all itemTotals
16 * - deliveryFee: Rs 30 if subtotal < 500, Rs 15 if 500-999, FREE (0) if >= 1000
17 * - gst: 5% of subtotal, rounded to 2 decimal places parseFloat(val.toFixed(2))
18 * - discount: based on coupon (see below)
19 * - grandTotal: subtotal + deliveryFee + gst - discount (minimum 0, use Math.max)
20 * - Round grandTotal to 2 decimal places
21 *
22 * Coupon codes (case-insensitive):
23 * - "FIRST50" => 50% off subtotal, max Rs 150 (use Math.min)
24 * - "FLAT100" => flat Rs 100 off
25 * - "FREESHIP" => delivery fee becomes 0 (discount = original delivery fee value)
26 * - null/undefined/invalid string => no discount (0)
27 *
28 * - Items with qty <= 0 ko skip karo
29 * - Hint: Use map(), reduce(), filter(), split(), parseFloat(),
30 * toFixed(), Math.max(), Math.min(), toLowerCase()
31 *
32 * Validation:
33 * - Agar cart array nahi hai ya empty hai, return null
34 *
35 * @param {Array<{ name: string, price: number, qty: number, addons?: string[] }>} cart
36 * @param {string} [coupon] - Optional coupon code
37 * @returns {{ items: Array<{ name: string, qty: number, basePrice: number, addonTotal: number, itemTotal: number }>, subtotal: number, deliveryFee: number, gst: number, discount: number, grandTotal: number } | null}
38 *
39 * @example
40 * buildZomatoOrder([{ name: "Biryani", price: 300, qty: 1, addons: ["Raita:30"] }], "FLAT100")
41 * // subtotal: 330, deliveryFee: 30, gst: 16.5, discount: 100
42 * // grandTotal: 330 + 30 + 16.5 - 100 = 276.5
43 *
44 * buildZomatoOrder([{ name: "Pizza", price: 500, qty: 2, addons: [] }], "FIRST50")
45 * // subtotal: 1000, deliveryFee: 0, gst: 50, discount: min(500, 150) = 150
46 * // grandTotal: 1000 + 0 + 50 - 150 = 900
47 */
48export function buildZomatoOrder(cart, coupon) {
49
50 if (!Array.isArray(cart) || cart.length === 0) {
51 return null;
52 }
53 const validItems = cart.filter(item => item.qty > 0);
54
55 if (validItems.length === 0) {
56 return null;
57 }
58 const items = validItems.map(item => {
59 const addonTotal = Array.isArray(item.addons)
60 ? item.addons.reduce((acc, addon) => {
61 const price = parseFloat(addon.split(":")[1]);
62 return acc + (isNaN(price) ? 0 : price);
63 }, 0)
64 : 0;
65
66 const itemTotal = (item.price + addonTotal) * item.qty;
67
68 return {
69 name: item.name,
70 qty: item.qty,
71 basePrice: item.price,
72 addonTotal,
73 itemTotal
74 };
75 });
76
77 const subtotal = items.reduce((acc, item) => acc + item.itemTotal, 0);
78
79 let deliveryFee = 0;
80
81 if (subtotal < 500) {
82 deliveryFee = 30;
83 } else if (subtotal < 1000) {
84 deliveryFee = 15;
85 } else {
86 deliveryFee = 0;
87 }
88
89 const gst = parseFloat((subtotal * 0.05).toFixed(2));
90
91 let discount = 0;
92 const code = typeof coupon === "string" ? coupon.toLowerCase() : "";
93
94 switch (code) {
95 case "first50":
96 discount = Math.min(subtotal * 0.5, 150);
97 break;
98
99 case "flat100":
100 discount = 100;
101 break;
102
103 case "freeship":
104 discount = deliveryFee;
105 deliveryFee = 0;
106 break;
107
108 default:
109 discount = 0;
110 }
111
112 const grandTotal = parseFloat(
113 Math.max(0, subtotal + deliveryFee + gst - discount).toFixed(2)
114 );
115
116 return {
117 items,
118 subtotal,
119 deliveryFee,
120 gst,
121 discount,
122 grandTotal
123 };
124}
125
126