From 859f7bbeaa44bea4db589b879cb6c8c449e4b95d Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Wed, 27 May 2026 13:25:11 +0530 Subject: [PATCH] Fix Customer Removal and Cancellation Handling Issues - Refactored customer and technician removal flow to ensure linked job cards and service bookings are properly cancelled. - Added inventory restoration logic to avoid duplicate restocking when cancelling bookings. - Introduced processBookingCancellation helper for consistent cancellation handling, notifications, and technician reassignment. - Updated UserManagementService::removeUser to invoke appropriate cancellation routines based on user type. - Ensured customer references and IDs are preserved correctly during booking cancellation. Fixes #1781 --- .../controllers/Controller.cpp | 4 +- .../services/ServiceManagementService.cpp | 231 ++++++++++++------ .../services/UserManagementService.cpp | 8 + 3 files changed, 164 insertions(+), 79 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index f1ca400..3b674ed 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp @@ -409,10 +409,8 @@ void Controller::removeUser(const std::string& userID) User* user = m_userManagementService.getUser(userID); if (!user) { - throw std::runtime_error("Error User not Found.\n"); + throw std::runtime_error("Error: User not Found.\n"); } - m_serviceManagementService.cancelCustomerServiceBookings(userID); - m_serviceManagementService.cancelTechnicianJobs(userID); m_userManagementService.removeUser(userID); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index b4fbc22..da45370 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -507,6 +507,89 @@ void ServiceManagementService::saveObservers() util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this); } +/* +Function: restoreInventory +Description: Restores inventory quantities for all required items in the services associated + with a given booking. Each item's quantity is incremented by a fixed value. +Parameter: ServiceBooking* booking - Pointer to the booking whose inventory items need to be restored +Return type: void +*/ +static void restoreInventory(ServiceBooking* booking) +{ + const int INCREMENT_VALUE = 1; + if (!booking) + { + return; + } + const auto& services = booking->getServices(); + for (int serviceIterator = 0; serviceIterator < services.getSize(); ++serviceIterator) + { + Service* service = services.getValueAt(serviceIterator); + if (!service) + { + continue; + } + const auto& items = service->getRequiredInventoryItems(); + for (int InventoryIterator = 0; InventoryIterator < items.getSize(); ++InventoryIterator) + { + InventoryItem* item = items.getValueAt(InventoryIterator); + if (item) + { + item->setQuantity(item->getQuantity() + INCREMENT_VALUE); + } + } + } +} + +/* +Function: processBookingCancellation +Description: Cancels jobs and updates the status of a given booking. Sends notifications to the + specified user, resets technician assignment if needed, and restores inventory items. +Parameter: ServiceBooking* booking - Pointer to the booking being cancelled + util::ServiceJobStatus newServiceBookingStatus - New status to assign to the booking + const std::string& notificationTitle - Title of the booking cancellation notification + const std::string& notificationMessage - Message body of the booking cancellation notification + User* notifyUser - User to notify about the cancellation + util::ServiceJobStatus jobCardStatus - New status to assign to associated job cards + const std::string& jobNotificationTitle - Title of the job cancellation notification + const std::string& jobNotificationMessage - Message body of the job cancellation notification + util::Map& jobs - Collection of job cards to update + ServiceManagementService& currentService - Reference to the service for sending notifications +Return type: void +*/ +static void processBookingCancellation(ServiceBooking* booking, + util::ServiceJobStatus newServiceBookingStatus, + const std::string& notificationTitle, + const std::string& notificationMessage, + User* notifyUser, + util::ServiceJobStatus jobCardStatus, + const std::string& jobNotificationTitle, + const std::string& jobNotificationMessage, + util::Map& jobs, ServiceManagementService& currentService) +{ + if (!booking || !notifyUser) + { + return; + } + for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator) + { + JobCard* jobCard = jobs.getValueAt(jobIterator); + if (jobCard && jobCard->getBookingId() == booking->getId()) + { + jobCard->setStatus(jobCardStatus); + currentService.sendNotification(notifyUser, jobNotificationTitle, jobNotificationMessage); + } + } + booking->setStatus(newServiceBookingStatus); + currentService.sendNotification(notifyUser, notificationTitle, notificationMessage); + if (newServiceBookingStatus == util::ServiceJobStatus::PENDING) + { + booking->setAssignedTechnician(nullptr); + booking->setAssignedTechnicianId(""); + } + restoreInventory(booking); +} + /* Function: cancelCustomerServiceBookings Description: Cancels all service bookings associated with a given customer or technician. @@ -515,69 +598,49 @@ Description: Cancels all service bookings associated with a given customer or te Parameter: const std::string& userID - ID of the customer or technician Return type: void */ -void ServiceManagementService::cancelCustomerServiceBookings(const std::string& userID) +void ServiceManagementService::cancelCustomerServiceBookings(const std::string& customerID) { const int INCREMENT_VALUE = 1; auto& users = m_dataStore.getUsers(); - int userIndex = users.find(userID); + int userIndex = users.find(customerID); if (userIndex == -1) { - throw std::runtime_error("User not found: " + userID); + throw std::runtime_error("User not found: " + customerID); } - User* user = users.getValueAt(userIndex); - if (user == nullptr) + User* customer = users.getValueAt(userIndex); + if (!customer) { - throw std::runtime_error("User not found: " + userID); + throw std::runtime_error("User not found: " + customerID); } - util::UserType type = user->getUserType(); - auto& bookings = DataStore::getInstance().getServiceBookings(); - for (int bookingIterator = 0; bookingIterator < bookings.getSize(); bookingIterator++) + auto& bookings = m_dataStore.getServiceBookings(); + auto& jobs = m_dataStore.getJobCards(); + for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++) { - ServiceBooking* booking = bookings.getValueAt(bookingIterator); - if (booking != nullptr && - (booking->getCustomerId() == userID || booking->getAssignedTechnicianId() == userID)) + ServiceBooking* booking = bookings.getValueAt(iteratorOne); + if (!booking) { - if (booking->getStatus() == util::ServiceJobStatus::PENDING || - booking->getStatus() == util::ServiceJobStatus::STARTED) - { - if (type == util::UserType::CUSTOMER) - { - booking->setStatus(util::ServiceJobStatus::CANCELLED); - booking->setCustomer(nullptr); - booking->setCustomerId(""); - User* assignedTechnician = booking->getAssignedTechnician(); - std::string title = "Customer Service Cancelled"; - std::string message = "The customer has cancelled their service booking. Your assigned job card has been cancelled and the inventory has been restocked."; - sendNotification(assignedTechnician, title, message); - } - else if (type == util::UserType::TECHNICIAN) - { - booking->setStatus(util::ServiceJobStatus::PENDING); - std::string title = "Technician Unavailable"; - std::string message = "Your assigned technician is no longer available. Your booking has been reset to pending, and we will reassign a new technician shortly."; - sendNotification(booking->getCustomer(), title, message); - } - booking->setAssignedTechnician(nullptr); - booking->setAssignedTechnicianId(""); - const auto& ListOfServices = booking->getServices(); - for (int serviceIterator = 0; serviceIterator < ListOfServices.getSize(); serviceIterator++) - { - Service* service = ListOfServices.getValueAt(serviceIterator); - if (service != nullptr) - { - const auto& items = service->getRequiredInventoryItems(); - for (int itemIterator = 0; itemIterator < items.getSize(); itemIterator++) - { - InventoryItem* item = items.getValueAt(itemIterator); - if (item != nullptr) - { - item->setQuantity(item->getQuantity() + INCREMENT_VALUE); - } - } - } - } - } + continue; } + std::string bookingID = booking->getId(); + if (booking->getCustomerId() != customerID) + { + continue; + } + if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED) + { + continue; + } + User* assignedTechnician = booking->getAssignedTechnician(); + std::string titleToTechnician = "Customer Service Cancelled"; + std::string messageToTechnician = "The customer has cancelled their service booking. Your assigned job card has been cancelled and the inventory has been restocked."; + std::string jobTitle = "Job Cancelled"; + std::string jobMessage = "The Job has cancelled. Your job card has been cancelled and the inventory has been restocked."; + processBookingCancellation(booking, + util::ServiceJobStatus::CANCELLED, + titleToTechnician, messageToTechnician, assignedTechnician, + util::ServiceJobStatus::CANCELLED, + jobTitle, jobMessage, jobs, *this + ); } } @@ -591,33 +654,49 @@ Return type: void void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID) { const int INCREMENT_VALUE = 1; - auto& jobs = m_dataStore.getJobCards(); - for (int jobIterator = 0; jobIterator < jobs.getSize(); jobIterator++) + auto& users = m_dataStore.getUsers(); + int userIndex = users.find(technicianID); + if (userIndex == -1) { - JobCard* job = jobs.getValueAt(jobIterator); - if (job != nullptr && job->getTechnicianId() == technicianID) + throw std::runtime_error("User not found: " + technicianID); + } + User* technician = users.getValueAt(userIndex); + if (!technician) + { + throw std::runtime_error("User not found: " + technicianID); + } + auto& bookings = m_dataStore.getServiceBookings(); + auto& jobs = m_dataStore.getJobCards(); + for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++) + { + ServiceBooking* booking = bookings.getValueAt(iteratorOne); + if (!booking) { - if (job->getStatus() == util::ServiceJobStatus::PENDING || job->getStatus() == util::ServiceJobStatus::STARTED) - { - job->setStatus(util::ServiceJobStatus::CANCELLED); - std::string title = "Job Cancelled"; - std::string message = "The Job has cancelled. Your job card has been cancelled and the inventory has been restocked."; - sendNotification(job->getTechnician(), title, message); - Service* service = job->getService(); - if (service != nullptr) - { - const auto& items = service->getRequiredInventoryItems(); - for (int itemIterator = 0; itemIterator < items.getSize(); itemIterator++) - { - InventoryItem* item = items.getValueAt(itemIterator); - if (item != nullptr) - { - item->setQuantity(item->getQuantity() + INCREMENT_VALUE); - } - } - } - } + continue; } + std::string technicianId = booking->getAssignedTechnicianId(); + if (technicianId != technicianID) + { + continue; + } + std::string bookingID = booking->getId(); + if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED) + { + continue; + } + User* customer = booking->getCustomer(); + if (!customer) + { + continue; + } + std::string title = "Technician Unavailable"; + std::string message = "Your assigned technician is no longer available. Your booking has been reset to pending, and we will reassign a new technician shortly."; + processBookingCancellation(booking, + util::ServiceJobStatus::PENDING, + title, message, customer, + util::ServiceJobStatus::CANCELLED, + title, message, jobs, *this + ); } } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 84fa7aa..df11b15 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -304,6 +304,14 @@ void UserManagementService::removeUser(const std::string& userID) if (index != -1) { User* user = m_dataStore.getUsers().getValueAt(index); + if (user->getUserType() == util::UserType::CUSTOMER) + { + serviceManagementService.cancelCustomerServiceBookings(userID); + } + if (user->getUserType() == util::UserType::TECHNICIAN) + { + serviceManagementService.cancelTechnicianJobs(userID); + } if (user != nullptr) { user->setState(util::State::INACTIVE);