๐ฝ๏ธ 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:
- Physical Entity Modeling: How cleanly you represent real-world restaurant objects (Tables of varied capacities, Menus, Orders, Kitchen display, Bills).
- 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. - 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.
- 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:
- Dining Model: Are we focusing purely on Dine-in, or do we need Takeaway/Online delivery as well? (Let's prioritize Dine-in first).
- 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?
- Order Lifecycle & Kitchen: Can customers add items incrementally to an active table order? Does the kitchen get notified when an order is placed?
- Billing & Taxation: How are bills computed? Standard subtotal + tax (e.g., 5% GST)? Does paying the bill automatically free the table?
- 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 โ
โโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ-
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.
- Tables have fixed capacities (2, 4, 6, or 8 seats) and states:
-
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).
- Menu holds items categorized as
-
Kitchen Routing & Order Lifecycle:
- Orders route to the Kitchen Display System (KDS).
- States:
CREATED$\to$PREPARING$\to$SERVED$\to$COMPLETED.
-
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(ItemCategoryenum: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(TableStatusenum: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(OrderStatusenum: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 bytableId.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 ..> BillStep 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 satisfiescapacity >= 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
MenuItemhas anisAvailableboolean.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 insidesettleBill()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 calladdItemToOrder()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:
"AnOrderrepresents kitchen preparation and culinary fulfillment (what dishes are cooked and served). ABillrepresents 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 bytableIdgives $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 fromAVAILABLE$\to$OCCUPIEDupon seating, and fromOCCUPIED$\to$AVAILABLEupon bill settlement. Managing this via explicit status enums prevents ghost tables and overbooking."
Step 7: Extensibility Without Breaking Existing Code
-
Takeaway & Online Delivery (Swiggy / Zomato Integration):
- Create an
OrderTypeenum (DINE_IN,TAKEAWAY,DELIVERY). - For
TAKEAWAY,tableIdcan be set to0ornull, and delivery address attached. - Kitchen KDS and billing work identically without rewriting order logic.
- Create an
-
Loyalty Discounts & Happy Hour Offers:
- Add a
DiscountCalculatorclass that applies 10% off on food subtotal during off-peak hours (e.g. 3 PM to 6 PM).
- Add a
-
Split Billing:
- Enhance
Billto support splitting by guest count ($N$ equal shares) or splitting by itemized dishes.
- Enhance
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:
- 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." - Order Lifecycle Invariants: "Orders strictly progress through
CREATED$\to$PREPARING$\to$SERVED$\to$COMPLETED, keeping the Kitchen Display Screen and waiter in sync." - Guarded Table Release: "A table can only be vacated once its bill has been settled (
markPaid()), eliminating accidental unpaid walkouts." - Clean OOP Boundaries: "Decoupling food fulfillment (
Order) from financial auditing (Bill) satisfies Single Responsibility and makes adding discounts or takeaway orders seamless."