Implement Service Refactoring
<UserStory> 1927: Implement Service Refactorings </UserStory> UserStory #1927 <Changes> 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. </Changes> <Test> N/A </Test> <Review> Sreeja Reghukumar, please review </Review>
This commit is contained in:
+1
@@ -157,6 +157,7 @@
|
||||
<ClInclude Include="core\patterns\Observer.h" />
|
||||
<ClInclude Include="core\patterns\Subject.h" />
|
||||
<ClInclude Include="datastores\DataStore.h" />
|
||||
<ClInclude Include="datastores\DataStoreLockGuard.h" />
|
||||
<ClInclude Include="datastores\sharedmemory\FileHeader.h" />
|
||||
<ClInclude Include="datastores\sharedmemory\MappingInfo.h" />
|
||||
<ClInclude Include="datastores\sharedmemory\RecordState.h" />
|
||||
|
||||
+3
@@ -278,5 +278,8 @@
|
||||
<ClInclude Include="datastores\sharedmemory\SharedMemory.h">
|
||||
<Filter>Header Files\DataStores\SharedMemory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="datastores\DataStoreLockGuard.h">
|
||||
<Filter>Header Files\DataStores</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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<std::string, TrackedRecord<Service>>& DataStore::getServices()
|
||||
{
|
||||
util::Map<std::string, TrackedRecord<Service>> services = loadRecords<Service, SerializedService>(m_services);
|
||||
refreshCache(m_serviceCache, services);
|
||||
util::Map<std::string, TrackedRecord<InventoryItem>>& inventoryItems = getInventoryItems();
|
||||
size_t numberOfServices = m_serviceCache.getSize();
|
||||
for (int iteratorOne =0; iteratorOne < numberOfServices; iteratorOne++)
|
||||
{
|
||||
Service* currentService = m_serviceCache.getValueAt(iteratorOne).data;
|
||||
util::Map<std::string, InventoryItem*> inventoryItemMap;
|
||||
util::Vector<std::string> 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<std::string, TrackedRecord<ComboPackage>>& DataStore::getComboPackages()
|
||||
{
|
||||
util::Map<std::string, TrackedRecord<ComboPackage>> comboPackages = loadRecords<ComboPackage, SerializedComboPackage>(m_comboPackages);
|
||||
refreshCache(m_comboPackageCache, comboPackages);
|
||||
util::Map<std::string, TrackedRecord<Service>>& services = getServices();
|
||||
size_t numberOfComboPackages = m_comboPackageCache.getSize();
|
||||
for (int iteratorOne = 0; iteratorOne < numberOfComboPackages; iteratorOne++)
|
||||
{
|
||||
ComboPackage* currentComboPackage = m_comboPackageCache.getValueAt(iteratorOne).data;
|
||||
util::Vector<std::string> currentServiceIds = currentComboPackage->getServiceIDs();
|
||||
util::Map<std::string, Service*> 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<std::string, TrackedRecord<ServiceBooking>>& DataStore::getServiceBookings()
|
||||
{
|
||||
util::Map<std::string, TrackedRecord<ServiceBooking>> serviceBookings = loadRecords<ServiceBooking, SerializedServiceBooking>(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<std::string, Service*> 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<std::string, TrackedRecord<JobCard>>& DataStore::getJobCards()
|
||||
{
|
||||
util::Map<std::string, TrackedRecord<JobCard>> jobCards = loadRecords<JobCard, SerializedJobCard>(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<Service, SerializedService>(m_services, m_serviceCache);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -407,6 +539,7 @@ Returns:
|
||||
*/
|
||||
void DataStore::saveComboPackages()
|
||||
{
|
||||
saveRecords<ComboPackage, SerializedComboPackage>(m_comboPackages, m_comboPackageCache);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -431,6 +564,7 @@ Returns:
|
||||
*/
|
||||
void DataStore::saveServiceBookings()
|
||||
{
|
||||
saveRecords<ServiceBooking, SerializedServiceBooking>(m_serviceBookings, m_serviceBookingCache);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -443,6 +577,7 @@ Returns:
|
||||
*/
|
||||
void DataStore::saveJobCards()
|
||||
{
|
||||
saveRecords<JobCard, SerializedJobCard>(m_jobCards, m_jobCardCache);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
+28
@@ -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;
|
||||
};
|
||||
+133
-63
@@ -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<std::string>&
|
||||
{
|
||||
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<std::string, Service*> 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<ServiceBooking>(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, 0);
|
||||
@@ -65,7 +67,7 @@ void ServiceManagementService::purchaseService(const util::Vector<std::string>&
|
||||
{
|
||||
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<std::string, Service*> selectedServices = comboPackage->getServices();
|
||||
ServiceBooking* serviceBooking = Factory::getObject<ServiceBooking>(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<std::string, TrackedRecord<InventoryItem>>& 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<std::string, JobCard*>& jobs,
|
||||
static void processBookingCancellation(TrackedRecord<ServiceBooking>& trackedBooking,
|
||||
util::Map<std::string, TrackedRecord<JobCard>>& jobs,
|
||||
ServiceManagementService& currentService,
|
||||
util::UserType userType)
|
||||
util::UserType userType,
|
||||
util::Map<std::string, TrackedRecord<InventoryItem>>& 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<std::string>& 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<std::string, Service*>& 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<ComboPackage>(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<std::string, ComboPackage*>
|
||||
*/
|
||||
util::Map<std::string, ComboPackage*> ServiceManagementService::getComboPackages()
|
||||
{
|
||||
return m_dataStore.getComboPackages();
|
||||
DataStoreLockGuard lock(m_dataStore);
|
||||
util::Map<std::string, ComboPackage*> 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<std::string, ComboPackage*>& 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<std::string, ServiceBooking*> ServiceManagementService::getServiceBookings()
|
||||
{
|
||||
return m_dataStore.getServiceBookings();
|
||||
DataStoreLockGuard lock(m_dataStore);
|
||||
util::Map<std::string, ServiceBooking*> 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<JobCard>(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<std::string>& inventoryItemIDs, double laborCost)
|
||||
{
|
||||
util::Map<std::string, InventoryItem*> 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<std::string, Service*>& 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<std::string, Service*> ServiceManagementService::getServices()
|
||||
{
|
||||
return m_dataStore.getServices();
|
||||
DataStoreLockGuard lock(m_dataStore);
|
||||
util::Map<std::string, Service*> services;
|
||||
services = util::getObjects(m_dataStore.getServices());
|
||||
return services;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -988,14 +1035,19 @@ Throws:
|
||||
*/
|
||||
void ServiceManagementService::removeService(const std::string& serviceID)
|
||||
{
|
||||
util::Map<std::string, Service*>& currentServices = m_dataStore.getServices();
|
||||
util::Map<std::string, ComboPackage*>& 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<std::string, Service*> 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<std::string, JobCard*> ServiceManagementService::getJobCards(const std::string& technicianID)
|
||||
{
|
||||
util::Map<std::string, JobCard*> jobCards = m_dataStore.getJobCards();
|
||||
DataStoreLockGuard lock(m_dataStore);
|
||||
auto& trackedJobCards = m_dataStore.getJobCards();
|
||||
util::Map<std::string, JobCard*> 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();
|
||||
}
|
||||
Reference in New Issue
Block a user