Fix Cancel Service Booking Functionality

Changes:

- Added Controller::removeServiceBooking() with proper documentation and
  delegation to ServiceManagementService.
- Implemented ServiceManagementService::removeServiceBooking() to handle
  cancellation of pending bookings, enforce status validation, send
  notifications, and persist changes safely.
- Updated CustomerMenu to include a "Cancel Service Booking" option in
  the menu, wired it into handleOperation, and implemented
  CustomerMenu::cancelServiceBooking() for user interaction.
- Ensured consistent declarations in Controller.h,
  ServiceManagementService.h, and CustomerMenu.h.

Fixes #2105
This commit is contained in:
Jissin Mathew
2026-06-17 20:48:54 +05:30
parent bb0d186b62
commit b45463a66d
6 changed files with 128 additions and 11 deletions
@@ -234,6 +234,17 @@ void Controller::removeInventoryItem(const std::string& inventoryItemID)
m_inventoryManagementService.removeInventoryItem(inventoryItemID); m_inventoryManagementService.removeInventoryItem(inventoryItemID);
} }
/*
Function: removeServiceBooking
Description: Removes a service booking from the service management system by its booking ID.
Parameter: const std::string& bookingID - ID of the service booking
Return type: void
*/
void Controller::removeServiceBooking(const std::string& bookingID)
{
m_serviceManagementService.removeServiceBooking(bookingID);
}
/* /*
Function: addInventoryItemStock Function: addInventoryItemStock
Description: Adds stock to an existing inventory item in the inventory management service. Description: Adds stock to an existing inventory item in the inventory management service.
@@ -265,6 +276,7 @@ util::Map<std::string, const ServiceBooking*> Controller::getServiceBookings()
return readOnlyServiceBookings; return readOnlyServiceBookings;
} }
/* /*
Function: getServiceBookingsByUser Function: getServiceBookingsByUser
Description: Retrieves all service bookings for a specific user. Description: Retrieves all service bookings for a specific user.
@@ -58,6 +58,7 @@ public:
util::Map<std::string, const User*> getUsers(util::UserType userType); util::Map<std::string, const User*> getUsers(util::UserType userType);
void createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID); void createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID);
void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost); void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeServiceBooking(const std::string& bookingID);
void removeService(const std::string& serviceID); void removeService(const std::string& serviceID);
util::Map<std::string, const JobCard*> getJobCardsByUser(); util::Map<std::string, const JobCard*> getJobCardsByUser();
void updateJobStatus(const std::string& jobID); void updateJobStatus(const std::string& jobID);
@@ -26,7 +26,6 @@ Date:19-May-2026
#include "UserManagementService.h" #include "UserManagementService.h"
#include "DataStoreLockGuard.h" #include "DataStoreLockGuard.h"
#include "Utility.h" #include "Utility.h"
#include "DataStoreLockGuard.h"
#include "EventManager.h" #include "EventManager.h"
/* /*
@@ -595,6 +594,10 @@ void ServiceManagementService::createJobCard(const std::string& bookingID, const
DataStoreLockGuard lock(m_dataStore); DataStoreLockGuard lock(m_dataStore);
UserManagementService m_userManagementService; UserManagementService m_userManagementService;
ServiceBooking* currentBooking = getServiceBooking(bookingID); ServiceBooking* currentBooking = getServiceBooking(bookingID);
if (currentBooking->getStatus() == util::ServiceJobStatus::CANCELLED)
{
throw std::runtime_error("Cannot create job card. Service Booking was cancelled!");
}
auto& currentTrackedJobCards = m_dataStore.getJobCards(); auto& currentTrackedJobCards = m_dataStore.getJobCards();
auto& currentTrackedInventoryItems = m_dataStore.getInventoryItems(); auto& currentTrackedInventoryItems = m_dataStore.getInventoryItems();
auto& currentTrackedServiceBookings = m_dataStore.getServiceBookings(); auto& currentTrackedServiceBookings = m_dataStore.getServiceBookings();
@@ -789,6 +792,61 @@ void ServiceManagementService::removeService(const std::string& serviceID)
m_dataStore.saveComboPackages(); m_dataStore.saveComboPackages();
} }
/*
Function: removeServiceBooking
Description: Removes a pending service booking by its ID.
Cancels only if status is PENDING, otherwise throws exceptions
for invalid states. Sends notification to the customer and
persists changes.
Parameter: const std::string& bookingID - ID of the service booking
Return type: void
*/
void ServiceManagementService::removeServiceBooking(const std::string& bookingID)
{
DataStoreLockGuard lock(m_dataStore);
auto& trackedServiceBookings = m_dataStore.getServiceBookings();
bool serviceBookingRemoved = false;
for (int iterator = 0; iterator < trackedServiceBookings.getSize(); iterator++)
{
auto& currentTrackedServiceBooking = trackedServiceBookings.getValueAt(iterator);
ServiceBooking* currentServiceBooking = currentTrackedServiceBooking.data;
if (currentServiceBooking && currentServiceBooking->getId() == bookingID)
{
if (currentServiceBooking->getStatus() == util::ServiceJobStatus::PENDING)
{
const std::string title = "Service Booking cancelled.";
const std::string message = "Service Booking of id " + bookingID + " successfully cancelled.";
currentServiceBooking->setStatus(util::ServiceJobStatus::CANCELLED);
currentTrackedServiceBooking.state = RecordState::MODIFIED;
serviceBookingRemoved = true;
sendNotification(currentServiceBooking->getCustomer(), title, message);
break;
}
else if(currentServiceBooking->getStatus() == util::ServiceJobStatus::COMPLETED)
{
throw std::runtime_error("Unable to cancel completed service booking.");
}
else if (currentServiceBooking->getStatus() == util::ServiceJobStatus::STARTED)
{
throw std::runtime_error("Unable to cancel started service booking.");
}
else if (currentServiceBooking->getStatus() == util::ServiceJobStatus::IN_PROGRESS)
{
throw std::runtime_error("Unable to cancel currently Inprogress service booking.");
}
else
{
throw std::runtime_error("Service Booking already cancelled.");
}
}
}
if (!serviceBookingRemoved)
{
throw std::runtime_error("Unable to cancel service booking.");
}
m_dataStore.saveServiceBookings();
}
/* /*
Function: getServiceBookings (overloaded) Function: getServiceBookings (overloaded)
Description: Retrieves all service bookings for a specific customer. Description: Retrieves all service bookings for a specific customer.
@@ -35,6 +35,7 @@ public:
void createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID); void createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID);
void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost); void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID); void removeService(const std::string& serviceID);
void removeServiceBooking(const std::string& bookingID);
util::Map<std::string, JobCard*> getJobCards(const std::string& technicianID); util::Map<std::string, JobCard*> getJobCards(const std::string& technicianID);
void updateJobStatus(const std::string& jobID); void updateJobStatus(const std::string& jobID);
void cancelCustomerServiceBookings(const std::string& customerID); void cancelCustomerServiceBookings(const std::string& customerID);
@@ -51,11 +51,12 @@ void CustomerMenu::showMenu()
<< "\n3. Update Profile" << "\n3. Update Profile"
<< "\n4. Change Password" << "\n4. Change Password"
<< "\n5. View Service History" << "\n5. View Service History"
<< "\n6. Complete Payments" << "\n6. Cancel Service Booking"
<< "\n7. View Invoices" << "\n7. Complete Payments"
<< "\n8. View Notifications" << "\n8. View Invoices"
<< "\n9. Configure Notifications" << "\n9. View Notifications"
<< "\n10. Logout" << "\n10. Configure Notifications"
<< "\n11. Logout"
<< "\nEnter a choice: "; << "\nEnter a choice: ";
util::read(choice); util::read(choice);
if (!handleOperation(choice)) if (!handleOperation(choice))
@@ -103,18 +104,21 @@ bool CustomerMenu::handleOperation(int choice)
viewServiceHistory(); viewServiceHistory();
break; break;
case 6: case 6:
completePayments(); cancelServiceBooking();
break; break;
case 7: case 7:
viewInvoices(); completePayments();
break; break;
case 8: case 8:
viewNotifications(); viewInvoices();
break; break;
case 9: case 9:
configureNotifications(); viewNotifications();
break; break;
case 10: case 10:
configureNotifications();
break;
case 11:
logout(); logout();
return false; return false;
default: default:
@@ -327,6 +331,46 @@ void CustomerMenu::viewServiceHistory()
util::pressEnter(); util::pressEnter();
} }
/*
Function: cancelServiceBooking
Description: Allows the customer to cancel a pending service booking.
Displays the list of active bookings, lets the user select one,
and removes it from the system. If no bookings are available,
an appropriate message is shown.
Parameter: None
Return type: void
*/
void CustomerMenu::cancelServiceBooking()
{
util::clear();
std::cout << "Cancel Service Booking\n";
const User* currentUser = m_controller.getAuthenticatedUser();
std::string currentUserID = currentUser->getId();
util::Map<std::string, const ServiceBooking*> serviceBookingsByCurrentUser = m_controller.getServiceBookingsByUser(currentUserID);
util::Map<int, const ServiceBooking*> serviceBookingsMap;
auto currentPendingServiceBookings = filterActiveServiceBookings(serviceBookingsByCurrentUser);
int bookingsSize = currentPendingServiceBookings.getSize();
if (listServiceBookings(currentPendingServiceBookings, bookingsSize, serviceBookingsMap))
{
const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap);
if (selectedService)
{
m_controller.removeServiceBooking(selectedService->getId());
std::cout << "Cancelled Service booking of id " + selectedService->getId() << std::endl << std::endl;
}
else
{
std::cout << "Invalid service booking index.\n\n";
return;
}
}
else
{
std::cout << "No pending service bookings available.\n\n";
}
util::pressEnter();
}
/* /*
Function: completePayments Function: completePayments
Description: Allows the customer to complete pending payments for invoices. Description: Allows the customer to complete pending payments for invoices.
@@ -28,5 +28,6 @@ public:
void completePayments(); void completePayments();
void viewInvoices(); void viewInvoices();
void viewNotifications(); void viewNotifications();
void cancelServiceBooking();
void configureNotifications(); void configureNotifications();
}; };