Compare commits

..

1 Commits

Author SHA1 Message Date
joelthomastrenser dd29c7324f Fix: Prevent duplicate usernames across all user states
Changes:
- Updated username duplicate validation to consider all existing users.
- Prevented reuse of usernames belonging to deleted/disabled accounts.
- Fixed authentication conflicts caused by duplicate usernames.

Fixes #1809
2026-06-01 17:40:27 +05:30
2 changed files with 51 additions and 55 deletions
@@ -543,65 +543,50 @@ static void restoreInventory(ServiceBooking* booking)
/* /*
Function: processBookingCancellation Function: processBookingCancellation
Description: Handles cancellation or reassignment of a service booking based on user type. Description: Cancels jobs and updates the status of a given booking. Sends notifications to the
Cancels associated job cards, updates booking status, clears technician assignments, specified user, resets technician assignment if needed, and restores inventory items.
restores inventory, and sends appropriate notifications. Parameter: ServiceBooking* booking - Pointer to the booking being cancelled
Parameters: util::ServiceJobStatus newServiceBookingStatus - New status to assign to the booking
ServiceBooking* booking - The booking to cancel or reset 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 util::Map<std::string, JobCard*>& jobs - Collection of job cards to update
ServiceManagementService& currentService - Service layer for notifications ServiceManagementService& currentService - Reference to the service for sending notifications
util::UserType userType - Type of user initiating cancellation (CUSTOMER or TECHNICIAN)
Return type: void Return type: void
*/ */
static void processBookingCancellation(ServiceBooking* booking, static void processBookingCancellation(ServiceBooking* booking,
util::Map<std::string, JobCard*>& jobs, util::ServiceJobStatus newServiceBookingStatus,
ServiceManagementService& currentService, const std::string& notificationTitle,
util::UserType userType) 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) if (!booking || !notifyUser)
{ {
return; return;
} }
for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator) for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator)
{ {
JobCard* jobCard = jobs.getValueAt(jobIterator); JobCard* jobCard = jobs.getValueAt(jobIterator);
if (!jobCard || jobCard->getBookingId() != booking->getId() || jobCard->getStatus() == util::ServiceJobStatus::CANCELLED) if (jobCard && jobCard->getBookingId() == booking->getId())
{ {
continue; jobCard->setStatus(jobCardStatus);
currentService.sendNotification(notifyUser, jobNotificationTitle, jobNotificationMessage);
} }
jobCard->setStatus(util::ServiceJobStatus::CANCELLED); }
if (userType == util::UserType::CUSTOMER) booking->setStatus(newServiceBookingStatus);
currentService.sendNotification(notifyUser, notificationTitle, notificationMessage);
if (newServiceBookingStatus == util::ServiceJobStatus::PENDING)
{ {
if (User* technician = booking->getAssignedTechnician())
{
const std::string jobTitle = "Job Cancelled";
const std::string jobMessage = "Your job card has been cancelled and the inventory has been restocked.";
currentService.sendNotification(technician, jobTitle, jobMessage);
}
}
}
if (userType == util::UserType::CUSTOMER)
{
booking->setStatus(util::ServiceJobStatus::CANCELLED);
if (User* technician = booking->getAssignedTechnician())
{
const std::string title = "Customer Service Cancelled";
const std::string message = "Your assigned job card has been cancelled and the inventory has been restocked.";
currentService.sendNotification(technician, title, message);
}
}
else if (userType == util::UserType::TECHNICIAN)
{
booking->setStatus(util::ServiceJobStatus::PENDING);
if (User* customer = booking->getCustomer())
{
const std::string title = "Technician Unavailable";
const std::string message = "Your booking has been reset to pending and we will reassign a new technician shortly.";
currentService.sendNotification(customer, title, message);
}
}
booking->setAssignedTechnician(nullptr); booking->setAssignedTechnician(nullptr);
booking->setAssignedTechnicianId(""); booking->setAssignedTechnicianId("");
}
restoreInventory(booking); restoreInventory(booking);
} }
@@ -639,13 +624,21 @@ void ServiceManagementService::cancelCustomerServiceBookings(const std::string&
{ {
continue; continue;
} }
if (booking->getStatus() != util::ServiceJobStatus::PENDING && if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED)
booking->getStatus() != util::ServiceJobStatus::STARTED &&
booking->getStatus() != util::ServiceJobStatus::IN_PROGRESS)
{ {
continue; continue;
} }
processBookingCancellation(booking, jobs, *this, util::UserType::CUSTOMER); 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 been 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
);
} }
} }
@@ -683,9 +676,7 @@ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicia
{ {
continue; continue;
} }
if (booking->getStatus() != util::ServiceJobStatus::PENDING && if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED)
booking->getStatus() != util::ServiceJobStatus::STARTED &&
booking->getStatus() != util::ServiceJobStatus::IN_PROGRESS)
{ {
continue; continue;
} }
@@ -694,7 +685,14 @@ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicia
{ {
continue; continue;
} }
processBookingCancellation(booking, jobs, *this, util::UserType::TECHNICIAN); 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
);
} }
} }
@@ -116,15 +116,13 @@ bool util::isPasswordValid(const std::string& password)
* usersMap - map of user objects keyed by identifier * usersMap - map of user objects keyed by identifier
* Returns: * Returns:
* bool - true if the username is already in use by an active user, false otherwise * bool - true if the username is already in use by an active user, false otherwise
* Notes:
* - Only considers users with state util::State::ACTIVE
*/ */
bool util::isUsernameDuplicate(const std::string& username, const util::Map<std::string, User*>& usersMap) bool util::isUsernameDuplicate(const std::string& username, const util::Map<std::string, User*>& usersMap)
{ {
int index = usersMap.findIf( int index = usersMap.findIf(
[&](const std::string&, User* user) [&](const std::string&, User* user)
{ {
return (user->getUserName() == username && user->getState() == util::State::ACTIVE); return (user->getUserName() == username);
} }
); );
return index != -1; return index != -1;