Implement delivery assignment flow, restaurant order handling, and new controller helpers

- Add new Controller helper getDeliveryStatusString()
- Add new Controller helper pickAssignmentFromDeliveryAssignments()
- Implement controller listRestaurantOrders()
- Implement controller markOrderReady()
- Add order to restaurant when customer places order
- Add m_assignments attribute to Controller
- Implement controller listDeliveryAssignments()
- Implement controller acceptDeliveryAssignments()
- Implement controller confirmDeliveryAssignments()
This commit is contained in:
Joel Thomas
2026-02-21 13:26:37 +05:30
parent 813f236172
commit 6f12328ed5
2 changed files with 300 additions and 4 deletions
@@ -15,6 +15,9 @@ Date: 19-02-2026
#include "Customer.h" #include "Customer.h"
#include "DeliveryPartner.h" #include "DeliveryPartner.h"
#include "Restaurant.h" #include "Restaurant.h"
#include "MenuItem.h"
#include "Order.h"
#include "DeliveryAssignment.h"
#include "inputHelper.h" #include "inputHelper.h"
#include "outputHelper.h" #include "outputHelper.h"
@@ -161,6 +164,65 @@ static orders::iterator pickOrderFromOrders(orders& userOrders)
return orderIterator; return orderIterator;
} }
static std::string getDeliveryStatusString(const DeliveryStatus& deliveryStatus)
{
switch (deliveryStatus)
{
case DeliveryStatus::CREATED:
return "Created";
case DeliveryStatus::ACCEPTED:
return "Accepted";
case DeliveryStatus::DELIVERED:
return "Delivered";
default:
return "Unkown";
}
}
static deliveryAssignments::iterator pickAssignmentFromDeliveryAssignments(deliveryAssignments& assignments, const users& allUsers)
{
util::clear();
std::cout << "Pick a Delivery Assignment\n";
int deliveryIndex = 1, deliveryChoiceIndex;
if (assignments.empty())
{
std::cout << "No Delivery Assignments available at the moment!\n";
return assignments.end();
}
std::cout << std::left << std::setw(8) << "Index"
<< std::left << std::setw(5) << "ID"
<< std::left << std::setw(12) << "Order ID"
<< std::left << std::setw(22) << "Delivery Status"
<< std::left << std::setw(30) << "Address"
<< "\n";
for (auto& assignment : assignments)
{
Order& order = assignment.second->getOrder();
users::const_iterator customer = allUsers.find(order.getCustomerUsername());
if (customer == allUsers.end())
{
throw std::runtime_error("Invalid state: Delivery Assignment has no associated Customer.");
}
std::cout << std::left << std::setw(8) << deliveryIndex
<< std::left << std::setw(5) << assignment.second->getId()
<< std::left << std::setw(12) << order.getId()
<< std::left << std::setw(22) << getDeliveryStatusString(assignment.second->getStatus())
<< std::left << std::setw(30) << customer->second->getAddress()
<< "\n";
deliveryIndex++;
}
std::cout << "\nSelect Index: ";
util::readValue<int>(deliveryChoiceIndex);
deliveryChoiceIndex--;
if (deliveryChoiceIndex < 0 || deliveryChoiceIndex >= assignments.size())
{
return assignments.end();
}
deliveryAssignments::iterator assignmentIterator = assignments.begin();
std::advance(assignmentIterator, deliveryChoiceIndex);
return assignmentIterator;
}
void FoodDeliveryController::run() void FoodDeliveryController::run()
{ {
bool isMenuActive = true; bool isMenuActive = true;
@@ -393,12 +455,118 @@ void FoodDeliveryController::updateRestaurantStatus() const
void FoodDeliveryController::listRestaurantOrders() const void FoodDeliveryController::listRestaurantOrders() const
{ {
try
{
util::clear();
if (!checkAccess(m_authenticatedUser, "RestaurantOwner"))
{
return;
}
RestaurantOwner& restaurantOwner = *(std::dynamic_pointer_cast<RestaurantOwner>(m_authenticatedUser));
restaurants::iterator restaurantIterator = pickRestaurantFromRestaurants(restaurantOwner.getRestaurants());
if (restaurantIterator != restaurantOwner.getRestaurants().end())
{
orders& restaurantOrders = restaurantIterator->second->getOrders();
if (restaurantOrders.empty())
{
std::cout << "Restaurant " << restaurantIterator->second->getName() << " has no orders!\n";
return;
}
orders::iterator orderIterator = pickOrderFromOrders(restaurantOrders);
if (orderIterator != restaurantOrders.end())
{
util::clear();
items& orderItems = orderIterator->second->getItems();
if (orderItems.empty())
{
throw std::runtime_error("Order has no items!");
}
std::cout << "Order " << orderIterator->second->getId() << "\n";
std::cout << std::left << std::setw(25) << "Menu Item"
<< std::left << std::setw(10) << "Price"
<< std::left << std::setw(10) << "Quantity"
<< std::left << std::setw(10) << "Total Cost"
<< "\n";
for (auto& item : orderItems)
{
MenuItem& menuItem = item->getMenuItem();
std::cout << std::left << std::setw(25) << menuItem.getName()
<< std::left << std::setw(10) << menuItem.getPrice()
<< std::left << std::setw(10) << item->getQuantity()
<< std::left << std::setw(10) << menuItem.getPrice() * item->getQuantity()
<< "\n";
}
std::cout << "\nNet Cost : " << orderIterator->second->getTotal() << "\n";
std::cout << "Status : " << getOrderStatusString(orderIterator->second->getStatus()) << "\n";
}
else
{
std::cout << "Invalid Index. Cannot display Restaurant Orders\n";
}
}
else if (!restaurantOwner.getRestaurants().empty())
{
std::cout << "Invalid Index. Cannot display Restaurant Orders\n";
return;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
} }
void FoodDeliveryController::markOrderReady() void FoodDeliveryController::markOrderReady()
{ {
try
{
util::clear();
if (!checkAccess(m_authenticatedUser, "RestaurantOwner"))
{
return;
}
RestaurantOwner& restaurantOwner = *(std::dynamic_pointer_cast<RestaurantOwner>(m_authenticatedUser));
restaurants::iterator restaurantIterator = pickRestaurantFromRestaurants(restaurantOwner.getRestaurants());
if (restaurantIterator != restaurantOwner.getRestaurants().end())
{
orders& restaurantOrders = restaurantIterator->second->getOrders();
if (restaurantOrders.empty())
{
std::cout << "Restaurant " << restaurantIterator->second->getName() << " has no orders!\n";
return;
}
orders::iterator orderIterator = pickOrderFromOrders(restaurantOrders);
if (orderIterator != restaurantOrders.end())
{
OrderStatus orderStatus = orderIterator->second->getStatus();
if (orderStatus == OrderStatus::CREATED)
{
orderIterator->second->setStatus(OrderStatus::READYFORPICKUP);
std::shared_ptr<DeliveryAssignment> deliveryAssignment = std::make_shared<DeliveryAssignment>(*orderIterator->second);
m_assignments[deliveryAssignment->getId()] = deliveryAssignment;
std::cout << "Order has been marked ready for pickup\n";
}
else
{
std::cout << "Cannot mark order ready for pickup. Order has already been cancelled, is in transit, or is already marked ready for pickup, or has been delivered!\n";
return;
}
}
else
{
std::cout << "Invalid Index. Cannot mark order ready for pickup!\n";
}
}
else if (!restaurantOwner.getRestaurants().empty())
{
std::cout << "Invalid Index. Cannot mark order ready for pickup!\n";
return;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
} }
void FoodDeliveryController::listMenuItems() const void FoodDeliveryController::listMenuItems() const
@@ -651,6 +819,7 @@ void FoodDeliveryController::placeOrder()
if (order && !order->getItems().empty()) if (order && !order->getItems().empty())
{ {
customer->addOrder(order); customer->addOrder(order);
restaurantIterator->second->addOrder(order);
std::cout << "Order with ID " << order->getId() << " has been placed successfully\n"; std::cout << "Order with ID " << order->getId() << " has been placed successfully\n";
} }
else else
@@ -718,17 +887,141 @@ void FoodDeliveryController::cancelOrder() const
void FoodDeliveryController::listDeliveryAssignments() void FoodDeliveryController::listDeliveryAssignments()
{ {
try
{
util::clear();
if (!checkAccess(m_authenticatedUser, "DeliveryPartner"))
{
return;
}
auto deliveryPartner = std::dynamic_pointer_cast<DeliveryPartner>(m_authenticatedUser);
if (!deliveryPartner)
{
throw std::runtime_error("Cannot accept Delivery Assignment. Failed to verify access!");
}
deliveryAssignments& assignments = deliveryPartner->getAssignedDeliveries();
if (assignments.empty())
{
std::cout << "You haven't accepted any Delivery Assignments!\n";
return;
}
std::cout << std::left << std::setw(5) << "ID"
<< std::left << std::setw(12) << "Order ID"
<< std::left << std::setw(22) << "Delivery Status"
<< std::left << std::setw(30) << "Address"
<< "\n";
for (auto& assignment : assignments)
{
Order& order = assignment.second->getOrder();
users::const_iterator customer = m_users.find(order.getCustomerUsername());
if (customer == m_users.end())
{
throw std::runtime_error("Invalid state: Delivery Assignment has no associated Customer.");
}
std::cout << std::left << std::setw(5) << assignment.second->getId()
<< std::left << std::setw(12) << order.getId()
<< std::left << std::setw(22) << getDeliveryStatusString(assignment.second->getStatus())
<< std::left << std::setw(30) << customer->second->getAddress()
<< "\n";
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
} }
void FoodDeliveryController::acceptDeliveryAssignment() void FoodDeliveryController::acceptDeliveryAssignment()
{ {
try
{
util::clear();
if (!checkAccess(m_authenticatedUser, "DeliveryPartner"))
{
return;
}
auto deliveryPartner = std::dynamic_pointer_cast<DeliveryPartner>(m_authenticatedUser);
if (!deliveryPartner)
{
throw std::runtime_error("Cannot accept Delivery Assignment. Failed to verify access!");
}
if (m_assignments.empty())
{
std::cout << "No Delivery Assignments available at the moment!\n";
return;
}
deliveryAssignments::iterator assignmentIterator = pickAssignmentFromDeliveryAssignments(m_assignments, m_users);
if (assignmentIterator != m_assignments.end())
{
DeliveryStatus deliveryStatus = assignmentIterator->second->getStatus();
if (deliveryStatus == DeliveryStatus::CREATED)
{
assignmentIterator->second->setStatus(DeliveryStatus::ACCEPTED);
assignmentIterator->second->getOrder().setStatus(OrderStatus::OUTFORDELIVERY);
deliveryPartner->acceptDeliveryAssignment(assignmentIterator->second);
std::cout << "Delivery Assignment " << assignmentIterator->second->getId() << " has been accepted successfully!\n";
}
else
{
std::cout << "Delivery Assignment " << assignmentIterator->second->getId() << " cannot be accepted as it is already accepted, or delivered!\n";
}
}
else
{
std::cout << "Invalid Index. Cannot accept Delivery Assignment!\n";
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
} }
void FoodDeliveryController::confirmDeliveryAssignment() void FoodDeliveryController::confirmDeliveryAssignment()
{ {
try
{
util::clear();
if (!checkAccess(m_authenticatedUser, "DeliveryPartner"))
{
return;
}
auto deliveryPartner = std::dynamic_pointer_cast<DeliveryPartner>(m_authenticatedUser);
if (!deliveryPartner)
{
throw std::runtime_error("Cannot confirm Delivery Assignment. Failed to verify access!");
}
deliveryAssignments& assignments = deliveryPartner->getAssignedDeliveries();
if (assignments.empty())
{
std::cout << "You haven't accepted any Delivery Assignments!\n";
return;
}
deliveryAssignments::iterator assignmentIterator = pickAssignmentFromDeliveryAssignments(assignments, m_users);
if (assignmentIterator != assignments.end())
{
DeliveryStatus deliveryStatus = assignmentIterator->second->getStatus();
if (deliveryStatus == DeliveryStatus::ACCEPTED)
{
assignmentIterator->second->setStatus(DeliveryStatus::DELIVERED);
assignmentIterator->second->getOrder().setStatus(OrderStatus::DELIVERED);
std::cout << "Delivery Assignment " << assignmentIterator->second->getId() << " has been completed successfully!\n";
}
else
{
std::cout << "Delivery Assignment " << assignmentIterator->second->getId() << " cannot be confirmed as it has not been accepted yet, or has already been delivered!\n";
}
}
else
{
std::cout << "Invalid Index. Cannot confirm Delivery Assignment!\n";
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
}
} }
void FoodDeliveryController::viewProfile() const void FoodDeliveryController::viewProfile() const
@@ -14,12 +14,14 @@ class Restaurant;
class MenuItem; class MenuItem;
class Item; class Item;
class Order; class Order;
class DeliveryAssignment;
using users = std::map<std::string, std::shared_ptr<User>>; using users = std::map<std::string, std::shared_ptr<User>>;
using restaurants = std::map<int, std::shared_ptr<Restaurant>>; using restaurants = std::map<int, std::shared_ptr<Restaurant>>;
using menuItems = std::map<int, std::shared_ptr<MenuItem>>; using menuItems = std::map<int, std::shared_ptr<MenuItem>>;
using items = std::vector<std::shared_ptr<Item>>; using items = std::vector<std::shared_ptr<Item>>;
using orders = std::map<int, std::shared_ptr<Order>>; using orders = std::map<int, std::shared_ptr<Order>>;
using deliveryAssignments = std::map<int, std::shared_ptr<DeliveryAssignment>>;
class FoodDeliveryController class FoodDeliveryController
{ {
@@ -27,6 +29,7 @@ private:
users m_users; users m_users;
restaurants m_restaurants; restaurants m_restaurants;
orders m_orders; orders m_orders;
deliveryAssignments m_assignments;
std::shared_ptr<User> m_authenticatedUser; std::shared_ptr<User> m_authenticatedUser;
public: public:
void run(); void run();