From f3220ee191d220c8581677e842e0b2ce2abe4d31 Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Fri, 12 Jun 2026 17:37:37 +0530 Subject: [PATCH] Implement Service Refactoring 1927: Implement Service Refactorings UserStory #1927 1. Added DataStoreLockGuard integration across ServiceManagementService methods for thread-safe datastore operations. 2. Updated DataStore::getServices(), getComboPackages(), getServiceBookings(), and getJobCards() to enrich records with linked entities (inventory items, services, bookings, technicians). 3. Modified ServiceManagementService::purchaseService() and purchaseComboPackage() to use tracked records and persist bookings safely. 4. Enhanced restoreInventory() and processBookingCancellation() to handle tracked records, update record states, and restore inventory items correctly. 5. Refactored cancelCustomerServiceBookings() and cancelTechnicianJobs() to use tracked records, restore inventory, and persist changes. 6. Updated createComboPackage(), removeComboPackage(), and createJobCard() to use tracked records and save changes to datastore. 7. Updated createService() to validate inventory items with tracked records and persist new services safely. 8. Added required header dependencies for DataStoreLockGuard and shared memory support. N/A Sreeja Reghukumar, please review --- .../Trenser.VehicleServiceSystem.vcxproj | 1 + ...enser.VehicleServiceSystem.vcxproj.filters | 3 + .../datastores/DataStore.cpp | 135 ++++++++++++ .../datastores/DataStore.h | 1 + .../datastores/DataStoreLockGuard.h | 28 +++ .../services/ServiceManagementService.cpp | 196 ++++++++++++------ 6 files changed, 301 insertions(+), 63 deletions(-) create mode 100644 Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj index 6a269f5..7c4bfd3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj @@ -157,6 +157,7 @@ + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters index 7e74b19..94301c4 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters @@ -278,5 +278,8 @@ Header Files\DataStores\SharedMemory + + Header Files\DataStores + \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp index 1cade32..0f71bce 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp @@ -12,6 +12,8 @@ Date: 19-May-2026 #include "Config.h" #include "SerializedRecords.h" #include "FileHelper.h" +#include "ServiceBooking.h" +#include "JobCard.h" /* Function: DataStore @@ -254,6 +256,28 @@ Returns: */ util::Map>& DataStore::getServices() { + util::Map> services = loadRecords(m_services); + refreshCache(m_serviceCache, services); + util::Map>& inventoryItems = getInventoryItems(); + size_t numberOfServices = m_serviceCache.getSize(); + for (int iteratorOne =0; iteratorOne < numberOfServices; iteratorOne++) + { + Service* currentService = m_serviceCache.getValueAt(iteratorOne).data; + util::Map inventoryItemMap; + util::Vector currentServiceInventoryItem = currentService->getRequiredInventoryItemIDs(); + for (int iteratorTwo = 0; iteratorTwo < currentServiceInventoryItem.getSize(); iteratorTwo++) + { + const std::string& currentInventoryItemId = currentServiceInventoryItem[iteratorTwo]; + int currentInventoryItemIndex = inventoryItems.find(currentInventoryItemId); + if (currentInventoryItemIndex == -1) + { + throw std::runtime_error("Invalid inventory item ID"); + } + InventoryItem* currentItem = inventoryItems.getValueAt(currentInventoryItemIndex).data; + inventoryItemMap[currentInventoryItemId] = currentItem; + } + currentService->setRequiredInventoryItems(inventoryItemMap); + } return m_serviceCache; } @@ -267,6 +291,28 @@ Returns: */ util::Map>& DataStore::getComboPackages() { + util::Map> comboPackages = loadRecords(m_comboPackages); + refreshCache(m_comboPackageCache, comboPackages); + util::Map>& services = getServices(); + size_t numberOfComboPackages = m_comboPackageCache.getSize(); + for (int iteratorOne = 0; iteratorOne < numberOfComboPackages; iteratorOne++) + { + ComboPackage* currentComboPackage = m_comboPackageCache.getValueAt(iteratorOne).data; + util::Vector currentServiceIds = currentComboPackage->getServiceIDs(); + util::Map currentComboPackageServices; + for (int iteratorTwo = 0; iteratorTwo < currentServiceIds.getSize(); iteratorTwo++) + { + const std::string& currentServiceId = currentServiceIds[iteratorTwo]; + int serviceIndex = services.find(currentServiceId); + if (serviceIndex == -1) + { + throw std::runtime_error("Invalid service ID"); + } + Service* currentService = services.getValueAt(serviceIndex).data; + currentComboPackageServices[currentServiceId] = currentService; + } + currentComboPackage->setServices(currentComboPackageServices); + } return m_comboPackageCache; } @@ -293,6 +339,49 @@ Returns: */ util::Map>& DataStore::getServiceBookings() { + util::Map> serviceBookings = loadRecords(m_serviceBookings); + refreshCache(m_serviceBookingCache, serviceBookings); + auto& users = getUsers(); + auto& services = getServices(); + size_t numberOfServiceBookings = m_serviceBookingCache.getSize(); + for (int iteratorOne = 0; iteratorOne < numberOfServiceBookings; iteratorOne++) + { + ServiceBooking* serviceBooking = m_serviceBookingCache.getValueAt(iteratorOne).data; + auto& serviceIds = serviceBooking->getServiceIDs(); + util::Map servicesInBooking; + for (int iteratorTwo = 0; iteratorTwo < serviceIds.getSize(); iteratorTwo++) + { + const std::string& currentServiceId = serviceIds[iteratorTwo]; + int serviceIndex = services.find(currentServiceId); + if (serviceIndex == -1) + { + throw std::runtime_error("Invalid service index."); + } + auto currentService = services.getValueAt(serviceIndex); + servicesInBooking[currentServiceId] = currentService.data; + } + serviceBooking->setServices(servicesInBooking); + if (!serviceBooking->getCustomerId().empty()) + { + int userIndex = users.find(serviceBooking->getCustomerId()); + if (userIndex == -1) + { + throw std::runtime_error("Invalid user index."); + } + auto customer = users.getValueAt(userIndex); + serviceBooking->setCustomer(customer.data); + } + if (!serviceBooking->getAssignedTechnicianId().empty()) + { + int technicianIndex = users.find(serviceBooking->getAssignedTechnicianId()); + if (technicianIndex == -1) + { + throw std::runtime_error("Invalid technician index."); + } + auto technician = users.getValueAt(technicianIndex); + serviceBooking->setAssignedTechnician(technician.data); + } + } return m_serviceBookingCache; } @@ -306,9 +395,51 @@ Returns: */ util::Map>& DataStore::getJobCards() { + util::Map> jobCards = loadRecords(m_jobCards); + refreshCache(m_jobCardCache, jobCards); + auto& serviceBookings = getServiceBookings(); + auto& services = getServices(); + auto& users = getUsers(); + int numberOfJobCards = m_jobCardCache.getSize(); + for (int iterator = 0; iterator < numberOfJobCards; iterator++) + { + JobCard* jobCard = m_jobCardCache.getValueAt(iterator).data; + if (!jobCard) + { + continue; + } + const std::string& bookingId = jobCard->getBookingId(); + int bookingIndex = serviceBookings.find(bookingId); + if (bookingIndex == -1) + { + throw std::runtime_error("Invalid booking ID: " + bookingId); + } + auto trackedBooking = serviceBookings.getValueAt(bookingIndex); + jobCard->setBooking(trackedBooking.data); + const std::string& serviceId = jobCard->getServiceId(); + int serviceIndex = services.find(serviceId); + if (serviceIndex == -1) + { + throw std::runtime_error("Invalid service ID: " + serviceId); + } + auto trackedService = services.getValueAt(serviceIndex); + jobCard->setService(trackedService.data); + const std::string& technicianId = jobCard->getTechnicianId(); + if (!technicianId.empty()) + { + int technicianIndex = users.find(technicianId); + if (technicianIndex == -1) + { + throw std::runtime_error("Invalid technician ID: " + technicianId); + } + auto trackedTechnician = users.getValueAt(technicianIndex); + jobCard->setTechnician(trackedTechnician.data); + } + } return m_jobCardCache; } + /* Function: getInvoices Description: Retrieves all invoice records from the datastore. @@ -395,6 +526,7 @@ Returns: */ void DataStore::saveServices() { + saveRecords(m_services, m_serviceCache); } /* @@ -407,6 +539,7 @@ Returns: */ void DataStore::saveComboPackages() { + saveRecords(m_comboPackages, m_comboPackageCache); } /* @@ -431,6 +564,7 @@ Returns: */ void DataStore::saveServiceBookings() { + saveRecords(m_serviceBookings, m_serviceBookingCache); } /* @@ -443,6 +577,7 @@ Returns: */ void DataStore::saveJobCards() { + saveRecords(m_jobCards, m_jobCardCache); } /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h index 3950b11..cbfd5b3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h @@ -11,6 +11,7 @@ Date: 19-May-2026 #include "Map.h" #include "MappingInfo.h" #include "TrackedRecord.h" +#include "SerializedRecords.h" #include "SharedMemory.h" class User; class Notification; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h new file mode 100644 index 0000000..2e04eb0 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h @@ -0,0 +1,28 @@ +/* +File: DataStoreLockGuard.h +Description: Defines the DataStoreLockGuard class used to manage DataStore + locking and unlocking automatically within a scope. +Author: Trenser +Date: 12-June-2026 +*/ + +#pragma once +#include "DataStore.h" + +class DataStoreLockGuard +{ +public: + explicit DataStoreLockGuard(DataStore& dataStore) + : m_dataStore(dataStore) + { + m_dataStore.lockDataStore(); + } + ~DataStoreLockGuard() + { + m_dataStore.unlockDataStore(); + } + DataStoreLockGuard(const DataStoreLockGuard&) = delete; + DataStoreLockGuard& operator=(const DataStoreLockGuard&) = delete; +private: + DataStore& m_dataStore; +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 1a9f753..f372bef 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -25,6 +25,7 @@ Date:19-May-2026 #include "Timestamp.h" #include "User.h" #include "UserManagementService.h" +#include "DataStoreLockGuard.h" #include "Utility.h" /* @@ -46,18 +47,19 @@ void ServiceManagementService::purchaseService(const util::Vector& { throw std::runtime_error("No user is currently logged in!"); } - auto& servicesMap = m_dataStore.getServices(); - auto& serviceBookingMap = m_dataStore.getServiceBookings(); + DataStoreLockGuard lock(m_dataStore); + auto& trackedServicesMap = m_dataStore.getServices(); + auto& trackedServiceBookingMap = m_dataStore.getServiceBookings(); util::Map selectedServices; int selectedServicesCount = serviceIDs.getSize(); for (int index = 0; index < selectedServicesCount; index++) { - int serviceIndex = servicesMap.find(serviceIDs[index]); + int serviceIndex = trackedServicesMap.find(serviceIDs[index]); if (serviceIndex == -1) { throw std::runtime_error("Service not found!"); } - Service* service = servicesMap.getValueAt(serviceIndex); + Service* service = trackedServicesMap.getValueAt(serviceIndex).data; selectedServices[service->getId()] = service; } ServiceBooking* serviceBooking = Factory::getObject(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, 0); @@ -65,7 +67,7 @@ void ServiceManagementService::purchaseService(const util::Vector& { throw std::runtime_error("Failed to create service booking"); } - serviceBookingMap[serviceBooking->getId()] = serviceBooking; + trackedServiceBookingMap[serviceBooking->getId()] = util::createNewRecord(serviceBooking); std::string title = "Service Booking succeeded"; std::string message = "Your service booking has been successfully placed with ID " + serviceBooking->getId(); sendNotification(authenticatedUser, title, message); @@ -90,21 +92,22 @@ void ServiceManagementService::purchaseComboPackage(const std::string& comboPack { throw std::runtime_error("No user is currently logged in!"); } - auto& comboPackagesMap = m_dataStore.getComboPackages(); - auto& serviceBookingMap = m_dataStore.getServiceBookings(); - int comboPackageIndex = comboPackagesMap.find(comboPackageID); + DataStoreLockGuard lock(m_dataStore); + auto& trackedComboPackagesMap = m_dataStore.getComboPackages(); + auto& trackedServiceBookingMap = m_dataStore.getServiceBookings(); + int comboPackageIndex = trackedComboPackagesMap.find(comboPackageID); if (comboPackageIndex == -1) { throw std::runtime_error("Combo Package not found!"); } - const ComboPackage* comboPackage = comboPackagesMap[comboPackageID]; + const ComboPackage* comboPackage = trackedComboPackagesMap[comboPackageID].data; util::Map selectedServices = comboPackage->getServices(); ServiceBooking* serviceBooking = Factory::getObject(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, comboPackage->getDiscountPercentage()); if (serviceBooking == nullptr) { throw std::runtime_error("Failed to create combo package service booking"); } - serviceBookingMap[serviceBooking->getId()] = serviceBooking; + trackedServiceBookingMap[serviceBooking->getId()] = util::createNewRecord(serviceBooking); 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); @@ -514,7 +517,7 @@ Description: Restores inventory quantities for all required items in the service Parameter: ServiceBooking* booking - Pointer to the booking whose inventory items need to be restored Return type: void */ -static void restoreInventory(ServiceBooking* booking) +static void restoreInventory(ServiceBooking* booking, util::Map>& trackedInventoryItems) { const int INCREMENT_VALUE = 1; if (!booking) @@ -533,9 +536,17 @@ static void restoreInventory(ServiceBooking* booking) for (int InventoryIterator = 0; InventoryIterator < items.getSize(); ++InventoryIterator) { InventoryItem* item = items.getValueAt(InventoryIterator); + const std::string& currentItemId = item->getId(); + int itemIndex = trackedInventoryItems.find(currentItemId); + if (itemIndex == -1) + { + continue; + } + auto& currentTrackedInventoryItem = trackedInventoryItems.getValueAt(itemIndex); if (item) { item->setQuantity(item->getQuantity() + INCREMENT_VALUE); + currentTrackedInventoryItem.state = RecordState::MODIFIED; } } } @@ -553,23 +564,28 @@ Parameters: util::UserType userType - Type of user initiating cancellation (CUSTOMER or TECHNICIAN) Return type: void */ -static void processBookingCancellation(ServiceBooking* booking, - util::Map& jobs, +static void processBookingCancellation(TrackedRecord& trackedBooking, + util::Map>& jobs, ServiceManagementService& currentService, - util::UserType userType) + util::UserType userType, + util::Map>& trackedInventoryItems) { + ServiceBooking* booking = trackedBooking.data; if (!booking) { return; } + const std::string& bookingId = booking->getId(); for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator) { - JobCard* jobCard = jobs.getValueAt(jobIterator); + auto& trackedJobCard = jobs.getValueAt(jobIterator); + JobCard* jobCard = trackedJobCard.data; if (!jobCard || jobCard->getBookingId() != booking->getId() || jobCard->getStatus() == util::ServiceJobStatus::CANCELLED) { continue; } jobCard->setStatus(util::ServiceJobStatus::CANCELLED); + trackedJobCard.state = RecordState::MODIFIED; if (userType == util::UserType::CUSTOMER) { if (User* technician = booking->getAssignedTechnician()) @@ -602,7 +618,8 @@ static void processBookingCancellation(ServiceBooking* booking, } booking->setAssignedTechnician(nullptr); booking->setAssignedTechnicianId(""); - restoreInventory(booking); + trackedBooking.state = RecordState::MODIFIED; + restoreInventory(booking, trackedInventoryItems); } /* @@ -615,22 +632,25 @@ Return type: void */ void ServiceManagementService::cancelCustomerServiceBookings(const std::string& customerID) { - auto& users = m_dataStore.getUsers(); - int userIndex = users.find(customerID); + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsers = m_dataStore.getUsers(); + int userIndex = trackedUsers.find(customerID); if (userIndex == -1) { throw std::runtime_error("User not found: " + customerID); } - User* customer = users.getValueAt(userIndex); + User* customer = trackedUsers.getValueAt(userIndex).data; if (!customer) { throw std::runtime_error("User not found: " + customerID); } - auto& bookings = m_dataStore.getServiceBookings(); - auto& jobs = m_dataStore.getJobCards(); - for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++) + auto& trackedBookings = m_dataStore.getServiceBookings(); + auto& trackedJobs = m_dataStore.getJobCards(); + auto& trackedInventoryItems = m_dataStore.getInventoryItems(); + for (int iteratorOne = 0; iteratorOne < trackedBookings.getSize(); iteratorOne++) { - ServiceBooking* booking = bookings.getValueAt(iteratorOne); + auto& trackedBooking = trackedBookings.getValueAt(iteratorOne); + ServiceBooking* booking = trackedBooking.data; if (!booking) { continue; @@ -645,8 +665,12 @@ void ServiceManagementService::cancelCustomerServiceBookings(const std::string& { continue; } - processBookingCancellation(booking, jobs, *this, util::UserType::CUSTOMER); + processBookingCancellation(trackedBooking, trackedJobs, *this, util::UserType::CUSTOMER, trackedInventoryItems); } + m_dataStore.saveUsers(); + m_dataStore.saveServiceBookings(); + m_dataStore.saveJobCards(); + m_dataStore.saveInventoryItems(); } /* @@ -658,22 +682,25 @@ Return type: void */ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID) { - auto& users = m_dataStore.getUsers(); - int userIndex = users.find(technicianID); + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsers = m_dataStore.getUsers(); + int userIndex = trackedUsers.find(technicianID); if (userIndex == -1) { throw std::runtime_error("User not found: " + technicianID); } - User* technician = users.getValueAt(userIndex); + User* technician = trackedUsers.getValueAt(userIndex).data; 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++) + auto& trackedBookings = m_dataStore.getServiceBookings(); + auto& trackedJobs = m_dataStore.getJobCards(); + auto& trackedInventoryItems = m_dataStore.getInventoryItems(); + for (int iteratorOne = 0; iteratorOne < trackedBookings.getSize(); iteratorOne++) { - ServiceBooking* booking = bookings.getValueAt(iteratorOne); + auto& trackedBooking = trackedBookings.getValueAt(iteratorOne); + ServiceBooking* booking = trackedBooking.data; if (!booking) { continue; @@ -694,8 +721,12 @@ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicia { continue; } - processBookingCancellation(booking, jobs, *this, util::UserType::TECHNICIAN); + processBookingCancellation(trackedBooking, trackedJobs, *this, util::UserType::TECHNICIAN, trackedInventoryItems); } + m_dataStore.saveUsers(); + m_dataStore.saveInventoryItems(); + m_dataStore.saveServiceBookings(); + m_dataStore.saveJobCards(); } /* @@ -709,6 +740,7 @@ Return type: void */ void ServiceManagementService::createComboPackage(const std::string& packageName, const util::Vector& serviceIDsInNewCombo, double discountPercentage) { + DataStoreLockGuard lock(m_dataStore); if (packageName.empty()) { throw std::invalid_argument("The Combo Package Name cannot be empty.\n"); @@ -721,19 +753,19 @@ void ServiceManagementService::createComboPackage(const std::string& packageName { throw std::invalid_argument("Discount percentage must be between 0 and 100."); } - auto& servicesMap = m_dataStore.getServices(); + auto& trackedServicesMap = m_dataStore.getServices(); for (int index = 0; index < serviceIDsInNewCombo.getSize(); index++) { - const std::string serviceid = serviceIDsInNewCombo[index]; - if (servicesMap.find(serviceid) == -1) + const std::string& serviceid = serviceIDsInNewCombo[index]; + if (trackedServicesMap.find(serviceid) == -1) { throw std::runtime_error("Service ID not found: " + serviceid); } } - auto& comboPackageMap = m_dataStore.getComboPackages(); - for (int iterator = 0; iterator < comboPackageMap.getSize(); iterator++) + auto& trackedComboPackageMap = m_dataStore.getComboPackages(); + for (int iterator = 0; iterator < trackedComboPackageMap.getSize(); iterator++) { - ComboPackage* existingCombos = comboPackageMap.getValueAt(iterator); + ComboPackage* existingCombos = trackedComboPackageMap.getValueAt(iterator).data; const util::Map& servicesInsideExistingCombos = existingCombos->getServices(); if (servicesInsideExistingCombos.getSize() == serviceIDsInNewCombo.getSize()) { @@ -757,15 +789,16 @@ void ServiceManagementService::createComboPackage(const std::string& packageName for (int iteratorOne = 0; iteratorOne < serviceIDsInNewCombo.getSize(); iteratorOne++) { const std::string& serviceId = serviceIDsInNewCombo[iteratorOne]; - int serviceIndex = servicesMap.find(serviceId); + int serviceIndex = trackedServicesMap.find(serviceId); if (serviceIndex == -1) { throw std::runtime_error("Service ID not found: " + serviceId); } - selectedServices.insert(serviceId, servicesMap.getValueAt(serviceIndex)); + selectedServices.insert(serviceId, trackedServicesMap.getValueAt(serviceIndex).data); } ComboPackage* newComboPackage = Factory::getObject(packageName, discountPercentage, selectedServices); - comboPackageMap.insert(newComboPackage->getId(), newComboPackage); + trackedComboPackageMap.insert(newComboPackage->getId(), util::createNewRecord(newComboPackage)); + m_dataStore.saveComboPackages(); } /* @@ -776,7 +809,10 @@ Return type: util::Map */ util::Map ServiceManagementService::getComboPackages() { - return m_dataStore.getComboPackages(); + DataStoreLockGuard lock(m_dataStore); + util::Map comboPackages; + comboPackages = util::getObjects(m_dataStore.getComboPackages()); + return comboPackages; } /* @@ -787,14 +823,17 @@ Return type: void */ void ServiceManagementService::removeComboPackage(const std::string& comboPackageID) { + DataStoreLockGuard lock(m_dataStore); bool removed = false; - util::Map& currentComboPackages = m_dataStore.getComboPackages(); - for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++) + auto& trackedComboPackages = m_dataStore.getComboPackages(); + for (int iterator = 0; iterator < trackedComboPackages.getSize(); iterator++) { - ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator); + auto& comboPackage = trackedComboPackages.getValueAt(iterator); + ComboPackage* currentComboPackage = comboPackage.data; if (currentComboPackage && currentComboPackage->getId() == comboPackageID) { currentComboPackage->setState(util::State::INACTIVE); + comboPackage.state = RecordState::MODIFIED; removed = true; break; } @@ -803,6 +842,7 @@ void ServiceManagementService::removeComboPackage(const std::string& comboPackag { throw std::runtime_error("Combo package with ID '" + comboPackageID + "' not found."); } + m_dataStore.saveComboPackages(); } /* @@ -815,7 +855,9 @@ Returns: */ util::Map ServiceManagementService::getServiceBookings() { - return m_dataStore.getServiceBookings(); + DataStoreLockGuard lock(m_dataStore); + util::Map serviceBookings; + serviceBookings = util::getObjects(m_dataStore.getServiceBookings()); } /* @@ -856,7 +898,8 @@ void ServiceManagementService::createJobCard(const std::string& bookingID, const { UserManagementService m_userManagementService; ServiceBooking* currentBooking = getServiceBooking(bookingID); - auto& currentJobCards = m_dataStore.getJobCards(); + DataStoreLockGuard lock(m_dataStore); + auto& currentTrackedJobCards = m_dataStore.getJobCards(); if (currentBooking == nullptr) { throw std::runtime_error("Service Booking not available"); @@ -902,7 +945,7 @@ void ServiceManagementService::createJobCard(const std::string& bookingID, const JobCard* jobCard = Factory::getObject(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::Timestamp(), util::ServiceJobStatus::STARTED, util::Timestamp()); if (jobCard) { - currentJobCards.insert(jobCard->getId(), jobCard); + currentTrackedJobCards.insert(jobCard->getId(), util::createNewRecord(jobCard)); sendNotification(selectedTechnician, title, message); } else @@ -930,14 +973,15 @@ Throws: void ServiceManagementService::createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost) { util::Map currentServiceInventoryItems; - auto inventoryItems = m_dataStore.getInventoryItems(); + DataStoreLockGuard lock(m_dataStore); + auto& trackedInventoryItems = m_dataStore.getInventoryItems(); for (int iteratorOne =0; iteratorOne < inventoryItemIDs.getSize(); iteratorOne++) { std::string currentItemID = inventoryItemIDs[iteratorOne]; bool itemFound = false; - for (int iteratorTwo = 0; iteratorTwo < inventoryItems.getSize(); iteratorTwo++) + for (int iteratorTwo = 0; iteratorTwo < trackedInventoryItems.getSize(); iteratorTwo++) { - InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iteratorTwo); + InventoryItem* currentInventoryItem = trackedInventoryItems.getValueAt(iteratorTwo).data; if (currentInventoryItem && currentInventoryItem->getId() == currentItemID) { itemFound = true; @@ -955,12 +999,12 @@ void ServiceManagementService::createService(const std::string& name, const util { throw std::runtime_error("Unable to create new service."); } - util::Map& currentServices = m_dataStore.getServices(); + auto& currentServices = m_dataStore.getServices(); if (currentServices.find(newService->getId()) != -1) { throw std::runtime_error("Service with this ID Already exists."); } - currentServices.insert(newService->getId(), newService); + currentServices.insert(newService->getId(), util::createNewRecord(newService)); } /* @@ -973,7 +1017,10 @@ Returns: */ util::Map ServiceManagementService::getServices() { - return m_dataStore.getServices(); + DataStoreLockGuard lock(m_dataStore); + util::Map services; + services = util::getObjects(m_dataStore.getServices()); + return services; } /* @@ -988,14 +1035,19 @@ Throws: */ void ServiceManagementService::removeService(const std::string& serviceID) { - util::Map& currentServices = m_dataStore.getServices(); - util::Map& currentComboPackages = m_dataStore.getComboPackages(); - if (currentServices.find(serviceID) != -1) + DataStoreLockGuard lock(m_dataStore); + auto& currentTrackedServices = m_dataStore.getServices(); + auto& currentTrackedComboPackages = m_dataStore.getComboPackages(); + if (currentTrackedServices.find(serviceID) != -1) { - currentServices.getValueAt(currentServices.find(serviceID))->setState(util::State::INACTIVE); - for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++) + int serviceIndex, comboPackageIndex; + serviceIndex = currentTrackedServices.find(serviceID); + currentTrackedServices.getValueAt(serviceIndex).data->setState(util::State::INACTIVE); + currentTrackedServices.getValueAt(serviceIndex).state = RecordState::MODIFIED; + for (int iterator = 0; iterator < currentTrackedComboPackages.getSize(); iterator++) { - ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator); + comboPackageIndex = iterator; + ComboPackage* currentComboPackage = currentTrackedComboPackages.getValueAt(iterator).data; if (currentComboPackage && currentComboPackage->getState() == util::State::ACTIVE) { util::Map currentServices = currentComboPackage->getServices(); @@ -1005,6 +1057,7 @@ void ServiceManagementService::removeService(const std::string& serviceID) if (currentService->getId() == serviceID) { currentComboPackage->setState(util::State::INACTIVE); + currentTrackedComboPackages.getValueAt(comboPackageIndex).state = RecordState::MODIFIED; break; } } @@ -1015,6 +1068,8 @@ void ServiceManagementService::removeService(const std::string& serviceID) { throw std::runtime_error("Service not found."); } + m_dataStore.saveServices(); + m_dataStore.saveComboPackages(); } /* @@ -1053,11 +1108,12 @@ Returns: */ util::Map ServiceManagementService::getJobCards(const std::string& technicianID) { - util::Map jobCards = m_dataStore.getJobCards(); + DataStoreLockGuard lock(m_dataStore); + auto& trackedJobCards = m_dataStore.getJobCards(); util::Map technicianJobCards; - for (int iterator = 0; iterator < jobCards.getSize(); iterator++) + for (int iterator = 0; iterator < trackedJobCards.getSize(); iterator++) { - JobCard* currentJobCard = jobCards.getValueAt(iterator); + JobCard* currentJobCard = trackedJobCards.getValueAt(iterator).data; if (currentJobCard->getTechnicianId() == technicianID) { technicianJobCards.insert(currentJobCard->getId(), currentJobCard); @@ -1106,6 +1162,7 @@ Returns: */ void ServiceManagementService::updateJobStatus(const std::string& jobID) { + DataStoreLockGuard lock(m_dataStore); AuthenticationManagementService authenticationManagementService; PaymentManagementService paymentManagementService; bool jobStatusUpdated = false, serviceBookingCompleted; @@ -1120,8 +1177,15 @@ void ServiceManagementService::updateJobStatus(const std::string& jobID) { throw std::runtime_error("No job cards assigned to the technician."); } + auto& trackedJobCards = m_dataStore.getJobCards(); + auto& trackedServiceBookings = m_dataStore.getServiceBookings(); if (currentAssignedJobs.find(jobID) != -1) { + int jobIndex = trackedJobCards.find(jobID); + if (jobIndex == -1) + { + throw std::runtime_error("Unable to fetch current job."); + } currentJob = currentAssignedJobs.getValueAt(currentAssignedJobs.find(jobID)); if (currentJob == nullptr) { @@ -1130,16 +1194,20 @@ void ServiceManagementService::updateJobStatus(const std::string& jobID) if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) { currentJob->setStatus(util::ServiceJobStatus::IN_PROGRESS); + trackedJobCards.getValueAt(jobIndex).state = RecordState::MODIFIED; jobStatusUpdated = true; } else if (currentJob->getStatus() == util::ServiceJobStatus::IN_PROGRESS) { currentJob->setStatus(util::ServiceJobStatus::COMPLETED); + trackedJobCards.getValueAt(jobIndex).state = RecordState::MODIFIED; jobStatusUpdated = true; serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs); if (serviceBookingCompleted) { + const std::string& bookingId = currentJob->getBookingId(); currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED); + trackedServiceBookings.getValueAt(trackedServiceBookings.find(bookingId)).state = RecordState::MODIFIED; paymentManagementService.generateInvoice(currentJob->getBooking()); std::string title = "Service Booking completed. Invoice Generated."; std::string message = "Services completed for the booking and invoice generated."; @@ -1155,4 +1223,6 @@ void ServiceManagementService::updateJobStatus(const std::string& jobID) { throw std::runtime_error("Failed to update job status. Job may already be completed."); } + m_dataStore.saveJobCards(); + m_dataStore.saveServiceBookings(); } \ No newline at end of file