satyacode
Background
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