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
This commit is contained in:
+1
-3
@@ -409,10 +409,8 @@ void Controller::removeUser(const std::string& userID)
|
|||||||
User* user = m_userManagementService.getUser(userID);
|
User* user = m_userManagementService.getUser(userID);
|
||||||
if (!user)
|
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);
|
m_userManagementService.removeUser(userID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+155
-76
@@ -507,6 +507,89 @@ void ServiceManagementService::saveObservers()
|
|||||||
util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this);
|
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<std::string, JobCard*>& 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<std::string, JobCard*>& 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
|
Function: cancelCustomerServiceBookings
|
||||||
Description: Cancels all service bookings associated with a given customer or technician.
|
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
|
Parameter: const std::string& userID - ID of the customer or technician
|
||||||
Return type: void
|
Return type: void
|
||||||
*/
|
*/
|
||||||
void ServiceManagementService::cancelCustomerServiceBookings(const std::string& userID)
|
void ServiceManagementService::cancelCustomerServiceBookings(const std::string& customerID)
|
||||||
{
|
{
|
||||||
const int INCREMENT_VALUE = 1;
|
const int INCREMENT_VALUE = 1;
|
||||||
auto& users = m_dataStore.getUsers();
|
auto& users = m_dataStore.getUsers();
|
||||||
int userIndex = users.find(userID);
|
int userIndex = users.find(customerID);
|
||||||
if (userIndex == -1)
|
if (userIndex == -1)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("User not found: " + userID);
|
throw std::runtime_error("User not found: " + customerID);
|
||||||
}
|
}
|
||||||
User* user = users.getValueAt(userIndex);
|
User* customer = users.getValueAt(userIndex);
|
||||||
if (user == nullptr)
|
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 = m_dataStore.getServiceBookings();
|
||||||
auto& bookings = DataStore::getInstance().getServiceBookings();
|
auto& jobs = m_dataStore.getJobCards();
|
||||||
for (int bookingIterator = 0; bookingIterator < bookings.getSize(); bookingIterator++)
|
for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++)
|
||||||
{
|
{
|
||||||
ServiceBooking* booking = bookings.getValueAt(bookingIterator);
|
ServiceBooking* booking = bookings.getValueAt(iteratorOne);
|
||||||
if (booking != nullptr &&
|
if (!booking)
|
||||||
(booking->getCustomerId() == userID || booking->getAssignedTechnicianId() == userID))
|
|
||||||
{
|
{
|
||||||
if (booking->getStatus() == util::ServiceJobStatus::PENDING ||
|
continue;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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)
|
void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID)
|
||||||
{
|
{
|
||||||
const int INCREMENT_VALUE = 1;
|
const int INCREMENT_VALUE = 1;
|
||||||
auto& jobs = m_dataStore.getJobCards();
|
auto& users = m_dataStore.getUsers();
|
||||||
for (int jobIterator = 0; jobIterator < jobs.getSize(); jobIterator++)
|
int userIndex = users.find(technicianID);
|
||||||
|
if (userIndex == -1)
|
||||||
{
|
{
|
||||||
JobCard* job = jobs.getValueAt(jobIterator);
|
throw std::runtime_error("User not found: " + technicianID);
|
||||||
if (job != nullptr && job->getTechnicianId() == 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)
|
continue;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
@@ -304,6 +304,14 @@ void UserManagementService::removeUser(const std::string& userID)
|
|||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
User* user = m_dataStore.getUsers().getValueAt(index);
|
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)
|
if (user != nullptr)
|
||||||
{
|
{
|
||||||
user->setState(util::State::INACTIVE);
|
user->setState(util::State::INACTIVE);
|
||||||
|
|||||||
Reference in New Issue
Block a user