From 78e6ae2fec5b7bcdd5348e302e835ef7639507cc Mon Sep 17 00:00:00 2001 From: Joel Thomas Date: Wed, 17 Jun 2026 11:30:15 +0530 Subject: [PATCH 1/7] Fix cache refresh from overwriting modified records Changes: - Added a check for RecordState::MODIFIED in DataStore::refreshCache(). - Preserved modified cache records during refresh instead of overwriting them with datastore values. - Discarded refreshed records when a corresponding cached record has pending changes. Fixes #2077 --- .../Trenser.VehicleServiceSystem/datastores/DataStore.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h index 021d831..03eb0eb 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h @@ -220,6 +220,12 @@ void DataStore::refreshCache(util::Map>& cac if (oldIndex != -1) { TrackedRecord& oldRecord = oldCache.getValueAt(oldIndex); + if (oldRecord.state == RecordState::MODIFIED) + { + delete refreshedRecord.data; + cache.insert(id, oldRecord); + continue; + } *oldRecord.data = *refreshedRecord.data; oldRecord.slotIndex = refreshedRecord.slotIndex; oldRecord.state = refreshedRecord.state; From b011f600cff399d3dc12e69739d64d71e0e45701 Mon Sep 17 00:00:00 2001 From: Joel Thomas Date: Wed, 17 Jun 2026 14:07:38 +0530 Subject: [PATCH 2/7] Fix notification overwrite caused by stale notification cache Changes: - Retrieved the notifications map before creating a new notification in sendNotification(). - Ensured the notification cache is refreshed before generating a notification ID. - Prevented newly created notifications from overwriting notifications added by other operations prior to save. Fixes #2079 --- .../services/InventoryManagementService.cpp | 2 +- .../services/PaymentManagementService.cpp | 2 +- .../services/ServiceManagementService.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp index a007ac1..f906431 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp @@ -270,6 +270,7 @@ void InventoryManagementService::sendNotification(User* user, const std::string& { return; } + auto& trackedNotificationsMap = m_dataStore.getNotifications(); Notification* notification = Factory::getObject( user->getId(), title, @@ -279,7 +280,6 @@ void InventoryManagementService::sendNotification(User* user, const std::string& { throw std::runtime_error("Failed to create notification"); } - auto& trackedNotificationsMap = m_dataStore.getNotifications(); trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification)); m_dataStore.saveNotifications(); EventManager::sendNotificationAvailableEvent(user->getId()); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp index 09bf1da..dad4421 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp @@ -98,6 +98,7 @@ void PaymentManagementService::sendNotification(User* user, const std::string& t { return; } + auto& trackedNotificationsMap = m_dataStore.getNotifications(); Notification* notification = Factory::getObject( user->getId(), title, @@ -107,7 +108,6 @@ void PaymentManagementService::sendNotification(User* user, const std::string& t { throw std::runtime_error("Failed to create notification"); } - auto& trackedNotificationsMap = m_dataStore.getNotifications(); trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification)); m_dataStore.saveNotifications(); EventManager::sendNotificationAvailableEvent(user->getId()); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index cf438d0..e703453 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -188,6 +188,7 @@ void ServiceManagementService::sendNotification(User* user, const std::string& t { return; } + auto& trackedNotificationsMap = m_dataStore.getNotifications(); Notification* notification = Factory::getObject( user->getId(), title, @@ -197,7 +198,6 @@ void ServiceManagementService::sendNotification(User* user, const std::string& t { throw std::runtime_error("Failed to create notification"); } - auto& trackedNotificationsMap = m_dataStore.getNotifications(); trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification)); m_dataStore.saveNotifications(); EventManager::sendNotificationAvailableEvent(user->getId()); From 1179f92849af361bd9e7f88d012683f3f1e8b30a Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Wed, 17 Jun 2026 14:20:20 +0530 Subject: [PATCH 3/7] Notification Dialog Does Not Indicate Intended Recipient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: - Updated AdminMenu::handleNotificationEvent, CustomerMenu::handleNotificationEvent, and TechnicianMenu::handleNotificationEvent to retrieve the authenticated user and pass their name to displayNewNotification(). - Modified Menu::handleAccountDisabledEvent to append the authenticated user’s name to the message box title when available. - Refactored displayNewNotification() in MenuHelper.h to accept the authenticated user’s name as an additional parameter. - Enhanced notification display logic to append the user’s name to the notification title when present. - Added null checks to ensure safe handling when no authenticated user exists. FIxes #2080 --- .../views/AdminMenu.cpp | 8 ++++++- .../views/CustomerMenu.cpp | 8 ++++++- .../views/Menu.cpp | 8 ++++++- .../views/MenuHelper.h | 23 +++++++++++++------ .../views/TechnicianMenu.cpp | 8 ++++++- 5 files changed, 44 insertions(+), 11 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 68ec663..71882ba 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -163,7 +163,13 @@ Return type: void void AdminMenu::handleNotificationEvent() { auto notifications = m_controller.getNotifications(); - displayNewNotification(notifications); + const User* authenticatedUser = m_controller.getAuthenticatedUser(); + std::string name; + if (authenticatedUser) + { + name = authenticatedUser->getName(); + } + displayNewNotification(notifications, name); } /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index 3932fba..a9d7990 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -134,7 +134,13 @@ Return type: void void CustomerMenu::handleNotificationEvent() { auto notifications = m_controller.getNotifications(); - displayNewNotification(notifications); + const User* authenticatedUser = m_controller.getAuthenticatedUser(); + std::string name; + if (authenticatedUser) + { + name = authenticatedUser->getName(); + } + displayNewNotification(notifications, name); } /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp index 2573c0e..e5881ff 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/Menu.cpp @@ -133,10 +133,16 @@ Return type: void void Menu::handleAccountDisabledEvent() { m_isMenuActive.store(false); + const User* authenticatedUser = m_controller.getAuthenticatedUser(); + std::string messageTitle = "Account Disabled"; + if (authenticatedUser) + { + messageTitle += " - " + authenticatedUser->getName(); + } MessageBoxA( GetConsoleWindow(), "Your account has been disabled.", - "Account Disabled", + messageTitle.c_str(), MB_OK | MB_ICONWARNING | MB_SETFOREGROUND | diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index 0d0f695..a92bead 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -1415,9 +1415,10 @@ Description: Displays the most recent notification from the supplied notification collection. Parameter: util::Vector notifications - collection of notifications + const std::string& - The name of the user currently authenticated with the system Return type: void */ -inline void displayNewNotification(util::Vector notifications) +inline void displayNewNotification(util::Vector notifications, const std::string& name) { const Notification* notification = nullptr; size_t numberOfNotifications = notifications.getSize(); @@ -1435,10 +1436,18 @@ inline void displayNewNotification(util::Vector notificatio } } } - MessageBoxA( - GetConsoleWindow(), - notification->getMessage().c_str(), - notification->getTitle().c_str(), - MB_OK | - MB_ICONINFORMATION); + if (notification) + { + std::string messageTitle = notification->getTitle(); + if (!name.empty()) + { + messageTitle += " - " + name; + } + MessageBoxA( + GetConsoleWindow(), + notification->getMessage().c_str(), + messageTitle.c_str(), + MB_OK | + MB_ICONINFORMATION); + } } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp index 4b090d8..ee4576c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp @@ -108,7 +108,13 @@ Return type: void void TechnicianMenu::handleNotificationEvent() { auto notifications = m_controller.getNotifications(); - displayNewNotification(notifications); + const User* authenticatedUser = m_controller.getAuthenticatedUser(); + std::string name; + if (authenticatedUser) + { + name = authenticatedUser->getName(); + } + displayNewNotification(notifications, name); } /* From 9d166362a7a75aba5a1ff305e5e06cf9367a184f Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Wed, 17 Jun 2026 15:17:55 +0530 Subject: [PATCH 4/7] Latest Notification Is Determined Using String Comparison Changes: - Added #include "StringHelper.h" to MenuHelper.h for utility functions. - Updated displayNewNotification() to compare notification IDs using util::extractNumber() instead of raw string comparison. - Ensured numeric ordering of notifications by extracting and comparing integer values from IDs. - Preserved existing notification selection logic while improving accuracy of ID comparisons. Fixes #2081 --- .../Trenser.VehicleServiceSystem/views/MenuHelper.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index a92bead..c87707a 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -28,6 +28,7 @@ Date: 21-May-2026 #include "Utility.h" #include "Validator.h" #include "Vector.h" +#include "StringHelper.h" /* Function: displayAllServices @@ -1430,7 +1431,7 @@ inline void displayNewNotification(util::Vector notificatio } else { - if (notification->getId() < notifications[index]->getId()) + if (util::extractNumber(notification->getId()) < util::extractNumber(notifications[index]->getId())) { notification = notifications[index]; } @@ -1450,4 +1451,4 @@ inline void displayNewNotification(util::Vector notificatio MB_OK | MB_ICONINFORMATION); } -} \ No newline at end of file +} From 82164e42c35196d2cf239d9b1c0f44e02598d4e2 Mon Sep 17 00:00:00 2001 From: Joel Thomas Date: Wed, 17 Jun 2026 16:47:15 +0530 Subject: [PATCH 5/7] Stop disabled users from performing operations after account deactivation Changes: - Added authorization state tracking to authenticated sessions. - Revoked authorization immediately when an account-disabled event is received. - Added authorization validation before protected service operations. - Cleared authorization state on logout. Fixes #2078 --- .../AuthenticationManagementService.cpp | 23 +++++++++++++++++++ .../AuthenticationManagementService.h | 2 ++ .../services/InventoryManagementService.cpp | 6 +++++ .../services/PaymentManagementService.cpp | 7 +++++- .../services/ServiceManagementService.cpp | 14 +++++++++++ .../services/UserManagementService.cpp | 5 ++++ 6 files changed, 56 insertions(+), 1 deletion(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp index 56137e5..dd80cd9 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp @@ -14,10 +14,29 @@ Date:19-May-2026 #include "DataStoreLockGuard.h" User* AuthenticationManagementService::m_authenticatedUser = nullptr; +bool AuthenticationManagementService::m_isAuthorized = false; EventManager AuthenticationManagementService::m_eventManager; HANDLE AuthenticationManagementService::m_accountDisabledEvent = NULL; HANDLE AuthenticationManagementService::m_notificationsAvailableEvent = NULL; + +/* +Function: ensureAuthorization +Description: Verifies that a user is currently authenticated before allowing + access to a protected operation. Throws an exception if no + authorized user session exists. +Parameter: None +Return type: void +Throws: std::runtime_error - if the user is not authorized +*/ +void AuthenticationManagementService::ensureAuthorization() +{ + if (!m_authenticatedUser || !m_isAuthorized) + { + throw std::runtime_error("You are not authorized to do this operation!"); + } +} + /* Function: login Description: Authenticates a user by checking the provided username and password @@ -40,12 +59,14 @@ bool AuthenticationManagementService::login(const std::string& username, const s if (password == user->getPassword()) { m_authenticatedUser = user; + m_isAuthorized = true; m_eventManager.initialize( user->getId(), []() { if (m_accountDisabledEvent) { + AuthenticationManagementService::m_isAuthorized = false; SetEvent(m_accountDisabledEvent); } }, @@ -86,6 +107,7 @@ void AuthenticationManagementService::logout() { m_eventManager.shutdown(); m_authenticatedUser = nullptr; + m_isAuthorized = false; m_accountDisabledEvent = NULL; m_notificationsAvailableEvent = NULL; } @@ -99,6 +121,7 @@ Return type: void */ void AuthenticationManagementService::changePassword(const std::string& newPassword) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); if (m_authenticatedUser == nullptr) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h index d512892..e927187 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h @@ -19,12 +19,14 @@ class AuthenticationManagementService { private: static User* m_authenticatedUser; + static bool m_isAuthorized; static EventManager m_eventManager; static HANDLE m_accountDisabledEvent; static HANDLE m_notificationsAvailableEvent; DataStore& m_dataStore; public: AuthenticationManagementService() : m_dataStore(DataStore::getInstance()) {} + static void ensureAuthorization(); bool login(const std::string& username, const std::string& password); void logout(); void changePassword(const std::string& newPassword); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp index f906431..6152fd3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp @@ -14,6 +14,7 @@ Date: 22-May-2026 #include "Factory.h" #include "InventoryItem.h" #include "InventoryManagementService.h" +#include "AuthenticationManagementService.h" #include "Timestamp.h" #include "User.h" #include "Utility.h" @@ -102,6 +103,7 @@ Return type: void */ void InventoryManagementService::addInventoryItem(const std::string& partName, int quantity, double price) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedInventoryItemMap = m_dataStore.getInventoryItems(); InventoryItem* newItem = Factory::getObject(partName, quantity, price); @@ -118,6 +120,7 @@ Return type: void */ void InventoryManagementService::addInventoryItemStock(const std::string& selectedItemId, int quantity) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedInventoryItemMap = m_dataStore.getInventoryItems(); int index = trackedInventoryItemMap.find(selectedItemId); @@ -144,6 +147,7 @@ Return type: util::Map */ util::Map InventoryManagementService::getInventoryItems() { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedInventoryItemMap = m_dataStore.getInventoryItems(); auto inventoryMap = util::getObjects(trackedInventoryItemMap); @@ -158,6 +162,7 @@ Return type: void */ void InventoryManagementService::removeInventoryItem(const std::string& inventoryItemID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedInventoryItemMap = m_dataStore.getInventoryItems(); int index = trackedInventoryItemMap.find(inventoryItemID); @@ -183,6 +188,7 @@ Return type: InventoryItem* */ InventoryItem* InventoryManagementService::getInventoryItem(const std::string& inventoryItemID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedInventoryItemMap = m_dataStore.getInventoryItems(); int index = trackedInventoryItemMap.find(inventoryItemID); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp index dad4421..b09b9bf 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp @@ -15,6 +15,7 @@ Date: 20-May-2026 #include "Invoice.h" #include "JobCard.h" #include "PaymentManagementService.h" +#include "AuthenticationManagementService.h" #include "DataStoreLockGuard.h" #include "Service.h" #include "ServiceBooking.h" @@ -233,6 +234,7 @@ Returns: */ util::Map PaymentManagementService::getInvoices(const std::string& customerID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& currentTrackedInvoices = m_dataStore.getInvoices(); util::Map currentUserInvoices; @@ -261,6 +263,7 @@ Throws: */ void PaymentManagementService::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& currentTrackedInvoices = m_dataStore.getInvoices(); int invoiceIndex = currentTrackedInvoices.find(invoiceID); @@ -289,7 +292,7 @@ void PaymentManagementService::completePayment(const std::string& invoiceID, uti } /* -Function: getAllInvoice +Function: getAllInvoices Description: Provides access to all invoices stored in the data store. Parameters: - none @@ -298,6 +301,7 @@ Returns: */ util::Map PaymentManagementService::getAllInvoices() { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); util::Map invoices; invoices = util::getObjects(m_dataStore.getInvoices()); @@ -317,6 +321,7 @@ Throws: */ void PaymentManagementService::confirmPayment(const std::string& invoiceID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& currentTrackedInvoices = m_dataStore.getInvoices(); int invoiceIndex = currentTrackedInvoices.find(invoiceID); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index e703453..da5eef6 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -42,6 +42,7 @@ Return type: void */ void ServiceManagementService::purchaseService(const util::Vector& serviceIDs, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel) { + AuthenticationManagementService::ensureAuthorization(); AuthenticationManagementService m_authenticationManagementService; auto authenticatedUser = m_authenticationManagementService.getAuthenticatedUser(); if (authenticatedUser == nullptr) @@ -87,6 +88,7 @@ Return type: void */ void ServiceManagementService::purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel) { + AuthenticationManagementService::ensureAuthorization(); AuthenticationManagementService m_authenticationManagementService; auto authenticatedUser = m_authenticationManagementService.getAuthenticatedUser(); if (authenticatedUser == nullptr) @@ -433,6 +435,7 @@ Return type: void */ void ServiceManagementService::createComboPackage(const std::string& packageName, const util::Vector& serviceIDsInNewCombo, double discountPercentage) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); if (packageName.empty()) { @@ -502,6 +505,7 @@ Return type: util::Map */ util::Map ServiceManagementService::getComboPackages() { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); util::Map comboPackages; comboPackages = util::getObjects(m_dataStore.getComboPackages()); @@ -516,6 +520,7 @@ Return type: void */ void ServiceManagementService::removeComboPackage(const std::string& comboPackageID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); bool removed = false; auto& trackedComboPackages = m_dataStore.getComboPackages(); @@ -548,6 +553,7 @@ Returns: */ util::Map ServiceManagementService::getServiceBookings() { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); util::Map serviceBookings; serviceBookings = util::getObjects(m_dataStore.getServiceBookings()); @@ -564,6 +570,7 @@ Returns: */ ServiceBooking* ServiceManagementService::getServiceBooking(const std::string& serviceID) { + AuthenticationManagementService::ensureAuthorization(); auto currentServiceBookings = getServiceBookings(); for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++) { @@ -590,6 +597,7 @@ Throws: */ void ServiceManagementService::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); UserManagementService m_userManagementService; ServiceBooking* currentBooking = getServiceBooking(bookingID); @@ -667,6 +675,7 @@ Throws: */ void ServiceManagementService::createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); util::Map currentServiceInventoryItems; auto& trackedInventoryItems = m_dataStore.getInventoryItems(); @@ -713,6 +722,7 @@ Returns: */ util::Map ServiceManagementService::getServices() { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); util::Map services; services = util::getObjects(m_dataStore.getServices()); @@ -731,6 +741,7 @@ Throws: */ void ServiceManagementService::removeService(const std::string& serviceID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& currentTrackedServices = m_dataStore.getServices(); auto& currentTrackedComboPackages = m_dataStore.getComboPackages(); @@ -778,6 +789,7 @@ Returns: */ util::Map ServiceManagementService::getServiceBookings(const std::string& customerID) { + AuthenticationManagementService::ensureAuthorization(); util::Map currentServiceBookings = getServiceBookings(); util::Map currentUserServiceBookings; if (currentServiceBookings.getSize() != 0) @@ -804,6 +816,7 @@ Returns: */ util::Map ServiceManagementService::getJobCards(const std::string& technicianID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedJobCards = m_dataStore.getJobCards(); util::Map technicianJobCards; @@ -858,6 +871,7 @@ Returns: */ void ServiceManagementService::updateJobStatus(const std::string& jobID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); AuthenticationManagementService authenticationManagementService; PaymentManagementService paymentManagementService; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index ab85936..0c3991d 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -15,6 +15,7 @@ Date:19-May-2026 #include "Notification.h" #include "PaymentManagementService.h" #include "ServiceManagementService.h" +#include "AuthenticationManagementService.h" #include "User.h" #include "UserManagementService.h" #include "Vector.h" @@ -114,6 +115,7 @@ Return type: void */ void UserManagementService::updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); auto usersMap = util::getObjects(trackedUsersMap); @@ -161,6 +163,7 @@ Throws: */ util::Vector UserManagementService::getUserNotifications(const std::string& userID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); if (trackedUsersMap.find(userID) == -1) @@ -204,6 +207,7 @@ Throws: */ void UserManagementService::deleteNotification(const std::string& notificationID, const std::string& userID) { + AuthenticationManagementService::ensureAuthorization(); DataStoreLockGuard lock(m_dataStore); auto& trackedUsersMap = m_dataStore.getUsers(); auto& trackedNotificationsMap = m_dataStore.getNotifications(); @@ -265,6 +269,7 @@ Return type: void */ void UserManagementService::removeUser(const std::string& userID) { + AuthenticationManagementService::ensureAuthorization(); InventoryManagementService inventoryManagementService; PaymentManagementService paymentManagementService; ServiceManagementService serviceManagementService; From 468106952f9894c67234df6d05c468ddb5fce4ac Mon Sep 17 00:00:00 2001 From: Joel Thomas Date: Wed, 17 Jun 2026 17:39:45 +0530 Subject: [PATCH 6/7] Notify admins when new service bookings are created Changes: - Added notifyAllAdmins() helper in ServiceManagementService. - Sent notifications to all administrators when a customer places a service booking. - Sent notifications to all administrators when a customer purchases a combo package. - Included the generated Service Booking ID in admin notifications. Fixes #2100 --- .../services/ServiceManagementService.cpp | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index da5eef6..a4d72bd 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -29,6 +29,31 @@ Date:19-May-2026 #include "DataStoreLockGuard.h" #include "EventManager.h" +/* +Function: notifyAllAdmins +Description: Sends a notification to all users with the ADMIN role. + Iterates through the provided user collection and delivers + the specified notification to each administrator using the + ServiceManagementService notification mechanism. +Parameter: const std::string& title - notification title +Parameter: const std::string& message - notification message +Parameter: const util::Map>& users - collection of tracked users +Parameter: ServiceManagementService* serviceManagementService - service used to dispatch notifications +Return type: void +*/ +static void notifyAllAdmins(const std::string& title, const std::string& message, const util::Map>& users, ServiceManagementService* serviceManagementService) +{ + int numberOfUsers = users.getSize(); + for (int index = 0; index < numberOfUsers; index++) + { + User* user = users.getValueAt(index).data; + if (user->getUserType() == util::UserType::ADMIN) + { + serviceManagementService->sendNotification(user, title, message); + } + } +} + /* Function: purchaseService Description: Creates a new service booking for the authenticated user. Validates @@ -73,6 +98,7 @@ void ServiceManagementService::purchaseService(const util::Vector& std::string title = "Service Booking succeeded"; std::string message = "Your service booking has been successfully placed with ID " + serviceBooking->getId(); sendNotification(authenticatedUser, title, message); + notifyAllAdmins("New Service Order Available", "A new service order has been placed with Service Booking ID " + serviceBooking->getId(), m_dataStore.getUsers(), this); } /* @@ -114,6 +140,7 @@ void ServiceManagementService::purchaseComboPackage(const std::string& comboPack std::string title = "Combo Package Service Booking succeeded"; std::string message = "Your service booking for the combo package has been successfully placed with ID " + serviceBooking->getId(); sendNotification(authenticatedUser, title, message); + notifyAllAdmins("New Combo Package Order Available", "A new combo package order has been placed with Service Booking ID " + serviceBooking->getId(), m_dataStore.getUsers(), this); } util::Map ServiceManagementService::m_observers{}; From 1651dfeafe337d62554ee7155fe2eb61599d82c9 Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Wed, 17 Jun 2026 18:10:12 +0530 Subject: [PATCH 7/7] Service Can Still Be Purchased After Required Inventory Item Is Removed Changes: - Added m_dataStore.saveServiceBookings() in ServiceManagementService::purchaseService() to persist bookings immediately after successful purchase. - Enhanced AdminMenu::removeInventoryItem() to also remove all services that depend on the removed inventory item, ensuring consistency between inventory and service availability. - Updated selectServiceFromServices() in MenuHelper.h to skip services if any of their required inventory items have a quantity less than 1, preventing users from selecting unavailable services. - Introduced inventory depletion checks before inserting services into the active services map, improving reliability of service selection. Fixes #2082 --- .../services/ServiceManagementService.cpp | 1 + .../views/AdminMenu.cpp | 17 +++++++++++++++++ .../views/MenuHelper.h | 15 +++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index cf438d0..879ed73 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -72,6 +72,7 @@ void ServiceManagementService::purchaseService(const util::Vector& std::string title = "Service Booking succeeded"; std::string message = "Your service booking has been successfully placed with ID " + serviceBooking->getId(); sendNotification(authenticatedUser, title, message); + m_dataStore.saveServiceBookings(); } /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 71882ba..62c64cd 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -338,6 +338,23 @@ void AdminMenu::removeInventoryItem() std::string selectedItemId = selectedItem->getId(); m_controller.removeInventoryItem(selectedItemId); std::cout << "Item " << selectedItem->getPartName() << " removed successfully." << std::endl; + const util::Map& listOfService = m_controller.getServices(); + for (int serviceIndex = 0; serviceIndex < listOfService.getSize(); serviceIndex++) + { + const Service* service = listOfService.getValueAt(serviceIndex); + if (!service) + { + continue; + } + const util::Map& requiredItems = service->getRequiredInventoryItems(); + if (requiredItems.find(selectedItemId) != -1) + { + m_controller.removeService(service->getId()); + std::cout << "Service " << service->getName() + << " removed as the item " + << selectedItem->getPartName() << " required for the service has been removed." << std::endl; + } + } } } util::pressEnter(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index c87707a..33cd5bd 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -1057,6 +1057,21 @@ inline const Service* selectServiceFromServices(const util::Map& requiredItems = currentService->getRequiredInventoryItems(); + for (int itemIndex = 0; itemIndex < requiredItems.getSize(); itemIndex++) + { + const InventoryItem* item = requiredItems.getValueAt(itemIndex); + if (!item || item->getQuantity() < 1) + { + hasDepletedItem = true; + break; + } + } + if (hasDepletedItem) + { + continue; + } activeServicesMap.insert(currentIndex, currentService); double partsCost = util::calculatePartsCost(currentService); std::cout << std::left