restaurant_management_system.md

๐Ÿฝ๏ธ Restaurant Management System โ€” Low-Level Design & Simulation

Target Interview Level: SDE-1 Fresher / Campus Placement โ€” Juspay-specific
Topic: End-to-End Restaurant Management System (Table Allocation, Order Routing, Kitchen KDS, and Billing)
Language: Clean C++ (Simple, readable, raw pointers, no smart-pointer/concurrency clutter)
Resume Synergy: Directly aligns with your internship at VTBIT Solution (Admin, Waiter, Kitchen Staff RBAC, order timers, and order lifecycle management).


๐Ÿงญ Interview Mindset: How Juspay Evaluates This Problem

When asked to design a Restaurant Management System (RMS) in an SDE-1 interview, interviewers look for:

  1. Physical Entity Modeling: How cleanly you represent real-world restaurant objects (Tables of varied capacities, Menus, Orders, Kitchen display, Bills).
  2. State Machine Rigor: An order moves through explicit lifecycle states (CREATED $\to$ SENT_TO_KITCHEN $\to$ PREPARING $\to$ SERVED $\to$ COMPLETED). A table cannot be vacated if a bill is unpaid.
  3. Smart Allocation (Best-Fit Table Search): A party of 2 should get a 2-seater table, not block an 8-seater table and cause revenue loss.
  4. Clean Decoupling: Decoupling food ordering from kitchen preparation and final payment settlement.

Step 1: Clarifying Requirements First (Thinking Out Loud)

Start the interview by engaging the interviewer to establish clear boundaries before writing classes.

The Live Dialogue:

Candidate: "Before jumping into class design, let me clarify the core operational scope of this restaurant:

  1. Dining Model: Are we focusing purely on Dine-in, or do we need Takeaway/Online delivery as well? (Let's prioritize Dine-in first).
  2. Table Allocation: Do tables have variable capacities (e.g. 2-seater, 4-seater, 6-seater), and should the system suggest the smallest suitable table for a party?
  3. Order Lifecycle & Kitchen: Can customers add items incrementally to an active table order? Does the kitchen get notified when an order is placed?
  4. Billing & Taxation: How are bills computed? Standard subtotal + tax (e.g., 5% GST)? Does paying the bill automatically free the table?
  5. Execution Scope: Should I write clean, in-memory domain logic and state transitions first?"

The Locked-In Requirements:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” Assign Table โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Customer โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€> โ”‚ Table Manager โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ (Assigned Table) โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” Take Order โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” KDS Route โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Waiter โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€> โ”‚ Order Service โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€> โ”‚ Kitchen โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” Settle Bill โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Billing Desk โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€> โ”‚ Table Freed โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  1. Table Management:

    • Tables have fixed capacities (2, 4, 6, or 8 seats) and states: AVAILABLE, OCCUPIED, RESERVED.
    • Best-Fit Heuristic: When a party of $N$ arrives, assign the smallest available table where $\text{capacity} \ge N$ to prevent capacity waste.
  2. Menu & Order Ingestion:

    • Menu holds items categorized as STARTER, MAIN_COURSE, BEVERAGE, DESSERT.
    • Items track real-time inventory availability (isAvailable).
    • An active table can place multiple rounds of orders (e.g., starters first, main course later).
  3. Kitchen Routing & Order Lifecycle:

    • Orders route to the Kitchen Display System (KDS).
    • States: CREATED $\to$ PREPARING $\to$ SERVED $\to$ COMPLETED.
  4. Billing & Settlement:

    • Generate itemized bill: Food Subtotal + 5% GST tax.
    • Bill states: UNPAID $\to$ PAID.
    • Once payment is verified, the associated table is automatically reset to AVAILABLE.

Step 2: Core Entities & Key Attributes

Here is how we map restaurant domain concepts into clean C++ classes:

1. MenuItem

  • Attributes:
    • itemId (string), name (string), price (double).
    • category (ItemCategory enum: STARTER, MAIN_COURSE, DESSERT, BEVERAGE).
    • isAvailable (bool): Out-of-stock guard.
  • Responsibility: Represents a single dish on the restaurant menu.

2. Table

  • Attributes:
    • tableId (int), capacity (int).
    • status (TableStatus enum: AVAILABLE, OCCUPIED, RESERVED).
  • Responsibility: Manages physical dining seating and occupancy.

3. OrderItem

  • Attributes:
    • item (MenuItem*), quantity (int).
  • Responsibility: Pairs a menu dish with an ordered count.

4. Order

  • Attributes:
    • orderId (string), tableId (int), waiterName (string).
    • items (vector<OrderItem>).
    • status (OrderStatus enum: CREATED, PREPARING, SERVED, COMPLETED, CANCELLED).
  • Responsibility: Represents an active batch of items ordered for a table.

5. Bill

  • Attributes:
    • billId (string), tableId (int), orderId (string).
    • subtotal (double), tax (double), totalAmount (double).
    • isPaid (bool).
  • Responsibility: Computes financial totals and tracks payment settlement.

6. Restaurant (Orchestrator / Facade)

  • Attributes:
    • tables (vector<Table*>), menu (map<string, MenuItem*>).
    • activeOrders (map<int, Order*>): Active orders keyed by tableId.
    • bills (map<string, Bill*>).
    • orderCounter (int), billCounter (int).
  • Responsibility: Tying table allocation, order intake, kitchen progress, and billing into a unified system.

Step 3: Class Relationships & Architecture

classDiagram class MenuItem { +string itemId +string name +double price +ItemCategory category +bool isAvailable } class OrderItem { +MenuItem* item +int quantity +double getTotalPrice() double } class Table { +int tableId +int capacity +TableStatus status +occupy() void +vacate() void } class Order { +string orderId +int tableId +string waiterName +vector~OrderItem~ items +OrderStatus status +addItem(MenuItem*, int) void +calculateSubtotal() double } class Bill { +string billId +int tableId +string orderId +double subtotal +double tax +double totalAmount +bool isPaid +markPaid() void } class Restaurant { -vector~Table*~ tables -map~string, MenuItem*~ menu -map~int, Order*~ activeOrders -map~string, Bill*~ bills +findBestFitTable(int) Table* +createOrder(int, string) Order* +addItemToOrder(int, string, int) bool +sendToKitchen(int) void +serveOrder(int) void +generateBill(int) Bill* +settleBill(string, string) bool } OrderItem --> MenuItem Order "1" *-- "many" OrderItem Restaurant "1" *-- "many" Table Restaurant "1" *-- "many" MenuItem Restaurant "1" *-- "many" Order Restaurant ..> Bill

Step 4: Walking Through Core Methods in Plain Language

1. findBestFitTable(int partySize)

When guests arrive: 1. Initialize candidateTable = nullptr. 2. Loop through all tables: - If table->status == AVAILABLE and table->capacity >= partySize: * If candidateTable == nullptr OR table->capacity < candidateTable->capacity: - candidateTable = table (Greedily picks smallest capacity that fits!) 3. If candidateTable found: - candidateTable->occupy() (status becomes OCCUPIED). - Return candidateTable. 4. If none found -> Return nullptr ("Restaurant full or no table large enough").

2. addItemToOrder(int tableId, string itemId, int quantity)

When waiter keys in a dish: 1. Lookup table in activeOrders map. 2. Verify item exists in menu and item->isAvailable == true. - If false -> REJECT: "Dish currently 86'd / out of stock". 3. If order is already COMPLETED or CANCELLED -> REJECT. 4. Append OrderItem(item, quantity) to order->items list.

3. sendToKitchen(int tableId) & serveOrder(int tableId)

Order State Pipeline: 1. sendToKitchen(): Transitions order->status from CREATED to PREPARING. - Kitchen Display Screen updates to show the chef the active ticket. 2. serveOrder(): Chef completes preparation, waiter delivers dishes to table. - Transitions order->status from PREPARING to SERVED.

4. generateBill(int tableId) & settleBill(string billId, string paymentMode)

Checkout & Table Release: 1. generateBill(): - Sum order subtotal = sum of (item.price * item.quantity). - Calculate 5% GST tax = subtotal * 0.05. - Total amount = subtotal + tax. - Create Bill object, mark as UNPAID. 2. settleBill(): - Mark bill as PAID. - Lookup associated table and call table->vacate() (status becomes AVAILABLE). - Remove table from activeOrders map. - Table is now immediately ready for new incoming diners!

Step 5: Explicit Edge Cases & How We Handle Them

Volunteer these scenarios during your Juspay interview:

1. The Table Waste Problem (Greedy Best-Fit vs. Random Table)

  • Problem: A couple (2 people) walks in. A naive system picks the first available table, assigning them an 8-seater. Minutes later, a family of 7 arrives and gets turned away because the 8-seater is blocked by 2 people.
  • Our Solution: findBestFitTable() iterates through all tables and picks the table with the minimum capacity that satisfies capacity >= partySize. A party of 2 gets a 2-seater or 4-seater first, preserving 8-seaters for large parties.

2. Ordering Out-of-Stock (86'd) Items

  • Problem: Kitchen runs out of Paneer Tikka mid-evening. A waiter inputs an order for it.
  • Our Solution: Every MenuItem has an isAvailable boolean. addItemToOrder() validates this flag before allowing the item onto a ticket, throwing a graceful error if unavailable.

3. Billing an Empty or In-Progress Order

  • Problem: A customer asks for the bill before any food has been ordered or while dishes are still being added.
  • Our Solution: generateBill() verifies that an active order exists and contains at least 1 item. If the order is empty, bill generation is blocked.

4. Premature Table Release

  • Problem: Waiter clears the table while payment is still pending.
  • Our Solution: table->vacate() is only triggered inside settleBill() after payment confirmation is validated. The table cannot be reassigned while an unpaid bill exists.

5. Incremental Ordering (Ordering More Dishes Mid-Meal)

  • Problem: Diners order starters first, then 30 minutes later order main courses on the same table.
  • Our Solution: The active order remains open and bound to tableId. Waiters can call addItemToOrder() multiple times throughout the dining session before requesting the final bill.

Step 6: Design Choices & Natural Justifications

[!IMPORTANT] Juspay Interview Tip: Do NOT force GoF pattern names like "I used the State Pattern". Explain the mechanical reasons behind your design.

1. Why decouple Bill from Order?

  • Live Reasoning:
    "An Order represents kitchen preparation and culinary fulfillment (what dishes are cooked and served). A Bill represents financial accounting (tax calculations, service charges, payment settlement, and discounts). Keeping them as distinct classes satisfies Single Responsibility and lets accounting rules change without touching kitchen ticket logic."

2. Why store activeOrders by tableId in the Restaurant facade?

  • Live Reasoning:
    "In a physical restaurant, staff identify customers by their table number ('Table 4 wants more bread', 'Table 2 requested the bill'). Keying active orders by tableId gives $O(1)$ fast lookups for both waiters and billing counters."

3. Why encapsulate Table Status as an explicit State Machine?

  • Live Reasoning:
    "A table's lifecycle has strict physical invariants: it can only transition from AVAILABLE $\to$ OCCUPIED upon seating, and from OCCUPIED $\to$ AVAILABLE upon bill settlement. Managing this via explicit status enums prevents ghost tables and overbooking."

Step 7: Extensibility Without Breaking Existing Code

  1. Takeaway & Online Delivery (Swiggy / Zomato Integration):

    • Create an OrderType enum (DINE_IN, TAKEAWAY, DELIVERY).
    • For TAKEAWAY, tableId can be set to 0 or null, and delivery address attached.
    • Kitchen KDS and billing work identically without rewriting order logic.
  2. Loyalty Discounts & Happy Hour Offers:

    • Add a DiscountCalculator class that applies 10% off on food subtotal during off-peak hours (e.g. 3 PM to 6 PM).
  3. Split Billing:

    • Enhance Bill to support splitting by guest count ($N$ equal shares) or splitting by itemized dishes.

Step 8: Complete, Working C++ Real-World Simulation

Here is the clean, complete C++ implementation (no smart pointers, no mutexes, simple raw pointers):

#include <iostream> #include <string> #include <vector> #include <map> #include <iomanip> using namespace std; // ============================================================================ // 1. DOMAIN ENUMS & TYPES // ============================================================================ enum class ItemCategory { STARTER, MAIN_COURSE, DESSERT, BEVERAGE }; enum class TableStatus { AVAILABLE, OCCUPIED, RESERVED }; enum class OrderStatus { CREATED, PREPARING, SERVED, COMPLETED, CANCELLED }; string categoryToString(ItemCategory cat) { switch (cat) { case ItemCategory::STARTER: return "Starter"; case ItemCategory::MAIN_COURSE: return "Main Course"; case ItemCategory::DESSERT: return "Dessert"; case ItemCategory::BEVERAGE: return "Beverage"; default: return "Unknown"; } } string orderStatusToString(OrderStatus status) { switch (status) { case OrderStatus::CREATED: return "CREATED"; case OrderStatus::PREPARING: return "PREPARING (In Kitchen)"; case OrderStatus::SERVED: return "SERVED (On Table)"; case OrderStatus::COMPLETED: return "COMPLETED"; case OrderStatus::CANCELLED: return "CANCELLED"; default: return "UNKNOWN"; } } // ============================================================================ // 2. MENU ITEM // ============================================================================ class MenuItem { public: string itemId; string name; double price; ItemCategory category; bool isAvailable; MenuItem(string id, string n, double p, ItemCategory cat, bool available = true) { itemId = id; name = n; price = p; category = cat; isAvailable = available; } }; // ============================================================================ // 3. TABLE // ============================================================================ class Table { public: int tableId; int capacity; TableStatus status; Table(int id, int cap) { tableId = id; capacity = cap; status = TableStatus::AVAILABLE; } void occupy() { status = TableStatus::OCCUPIED; } void vacate() { status = TableStatus::AVAILABLE; } }; // ============================================================================ // 4. ORDER ITEM & ORDER // ============================================================================ class OrderItem { public: MenuItem* item; int quantity; OrderItem(MenuItem* itm, int qty) { item = itm; quantity = qty; } double getTotalPrice() const { return item->price * quantity; } }; class Order { public: string orderId; int tableId; string waiterName; vector<OrderItem> items; OrderStatus status; Order(string oId, int tId, string waiter) { orderId = oId; tableId = tId; waiterName = waiter; status = OrderStatus::CREATED; } void addItem(MenuItem* item, int quantity) { items.push_back(OrderItem(item, quantity)); } double calculateSubtotal() const { double total = 0.0; for (const auto& orderItem : items) { total += orderItem.getTotalPrice(); } return total; } }; // ============================================================================ // 5. BILL & SETTLEMENT // ============================================================================ class Bill { public: string billId; int tableId; string orderId; double subtotal; double tax; // 5% GST double totalAmount; bool isPaid; string paymentMode; Bill(string bId, int tId, string oId, double sub) { billId = bId; tableId = tId; orderId = oId; subtotal = sub; tax = subtotal * 0.05; // 5% GST totalAmount = subtotal + tax; isPaid = false; paymentMode = "PENDING"; } void markPaid(string mode) { isPaid = true; paymentMode = mode; } void print() const { cout << " โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n" << " โ”‚ ๐Ÿงพ BILL RECEIPT: " << billId << " | Table: T-" << tableId << "\n" << " โ”‚ Subtotal: โ‚น" << fixed << setprecision(2) << subtotal << "\n" << " โ”‚ GST (5%): โ‚น" << fixed << setprecision(2) << tax << "\n" << " โ”‚ -----------------------------------------------------------\n" << " โ”‚ Total Due: โ‚น" << fixed << setprecision(2) << totalAmount << "\n" << " โ”‚ Status: " << (isPaid ? "PAID via " + paymentMode : "UNPAID") << "\n" << " โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n"; } }; // ============================================================================ // 6. RESTAURANT SYSTEM FACADE // ============================================================================ class Restaurant { private: string name; vector<Table*> tables; map<string, MenuItem*> menu; map<int, Order*> activeOrders; // tableId -> Order* map<string, Bill*> bills; // billId -> Bill* int orderCounter; int billCounter; public: Restaurant(string restName) { name = restName; orderCounter = 100; billCounter = 500; } ~Restaurant() { for (auto t : tables) delete t; for (auto& pair : menu) delete pair.second; for (auto& pair : activeOrders) delete pair.second; for (auto& pair : bills) delete pair.second; } void addTable(int tableId, int capacity) { tables.push_back(new Table(tableId, capacity)); } void addMenuItem(string id, string name, double price, ItemCategory cat, bool available = true) { menu[id] = new MenuItem(id, name, price, cat, available); } // Best-Fit Table Selection Heuristic Table* assignTable(int partySize) { cout << "\n๐Ÿ›Ž๏ธ [TABLE REQUEST] Party of " << partySize << " arrived. Searching optimal table...\n"; Table* bestFit = nullptr; for (auto table : tables) { if (table->status == TableStatus::AVAILABLE && table->capacity >= partySize) { if (bestFit == nullptr || table->capacity < bestFit->capacity) { bestFit = table; // Greedily find smallest capacity that fits } } } if (bestFit == nullptr) { cout << " โŒ [ALLOCATION FAILED] No available table can accommodate " << partySize << " guests!\n"; return nullptr; } bestFit->occupy(); cout << " โœ… [TABLE ASSIGNED] Table T-" << bestFit->tableId << " (" << bestFit->capacity << "-Seater) assigned to Party of " << partySize << ".\n"; return bestFit; } Order* createOrder(int tableId, string waiterName) { string orderId = "ORD-" + to_string(++orderCounter); Order* order = new Order(orderId, tableId, waiterName); activeOrders[tableId] = order; cout << " ๐Ÿ“‹ [ORDER INITIALIZED] Order " << orderId << " started for Table T-" << tableId << " by Waiter " << waiterName << ".\n"; return order; } bool addItemToOrder(int tableId, string itemId, int quantity) { if (activeOrders.find(tableId) == activeOrders.end()) { cout << " โŒ [ORDER ERROR] No active order found for Table T-" << tableId << "!\n"; return false; } if (menu.find(itemId) == menu.end()) { cout << " โŒ [MENU ERROR] Item " << itemId << " does not exist!\n"; return false; } MenuItem* menuItem = menu[itemId]; if (!menuItem->isAvailable) { cout << " โ›” [OUT OF STOCK] " << menuItem->name << " is currently unavailable!\n"; return false; } activeOrders[tableId]->addItem(menuItem, quantity); cout << " โž• [ITEM ADDED] " << quantity << "x " << menuItem->name << " (@ โ‚น" << menuItem->price << ") added to Table T-" << tableId << ".\n"; return true; } void sendToKitchen(int tableId) { if (activeOrders.find(tableId) == activeOrders.end()) return; Order* order = activeOrders[tableId]; order->status = OrderStatus::PREPARING; cout << "\n๐Ÿ‘จโ€๐Ÿณ [KITCHEN ROUTED] Order " << order->orderId << " for Table T-" << tableId << " is now " << orderStatusToString(order->status) << ".\n"; } void serveOrder(int tableId) { if (activeOrders.find(tableId) == activeOrders.end()) return; Order* order = activeOrders[tableId]; order->status = OrderStatus::SERVED; cout << "๐Ÿฝ๏ธ [ORDER SERVED] Order " << order->orderId << " delivered to Table T-" << tableId << " (" << orderStatusToString(order->status) << ").\n"; } Bill* generateBill(int tableId) { if (activeOrders.find(tableId) == activeOrders.end()) { cout << " โŒ [BILL ERROR] No active order on Table T-" << tableId << "!\n"; return nullptr; } Order* order = activeOrders[tableId]; double subtotal = order->calculateSubtotal(); string billId = "BILL-" + to_string(++billCounter); Bill* bill = new Bill(billId, tableId, order->orderId, subtotal); bills[billId] = bill; cout << "\n๐Ÿ’ฐ [BILL GENERATED] Bill " << billId << " created for Table T-" << tableId << ".\n"; bill->print(); return bill; } bool settleBill(string billId, string paymentMethod) { if (bills.find(billId) == bills.end()) { cout << " โŒ [PAYMENT ERROR] Invalid Bill ID " << billId << "!\n"; return false; } Bill* bill = bills[billId]; bill->markPaid(paymentMethod); // Release physical table for (auto table : tables) { if (table->tableId == bill->tableId) { table->vacate(); cout << "๐Ÿ”“ [TABLE VACATED] Table T-" << table->tableId << " is now AVAILABLE for next guests.\n"; break; } } // Clean up active order activeOrders.erase(bill->tableId); cout << "โœ… [PAYMENT SETTLED] Bill " << billId << " settled via " << paymentMethod << ". Dining session finished!\n"; return true; } void printTableStatus() const { cout << "\n========================================================\n"; cout << "๐Ÿ“Š LIVE RESTAURANT TABLE OVERVIEW: " << name << "\n"; cout << "========================================================\n"; for (auto t : tables) { cout << "Table T-" << t->tableId << " [" << t->capacity << "-Seater] -> " << (t->status == TableStatus::AVAILABLE ? "๐ŸŸข AVAILABLE" : "๐Ÿ”ด OCCUPIED") << "\n"; } cout << "========================================================\n"; } }; // ============================================================================ // 7. REAL-WORLD SIMULATION (MAIN) // ============================================================================ int main() { cout << "==================================================================\n"; cout << "๐Ÿฝ๏ธ RESTAURANT MANAGEMENT SYSTEM - REAL-WORLD SIMULATION\n"; cout << "==================================================================\n"; Restaurant royalSpice("Royal Spice Fine Dine"); // 1. Setup Tables: 2-seaters, 4-seaters, 6-seaters, 8-seaters royalSpice.addTable(1, 2); royalSpice.addTable(2, 2); royalSpice.addTable(3, 4); royalSpice.addTable(4, 6); royalSpice.addTable(5, 8); // 2. Setup Menu royalSpice.addMenuItem("M01", "Paneer Butter Masala", 320.0, ItemCategory::MAIN_COURSE, true); royalSpice.addMenuItem("M02", "Garlic Naan", 60.0, ItemCategory::MAIN_COURSE, true); royalSpice.addMenuItem("M03", "Crispy Corn", 220.0, ItemCategory::STARTER, true); royalSpice.addMenuItem("M04", "Gulab Jamun", 110.0, ItemCategory::DESSERT, true); royalSpice.addMenuItem("M05", "Special Tandoori Platter", 550.0, ItemCategory::STARTER, false); // OUT OF STOCK royalSpice.printTableStatus(); // ------------------------------------------------------------- // SCENARIO 1: Best-Fit Table Allocation (Party of 2) // Should get Table T-1 or T-2 (2-seater), NOT Table T-5 (8-seater) // ------------------------------------------------------------- Table* t1 = royalSpice.assignTable(2); // ------------------------------------------------------------- // SCENARIO 2: Taking Order & Stock Verification // ------------------------------------------------------------- royalSpice.createOrder(t1->tableId, "Ramesh (Waiter)"); royalSpice.addItemToOrder(t1->tableId, "M03", 1); // 1x Crispy Corn royalSpice.addItemToOrder(t1->tableId, "M01", 1); // 1x Paneer Butter Masala royalSpice.addItemToOrder(t1->tableId, "M02", 3); // 3x Garlic Naan // Try ordering out-of-stock item cout << "\n--- Testing Out-of-Stock Item Rejection ---"; royalSpice.addItemToOrder(t1->tableId, "M05", 1); // Platter (isAvailable = false) // ------------------------------------------------------------- // SCENARIO 3: Kitchen KDS Pipeline (Preparing -> Served) // ------------------------------------------------------------- royalSpice.sendToKitchen(t1->tableId); royalSpice.serveOrder(t1->tableId); // ------------------------------------------------------------- // SCENARIO 4: Billing & Table Vacation // ------------------------------------------------------------- Bill* billT1 = royalSpice.generateBill(t1->tableId); royalSpice.settleBill(billT1->billId, "UPI (GooglePay)"); royalSpice.printTableStatus(); // ------------------------------------------------------------- // SCENARIO 5: Large Party Allocation Test (Party of 7) // Should select Table T-5 (8-seater) // ------------------------------------------------------------- Table* tLarge = royalSpice.assignTable(7); royalSpice.createOrder(tLarge->tableId, "Suresh (Waiter)"); royalSpice.addItemToOrder(tLarge->tableId, "M01", 3); // 3x Paneer royalSpice.addItemToOrder(tLarge->tableId, "M02", 8); // 8x Naan royalSpice.addItemToOrder(tLarge->tableId, "M04", 4); // 4x Gulab Jamun royalSpice.sendToKitchen(tLarge->tableId); royalSpice.serveOrder(tLarge->tableId); Bill* billLarge = royalSpice.generateBill(tLarge->tableId); royalSpice.settleBill(billLarge->billId, "CREDIT_CARD"); royalSpice.printTableStatus(); return 0; }

๐Ÿ–ฅ๏ธ Expected Simulation Output Walkthrough

================================================================== ๐Ÿฝ๏ธ RESTAURANT MANAGEMENT SYSTEM - REAL-WORLD SIMULATION ================================================================== ======================================================== ๐Ÿ“Š LIVE RESTAURANT TABLE OVERVIEW: Royal Spice Fine Dine ======================================================== Table T-1 [2-Seater] -> ๐ŸŸข AVAILABLE Table T-2 [2-Seater] -> ๐ŸŸข AVAILABLE Table T-3 [4-Seater] -> ๐ŸŸข AVAILABLE Table T-4 [6-Seater] -> ๐ŸŸข AVAILABLE Table T-5 [8-Seater] -> ๐ŸŸข AVAILABLE ======================================================== ๐Ÿ›Ž๏ธ [TABLE REQUEST] Party of 2 arrived. Searching optimal table... โœ… [TABLE ASSIGNED] Table T-1 (2-Seater) assigned to Party of 2. ๐Ÿ“‹ [ORDER INITIALIZED] Order ORD-101 started for Table T-1 by Waiter Ramesh (Waiter). โž• [ITEM ADDED] 1x Crispy Corn (@ โ‚น220.00) added to Table T-1. โž• [ITEM ADDED] 1x Paneer Butter Masala (@ โ‚น320.00) added to Table T-1. โž• [ITEM ADDED] 3x Garlic Naan (@ โ‚น60.00) added to Table T-1. --- Testing Out-of-Stock Item Rejection --- โ›” [OUT OF STOCK] Special Tandoori Platter is currently unavailable! ๐Ÿ‘จโ€๐Ÿณ [KITCHEN ROUTED] Order ORD-101 for Table T-1 is now PREPARING (In Kitchen). ๐Ÿฝ๏ธ [ORDER SERVED] Order ORD-101 delivered to Table T-1 (SERVED (On Table)). ๐Ÿ’ฐ [BILL GENERATED] Bill BILL-501 created for Table T-1. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ ๐Ÿงพ BILL RECEIPT: BILL-501 | Table: T-1 โ”‚ Subtotal: โ‚น720.00 โ”‚ GST (5%): โ‚น36.00 โ”‚ ----------------------------------------------------------- โ”‚ Total Due: โ‚น756.00 โ”‚ Status: UNPAID โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๐Ÿ”“ [TABLE VACATED] Table T-1 is now AVAILABLE for next guests. โœ… [PAYMENT SETTLED] Bill BILL-501 settled via UPI (GooglePay). Dining session finished! ======================================================== ๐Ÿ“Š LIVE RESTAURANT TABLE OVERVIEW: Royal Spice Fine Dine ======================================================== Table T-1 [2-Seater] -> ๐ŸŸข AVAILABLE Table T-2 [2-Seater] -> ๐ŸŸข AVAILABLE Table T-3 [4-Seater] -> ๐ŸŸข AVAILABLE Table T-4 [6-Seater] -> ๐ŸŸข AVAILABLE Table T-5 [8-Seater] -> ๐ŸŸข AVAILABLE ======================================================== ๐Ÿ›Ž๏ธ [TABLE REQUEST] Party of 7 arrived. Searching optimal table... โœ… [TABLE ASSIGNED] Table T-5 (8-Seater) assigned to Party of 7. ๐Ÿ“‹ [ORDER INITIALIZED] Order ORD-102 started for Table T-5 by Waiter Suresh (Waiter). โž• [ITEM ADDED] 3x Paneer Butter Masala (@ โ‚น320.00) added to Table T-5. โž• [ITEM ADDED] 8x Garlic Naan (@ โ‚น60.00) added to Table T-5. โž• [ITEM ADDED] 4x Gulab Jamun (@ โ‚น110.00) added to Table T-5. ๐Ÿ‘จโ€๐Ÿณ [KITCHEN ROUTED] Order ORD-102 for Table T-5 is now PREPARING (In Kitchen). ๐Ÿฝ๏ธ [ORDER SERVED] Order ORD-102 delivered to Table T-5 (SERVED (On Table)). ๐Ÿ’ฐ [BILL GENERATED] Bill BILL-502 created for Table T-5. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ ๐Ÿงพ BILL RECEIPT: BILL-502 | Table: T-5 โ”‚ Subtotal: โ‚น1880.00 โ”‚ GST (5%): โ‚น94.00 โ”‚ ----------------------------------------------------------- โ”‚ Total Due: โ‚น1974.00 โ”‚ Status: UNPAID โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๐Ÿ”“ [TABLE VACATED] Table T-5 is now AVAILABLE for next guests. โœ… [PAYMENT SETTLED] Bill BILL-502 settled via CREDIT_CARD. Dining session finished! ======================================================== ๐Ÿ“Š LIVE RESTAURANT TABLE OVERVIEW: Royal Spice Fine Dine ======================================================== Table T-1 [2-Seater] -> ๐ŸŸข AVAILABLE Table T-2 [2-Seater] -> ๐ŸŸข AVAILABLE Table T-3 [4-Seater] -> ๐ŸŸข AVAILABLE Table T-4 [6-Seater] -> ๐ŸŸข AVAILABLE Table T-5 [8-Seater] -> ๐ŸŸข AVAILABLE ========================================================

๐ŸŽฏ Quick Cheat-Sheet for the Juspay Round

When wrapping up this solution with the interviewer, summarize with this 30-second closing pitch:

  1. Greedy Best-Fit Allocation: "We avoid revenue loss by allocating the smallest available table that satisfies party size (capacity >= partySize), preventing a couple from blocking an 8-seater table."
  2. Order Lifecycle Invariants: "Orders strictly progress through CREATED $\to$ PREPARING $\to$ SERVED $\to$ COMPLETED, keeping the Kitchen Display Screen and waiter in sync."
  3. Guarded Table Release: "A table can only be vacated once its bill has been settled (markPaid()), eliminating accidental unpaid walkouts."
  4. Clean OOP Boundaries: "Decoupling food fulfillment (Order) from financial auditing (Bill) satisfies Single Responsibility and makes adding discounts or takeaway orders seamless."