Compare commits

..

13 Commits

Author SHA1 Message Date
joelthomastrenser d41b9da4e2 changes 2026-06-11 18:06:14 +05:30
Jissin Mathew 0bef16e82c Added file headers and updated the readpassword utility functionality 2026-06-11 18:02:09 +05:30
joelthomastrenser dc5da0a7b7 changes 2026-06-11 16:39:47 +05:30
joelthomastrenser 7454c5a75f changes 2026-06-11 15:49:20 +05:30
joelthomastrenser 93a38bc6fb changes 2026-06-11 14:09:07 +05:30
joelthomastrenser a8cd72ed17 notif 2026-06-11 12:59:24 +05:30
joelthomastrenser adf74e2427 changes 2026-06-11 12:40:43 +05:30
joelthomastrenser 603ed9c60e some code changes 2026-06-11 11:10:54 +05:30
joelthomastrenser 43c337d46a openorclosefilemappingA 2026-06-11 10:40:40 +05:30
joelthomastrenser 1ef6cd9479 changes 2026-06-10 18:18:03 +05:30
joelthomastrenser f8cb7453a7 finish ser/deser 2026-06-10 16:13:43 +05:30
joelthomastrenser 6e9a9292de vcxproj 2026-06-10 15:44:36 +05:30
joelthomastrenser ec1f4ea117 shm init 2026-06-10 15:42:34 +05:30
43 changed files with 1388 additions and 1006 deletions
+2 -2
View File
@@ -427,5 +427,5 @@ FodyWeavers.xsd
*.msm *.msm
*.msp *.msp
# DAT Files # CSV Files
*.dat *.csv
@@ -140,6 +140,7 @@
<ClCompile Include="models\User.cpp" /> <ClCompile Include="models\User.cpp" />
<ClCompile Include="services\AuthenticationManagementService.cpp" /> <ClCompile Include="services\AuthenticationManagementService.cpp" />
<ClCompile Include="services\InventoryManagementService.cpp" /> <ClCompile Include="services\InventoryManagementService.cpp" />
<ClCompile Include="services\NotificationManagementService.cpp" />
<ClCompile Include="services\PaymentManagementService.cpp" /> <ClCompile Include="services\PaymentManagementService.cpp" />
<ClCompile Include="services\ServiceManagementService.cpp" /> <ClCompile Include="services\ServiceManagementService.cpp" />
<ClCompile Include="services\UserManagementService.cpp" /> <ClCompile Include="services\UserManagementService.cpp" />
@@ -156,7 +157,6 @@
<ClInclude Include="core\patterns\Observer.h" /> <ClInclude Include="core\patterns\Observer.h" />
<ClInclude Include="core\patterns\Subject.h" /> <ClInclude Include="core\patterns\Subject.h" />
<ClInclude Include="datastores\DataStore.h" /> <ClInclude Include="datastores\DataStore.h" />
<ClInclude Include="datastores\DataStoreLockGuard.h" />
<ClInclude Include="datastores\sharedmemory\FileHeader.h" /> <ClInclude Include="datastores\sharedmemory\FileHeader.h" />
<ClInclude Include="datastores\sharedmemory\MappingInfo.h" /> <ClInclude Include="datastores\sharedmemory\MappingInfo.h" />
<ClInclude Include="datastores\sharedmemory\RecordState.h" /> <ClInclude Include="datastores\sharedmemory\RecordState.h" />
@@ -181,6 +181,7 @@
<ClInclude Include="utilities\Config.h" /> <ClInclude Include="utilities\Config.h" />
<ClInclude Include="utilities\Enums.h" /> <ClInclude Include="utilities\Enums.h" />
<ClInclude Include="utilities\FileHelper.h" /> <ClInclude Include="utilities\FileHelper.h" />
<ClInclude Include="utilities\FileManager.h" />
<ClInclude Include="utilities\InputHelper.h" /> <ClInclude Include="utilities\InputHelper.h" />
<ClInclude Include="utilities\Map.h" /> <ClInclude Include="utilities\Map.h" />
<ClInclude Include="utilities\OutputHelper.h" /> <ClInclude Include="utilities\OutputHelper.h" />
@@ -114,6 +114,9 @@
<ClCompile Include="datastores\DataStore.cpp"> <ClCompile Include="datastores\DataStore.cpp">
<Filter>Source Files\DataStores</Filter> <Filter>Source Files\DataStores</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="services\NotificationManagementService.cpp">
<Filter>Source Files\Services</Filter>
</ClCompile>
<ClCompile Include="core\patterns\Observer.cpp"> <ClCompile Include="core\patterns\Observer.cpp">
<Filter>Source Files\Core\Patterns</Filter> <Filter>Source Files\Core\Patterns</Filter>
</ClCompile> </ClCompile>
@@ -242,6 +245,9 @@
<ClInclude Include="utilities\Config.h"> <ClInclude Include="utilities\Config.h">
<Filter>Header Files\Utilities</Filter> <Filter>Header Files\Utilities</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="utilities\FileManager.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="utilities\StringHelper.h"> <ClInclude Include="utilities\StringHelper.h">
<Filter>Header Files\Utilities</Filter> <Filter>Header Files\Utilities</Filter>
</ClInclude> </ClInclude>
@@ -272,8 +278,5 @@
<ClInclude Include="datastores\sharedmemory\SharedMemory.h"> <ClInclude Include="datastores\sharedmemory\SharedMemory.h">
<Filter>Header Files\DataStores\SharedMemory</Filter> <Filter>Header Files\DataStores\SharedMemory</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="datastores\DataStoreLockGuard.h">
<Filter>Header Files\DataStores</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -588,37 +588,63 @@ void Controller::configureNotifications(bool paymentNotifications, bool serviceN
} }
/* /*
Function: initialize Function: loadSystemData
Description: Initializes the system and run system checks to ensure critical configurations, such as verifying admin existence. Description: Loads all system data from persistent storage into memory.
Parameters: Invokes the respective management services to load users, inventory items, services,
- None combo packages, service bookings, job cards, invoices, and observers.
Returns:
- bool
*/
bool Controller::initialize()
{
auto& dataStore = DataStore::getInstance();
if (!dataStore.initialize())
{
return false;
}
m_userManagementService.ensureAdminExists();
m_inventoryManagementService.sendLowStockAlerts();
m_paymentManagementService.sendPaymentReminders();
return true;
}
/*
Function: shutdown
Description: Shutdown the system, and do necessary cleanups
Parameters: Parameters:
- None - None
Returns: Returns:
- void - void
*/ */
void Controller::shutdown() void Controller::loadSystemData()
{ {
auto& dataStore = DataStore::getInstance(); m_userManagementService.loadUsers();
dataStore.shutdown(); m_inventoryManagementService.loadInventoryItems();
m_serviceManagementService.loadServices();
m_serviceManagementService.loadComboPackages();
m_serviceManagementService.loadServiceBookings();
m_serviceManagementService.loadJobCards();
m_paymentManagementService.loadInvoices();
m_serviceManagementService.loadObservers();
m_paymentManagementService.loadObservers();
m_inventoryManagementService.loadObservers();
} }
/*
Function: saveSystemData
Description: Saves all system data from memory back to persistent storage.
Invokes the respective management services to save users, inventory items, services,
combo packages, service bookings, job cards, invoices, and observers.
Parameters:
- None
Returns:
- void
*/
void Controller::saveSystemData()
{
m_userManagementService.saveUsers();
m_inventoryManagementService.saveInventoryItems();
m_serviceManagementService.saveServices();
m_serviceManagementService.saveComboPackages();
m_serviceManagementService.saveServiceBookings();
m_serviceManagementService.saveJobCards();
m_paymentManagementService.saveInvoices();
m_serviceManagementService.saveObservers();
m_paymentManagementService.saveObservers();
m_inventoryManagementService.saveObservers();
}
/*
Function: runSystemChecks
Description: Runs system checks to ensure critical configurations, such as verifying admin existence.
Parameter: None
Return type: void
*/
void Controller::runSystemChecks()
{
m_userManagementService.ensureAdminExists();
m_inventoryManagementService.sendLowStockAlerts();
m_paymentManagementService.sendPaymentReminders();
}
@@ -70,6 +70,7 @@ public:
util::Vector<const Notification*> getNotifications(); util::Vector<const Notification*> getNotifications();
void deleteNotification(const std::string& notificationID); void deleteNotification(const std::string& notificationID);
void configureNotifications(bool paymentNotifications, bool serviceNotifications); void configureNotifications(bool paymentNotifications, bool serviceNotifications);
bool initialize(); void loadSystemData();
void shutdown(); void saveSystemData();
void runSystemChecks();
}; };
@@ -7,8 +7,11 @@ Date: 19-May-2026
#pragma once #pragma once
class Notification;
class Observer class Observer
{ {
public: public:
virtual ~Observer() = default; virtual ~Observer() = default;
virtual void addNotification(Notification* notification) = 0;
}; };
@@ -13,42 +13,9 @@ Date: 19-May-2026
#include "SerializedRecords.h" #include "SerializedRecords.h"
#include "FileHelper.h" #include "FileHelper.h"
/*
Function: DataStore
Description: Constructs the DataStore singleton and initializes
internal handles to their default values.
Parameters:
- None
Returns:
- None
*/
DataStore::DataStore() : DataStore::DataStore() :
m_globalMutex(NULL) {} m_globalMutex(NULL) {}
/*
Function: ~DataStore
Description: Destroys the DataStore singleton and releases all
cached application objects owned by the datastore.
This includes users, notifications, services,
combo packages, inventory items, service bookings,
job cards, and invoices.
Parameters:
- None
Returns:
- None
*/
DataStore::~DataStore()
{
clearCache(m_userCache);
clearCache(m_notificationCache);
clearCache(m_serviceCache);
clearCache(m_comboPackageCache);
clearCache(m_inventoryItemCache);
clearCache(m_serviceBookingCache);
clearCache(m_jobCardCache);
clearCache(m_invoiceCache);
}
/* /*
Function: initialize Function: initialize
Description: Initializes the shared-memory datastore. Description: Initializes the shared-memory datastore.
@@ -144,6 +111,11 @@ bool DataStore::initialize()
success = false; success = false;
break; break;
} }
if (!SharedMemory::createOrOpenMapping(m_payments))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_serviceManagementObservers)) if (!SharedMemory::createOrOpenMapping(m_serviceManagementObservers))
{ {
success = false; success = false;
@@ -188,6 +160,7 @@ void DataStore::shutdown()
SharedMemory::closeMapping(m_serviceBookings); SharedMemory::closeMapping(m_serviceBookings);
SharedMemory::closeMapping(m_jobCards); SharedMemory::closeMapping(m_jobCards);
SharedMemory::closeMapping(m_invoices); SharedMemory::closeMapping(m_invoices);
SharedMemory::closeMapping(m_payments);
SharedMemory::closeMapping(m_serviceManagementObservers); SharedMemory::closeMapping(m_serviceManagementObservers);
SharedMemory::closeMapping(m_paymentManagementObservers); SharedMemory::closeMapping(m_paymentManagementObservers);
SharedMemory::closeMapping(m_inventoryManagementObservers); SharedMemory::closeMapping(m_inventoryManagementObservers);
@@ -220,11 +193,9 @@ Parameters:
Returns: Returns:
- util::Map<std::string, TrackedRecord<User>>: Collection of user records - util::Map<std::string, TrackedRecord<User>>: Collection of user records
*/ */
util::Map<std::string, TrackedRecord<User>>& DataStore::getUsers() util::Map<std::string, TrackedRecord<User>> DataStore::getUsers()
{ {
auto users = loadRecords<User, SerializedUser>(m_users); return util::Map<std::string, TrackedRecord<User>>();
refreshCache(m_userCache, users);
return m_userCache;
} }
/* /*
@@ -235,11 +206,9 @@ Parameters:
Returns: Returns:
- util::Map<std::string, TrackedRecord<Notification>>: Collection of notification records - util::Map<std::string, TrackedRecord<Notification>>: Collection of notification records
*/ */
util::Map<std::string, TrackedRecord<Notification>>& DataStore::getNotifications() util::Map<std::string, TrackedRecord<Notification>> DataStore::getNotifications()
{ {
auto notifications = loadRecords<Notification, SerializedNotification>(m_notifications); return util::Map<std::string, TrackedRecord<Notification>>();
refreshCache(m_notificationCache, notifications);
return m_notificationCache;
} }
/* /*
@@ -250,9 +219,9 @@ Parameters:
Returns: Returns:
- util::Map<std::string, TrackedRecord<Service>>: Collection of service records - util::Map<std::string, TrackedRecord<Service>>: Collection of service records
*/ */
util::Map<std::string, TrackedRecord<Service>>& DataStore::getServices() util::Map<std::string, TrackedRecord<Service>> DataStore::getServices()
{ {
return m_serviceCache; return util::Map<std::string, TrackedRecord<Service>>();
} }
/* /*
@@ -263,9 +232,9 @@ Parameters:
Returns: Returns:
- util::Map<std::string, TrackedRecord<ComboPackage>>: Collection of combo package records - util::Map<std::string, TrackedRecord<ComboPackage>>: Collection of combo package records
*/ */
util::Map<std::string, TrackedRecord<ComboPackage>>& DataStore::getComboPackages() util::Map<std::string, TrackedRecord<ComboPackage>> DataStore::getComboPackages()
{ {
return m_comboPackageCache; return util::Map<std::string, TrackedRecord<ComboPackage>>();
} }
/* /*
@@ -276,9 +245,9 @@ Parameters:
Returns: Returns:
- util::Map<std::string, TrackedRecord<InventoryItem>>: Collection of inventory item records - util::Map<std::string, TrackedRecord<InventoryItem>>: Collection of inventory item records
*/ */
util::Map<std::string, TrackedRecord<InventoryItem>>& DataStore::getInventoryItems() util::Map<std::string, TrackedRecord<InventoryItem>> DataStore::getInventoryItems()
{ {
return m_inventoryItemCache; return util::Map<std::string, TrackedRecord<InventoryItem>>();
} }
/* /*
@@ -289,9 +258,9 @@ Parameters:
Returns: Returns:
- util::Map<std::string, TrackedRecord<ServiceBooking>>: Collection of service booking records - util::Map<std::string, TrackedRecord<ServiceBooking>>: Collection of service booking records
*/ */
util::Map<std::string, TrackedRecord<ServiceBooking>>& DataStore::getServiceBookings() util::Map<std::string, TrackedRecord<ServiceBooking>> DataStore::getServiceBookings()
{ {
return m_serviceBookingCache; return util::Map<std::string, TrackedRecord<ServiceBooking>>();
} }
/* /*
@@ -302,9 +271,9 @@ Parameters:
Returns: Returns:
- util::Map<std::string, TrackedRecord<JobCard>>: Collection of job card records - util::Map<std::string, TrackedRecord<JobCard>>: Collection of job card records
*/ */
util::Map<std::string, TrackedRecord<JobCard>>& DataStore::getJobCards() util::Map<std::string, TrackedRecord<JobCard>> DataStore::getJobCards()
{ {
return m_jobCardCache; return util::Map<std::string, TrackedRecord<JobCard>>();
} }
/* /*
@@ -315,40 +284,22 @@ Parameters:
Returns: Returns:
- util::Map<std::string, TrackedRecord<Invoice>>: Collection of invoice records - util::Map<std::string, TrackedRecord<Invoice>>: Collection of invoice records
*/ */
util::Map<std::string, TrackedRecord<Invoice>>& DataStore::getInvoices() util::Map<std::string, TrackedRecord<Invoice>> DataStore::getInvoices()
{ {
return m_invoiceCache; return util::Map<std::string, TrackedRecord<Invoice>>();
} }
/* /*
Function: getObservers Function: getPayments
Description: Retrieves observer records from the specified observer mapping Description: Retrieves all payment records from the datastore.
and resolves them to User objects.
Parameters: Parameters:
- mapping: Observer mapping to read from - None
Returns: Returns:
- util::Map<std::string, User*>: Collection of observer records - util::Map<std::string, TrackedRecord<Payment>>: Collection of payment records
Throws:
- std::runtime_error if an observer references an invalid user ID
*/ */
util::Map<std::string, User*> DataStore::getObservers(MappingInfo& mapping) util::Map<std::string, TrackedRecord<Payment>> DataStore::getPayments()
{ {
auto& users = getUsers(); return util::Map<std::string, TrackedRecord<Payment>>();
util::Map<std::string, User*> observers;
SharedMemory::ensureLatestMapping(mapping);
size_t recordCount = SharedMemory::getRecordCount(mapping);
for (size_t index = 0; index < recordCount; index++)
{
const SerializedObserver* observer = static_cast<SerializedObserver*>(SharedMemory::getRecordAddress(mapping, index));
int userIndex = users.find(observer->id);
if (userIndex == -1)
{
throw std::runtime_error("Invalid observer user ID");
}
User* user = users.getValueAt(userIndex).data;
observers.insert(user->getId(), user);
}
return observers;
} }
/* /*
@@ -357,11 +308,11 @@ Description: Retrieves all service management observer records from the datastor
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, User*>: Collection of observer records - util::Map<std::string, TrackedRecord<std::string>>: Collection of observer records
*/ */
util::Map<std::string, User*> DataStore::getServiceManagementObservers() util::Map<std::string, TrackedRecord<std::string>> DataStore::getServiceManagementObservers()
{ {
return getObservers(m_serviceManagementObservers); return util::Map<std::string, TrackedRecord<std::string>>();
} }
/* /*
@@ -370,11 +321,11 @@ Description: Retrieves all payment management observer records from the datastor
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, User*>: Collection of observer records - util::Map<std::string, TrackedRecord<std::string>>: Collection of observer records
*/ */
util::Map<std::string, User*> DataStore::getPaymentManagementObservers() util::Map<std::string, TrackedRecord<std::string>> DataStore::getPaymentManagementObservers()
{ {
return getObservers(m_paymentManagementObservers); return util::Map<std::string, TrackedRecord<std::string>>();
} }
/* /*
@@ -383,48 +334,46 @@ Description: Retrieves all inventory management observer records from the datast
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, User*>: Collection of observer records - util::Map<std::string, TrackedRecord<std::string>>: Collection of observer records
*/ */
util::Map<std::string, User*> DataStore::getInventoryManagementObservers() util::Map<std::string, TrackedRecord<std::string>> DataStore::getInventoryManagementObservers()
{ {
return getObservers(m_inventoryManagementObservers); return util::Map<std::string, TrackedRecord<std::string>>();
} }
/* /*
Function: saveUsers Function: saveUsers
Description: Persists all user records to the datastore. Description: Persists all user records to the datastore.
Parameters: Parameters:
- None - users: util::Map<std::string, TrackedRecord<User>>&, collection of user records
Returns: Returns:
- None - None
*/ */
void DataStore::saveUsers() void DataStore::saveUsers(util::Map<std::string, TrackedRecord<User>>& users)
{ {
saveRecords<User, SerializedUser>(m_users, m_userCache);
} }
/* /*
Function: saveNotifications Function: saveNotifications
Description: Persists all notification records to the datastore. Description: Persists all notification records to the datastore.
Parameters: Parameters:
- None - notifications: util::Map<std::string, TrackedRecord<Notification>>&, collection of notification records
Returns: Returns:
- None - None
*/ */
void DataStore::saveNotifications() void DataStore::saveNotifications(util::Map<std::string, TrackedRecord<Notification>>& notifications)
{ {
saveRecords<Notification, SerializedNotification>(m_notifications, m_notificationCache);
} }
/* /*
Function: saveServices Function: saveServices
Description: Persists all service records to the datastore. Description: Persists all service records to the datastore.
Parameters: Parameters:
- None - services: util::Map<std::string, TrackedRecord<Service>>&, collection of service records
Returns: Returns:
- None - None
*/ */
void DataStore::saveServices() void DataStore::saveServices(util::Map<std::string, TrackedRecord<Service>>& services)
{ {
} }
@@ -432,11 +381,11 @@ void DataStore::saveServices()
Function: saveComboPackages Function: saveComboPackages
Description: Persists all combo package records to the datastore. Description: Persists all combo package records to the datastore.
Parameters: Parameters:
- None - comboPackages: util::Map<std::string, TrackedRecord<ComboPackage>>&, collection of combo package records
Returns: Returns:
- None - None
*/ */
void DataStore::saveComboPackages() void DataStore::saveComboPackages(util::Map<std::string, TrackedRecord<ComboPackage>>& comboPackages)
{ {
} }
@@ -444,11 +393,11 @@ void DataStore::saveComboPackages()
Function: saveInventoryItems Function: saveInventoryItems
Description: Persists all inventory item records to the datastore. Description: Persists all inventory item records to the datastore.
Parameters: Parameters:
- None - inventoryItems: util::Map<std::string, TrackedRecord<InventoryItem>>&, collection of inventory item records
Returns: Returns:
- None - None
*/ */
void DataStore::saveInventoryItems() void DataStore::saveInventoryItems(util::Map<std::string, TrackedRecord<InventoryItem>>& inventoryItems)
{ {
} }
@@ -456,11 +405,11 @@ void DataStore::saveInventoryItems()
Function: saveServiceBookings Function: saveServiceBookings
Description: Persists all service booking records to the datastore. Description: Persists all service booking records to the datastore.
Parameters: Parameters:
- None - bookings: util::Map<std::string, TrackedRecord<ServiceBooking>>&, collection of service booking records
Returns: Returns:
- None - None
*/ */
void DataStore::saveServiceBookings() void DataStore::saveServiceBookings(util::Map<std::string, TrackedRecord<ServiceBooking>>& bookings)
{ {
} }
@@ -468,11 +417,11 @@ void DataStore::saveServiceBookings()
Function: saveJobCards Function: saveJobCards
Description: Persists all job card records to the datastore. Description: Persists all job card records to the datastore.
Parameters: Parameters:
- None - jobCards: util::Map<std::string, TrackedRecord<JobCard>>&, collection of job card records
Returns: Returns:
- None - None
*/ */
void DataStore::saveJobCards() void DataStore::saveJobCards(util::Map<std::string, TrackedRecord<JobCard>>& jobCards)
{ {
} }
@@ -480,83 +429,86 @@ void DataStore::saveJobCards()
Function: saveInvoices Function: saveInvoices
Description: Persists all invoice records to the datastore. Description: Persists all invoice records to the datastore.
Parameters: Parameters:
- None - invoices: util::Map<std::string, TrackedRecord<Invoice>>&, collection of invoice records
Returns: Returns:
- None - None
*/ */
void DataStore::saveInvoices() void DataStore::saveInvoices(util::Map<std::string, TrackedRecord<Invoice>>& invoices)
{ {
} }
/* /*
Function: saveObservers Function: savePayments
Description: Persists observer records to the specified observer mapping. Description: Persists all payment records to the datastore.
Parameters: Parameters:
- mapping: MappingInfo&, observer mapping to save to - payments: util::Map<std::string, TrackedRecord<Payment>>&, collection of payment records
- observers: util::Map<std::string, User*>&, collection of observer records
Returns: Returns:
- None - None
*/ */
void DataStore::saveObservers(MappingInfo& mapping, util::Map<std::string, User*>& observers) void DataStore::savePayments(util::Map<std::string, TrackedRecord<Payment>>& payments)
{ {
size_t observerCount = static_cast<size_t>(observers.getSize());
size_t capacity = config::file::INITIAL_CAPACITY;
while (capacity < observerCount)
{
capacity *= config::file::GROWTH_FACTOR;
}
if (!SharedMemory::resizeMapping(mapping, capacity))
{
throw std::runtime_error("Failed to resize observer mapping");
}
SharedMemory::setRecordCount(mapping, observerCount);
for (size_t index = 0; index < observerCount; index++)
{
SerializedObserver serializedObserver;
User* user = observers.getValueAt(static_cast<int>(index));
strcpy_s(serializedObserver.id, sizeof(serializedObserver.id), user->getId().c_str());
SerializedObserver* destination = static_cast<SerializedObserver*>(SharedMemory::getRecordAddress(mapping, index));
*destination = serializedObserver;
}
} }
/* /*
Function: saveServiceManagementObservers Function: saveServiceManagementObservers
Description: Persists all service management observer records to the datastore. Description: Persists all service management observer records to the datastore.
Parameters: Parameters:
- observers: util::Map<std::string, User*>&, collection of observer records - observers: util::Map<std::string, TrackedRecord<std::string>>&, collection of observer records
Returns: Returns:
- None - None
*/ */
void DataStore::saveServiceManagementObservers(util::Map<std::string, User*>& observers) void DataStore::saveServiceManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& observers)
{ {
saveObservers(m_serviceManagementObservers, observers);
} }
/* /*
Function: savePaymentManagementObservers Function: savePaymentManagementObservers
Description: Persists all payment management observer records to the datastore. Description: Persists all payment management observer records to the datastore.
Parameters: Parameters:
- observers: util::Map<std::string, User*>&, collection of observer records - observers: util::Map<std::string, TrackedRecord<std::string>>&, collection of observer records
Returns: Returns:
- None - None
*/ */
void DataStore::savePaymentManagementObservers(util::Map<std::string, User*>& observers) void DataStore::savePaymentManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& observers)
{ {
saveObservers(m_paymentManagementObservers, observers);
} }
/* /*
Function: saveInventoryManagementObservers Function: saveInventoryManagementObservers
Description: Persists all inventory management observer records to the datastore. Description: Persists all inventory management observer records to the datastore.
Parameters: Parameters:
- observers: util::Map<std::string, User*>&, collection of observer records - observers: util::Map<std::string, TrackedRecord<std::string>>&, collection of observer records
Returns: Returns:
- None - None
*/ */
void DataStore::saveInventoryManagementObservers(util::Map<std::string, User*>& observers) void DataStore::saveInventoryManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& observers)
{ {
saveObservers(m_inventoryManagementObservers, observers); }
/*
Function: lockDataStore
Description: Acquires exclusive access to the datastore.
Parameters:
- None
Returns:
- bool: True if the datastore was successfully locked, otherwise false
*/
bool DataStore::lockDataStore()
{
return false;
}
/*
Function: unlockDataStore
Description: Releases exclusive access to the datastore.
Parameters:
- None
Returns:
- bool: True if the datastore was successfully unlocked, otherwise false
*/
bool DataStore::unlockDataStore()
{
return false;
} }
/* /*
@@ -601,5 +553,4 @@ bool DataStore::unlockDataStore()
return false; return false;
} }
return ReleaseMutex(m_globalMutex) != 0; return ReleaseMutex(m_globalMutex) != 0;
} }
@@ -12,20 +12,20 @@ Date: 19-May-2026
#include "MappingInfo.h" #include "MappingInfo.h"
#include "TrackedRecord.h" #include "TrackedRecord.h"
#include "SharedMemory.h" #include "SharedMemory.h"
#include "User.h" class User;
#include "Notification.h" class Notification;
#include "Service.h" class Service;
#include "ComboPackage.h" class ComboPackage;
#include "InventoryItem.h" class InventoryItem;
#include "ServiceBooking.h" class ServiceBooking;
#include "JobCard.h" class JobCard;
#include "Invoice.h" class Invoice;
class Payment;
class DataStore class DataStore
{ {
private: private:
DataStore(); DataStore();
~DataStore();
DataStore(const DataStore&) = delete; DataStore(const DataStore&) = delete;
DataStore& operator=(const DataStore&) = delete; DataStore& operator=(const DataStore&) = delete;
DataStore(DataStore&&) = delete; DataStore(DataStore&&) = delete;
@@ -39,43 +39,38 @@ private:
MappingInfo m_serviceBookings; MappingInfo m_serviceBookings;
MappingInfo m_jobCards; MappingInfo m_jobCards;
MappingInfo m_invoices; MappingInfo m_invoices;
MappingInfo m_payments;
MappingInfo m_serviceManagementObservers; MappingInfo m_serviceManagementObservers;
MappingInfo m_paymentManagementObservers; MappingInfo m_paymentManagementObservers;
MappingInfo m_inventoryManagementObservers; MappingInfo m_inventoryManagementObservers;
util::Map<std::string, TrackedRecord<User>> m_userCache;
util::Map<std::string, TrackedRecord<Notification>> m_notificationCache;
util::Map<std::string, TrackedRecord<Service>> m_serviceCache;
util::Map<std::string, TrackedRecord<ComboPackage>> m_comboPackageCache;
util::Map<std::string, TrackedRecord<InventoryItem>> m_inventoryItemCache;
util::Map<std::string, TrackedRecord<ServiceBooking>> m_serviceBookingCache;
util::Map<std::string, TrackedRecord<JobCard>> m_jobCardCache;
util::Map<std::string, TrackedRecord<Invoice>> m_invoiceCache;
public: public:
static DataStore& getInstance(); static DataStore& getInstance();
bool initialize(); bool initialize();
void shutdown(); void shutdown();
util::Map<std::string, TrackedRecord<User>>& getUsers(); util::Map<std::string, TrackedRecord<User>> getUsers();
util::Map<std::string, TrackedRecord<Notification>>& getNotifications(); util::Map<std::string, TrackedRecord<Notification>> getNotifications();
util::Map<std::string, TrackedRecord<Service>>& getServices(); util::Map<std::string, TrackedRecord<Service>> getServices();
util::Map<std::string, TrackedRecord<ComboPackage>>& getComboPackages(); util::Map<std::string, TrackedRecord<ComboPackage>> getComboPackages();
util::Map<std::string, TrackedRecord<InventoryItem>>& getInventoryItems(); util::Map<std::string, TrackedRecord<InventoryItem>> getInventoryItems();
util::Map<std::string, TrackedRecord<ServiceBooking>>& getServiceBookings(); util::Map<std::string, TrackedRecord<ServiceBooking>> getServiceBookings();
util::Map<std::string, TrackedRecord<JobCard>>& getJobCards(); util::Map<std::string, TrackedRecord<JobCard>> getJobCards();
util::Map<std::string, TrackedRecord<Invoice>>& getInvoices(); util::Map<std::string, TrackedRecord<Invoice>> getInvoices();
util::Map<std::string, User*> getServiceManagementObservers(); util::Map<std::string, TrackedRecord<Payment>> getPayments();
util::Map<std::string, User*> getPaymentManagementObservers(); util::Map<std::string, TrackedRecord<std::string>> getServiceManagementObservers();
util::Map<std::string, User*> getInventoryManagementObservers(); util::Map<std::string, TrackedRecord<std::string>> getPaymentManagementObservers();
void saveUsers(); util::Map<std::string, TrackedRecord<std::string>> getInventoryManagementObservers();
void saveNotifications(); void saveUsers(util::Map<std::string, TrackedRecord<User>>& users);
void saveServices(); void saveNotifications(util::Map<std::string, TrackedRecord<Notification>>& notifications);
void saveComboPackages(); void saveServices(util::Map<std::string, TrackedRecord<Service>>& services);
void saveInventoryItems(); void saveComboPackages(util::Map<std::string, TrackedRecord<ComboPackage>>& comboPackages);
void saveServiceBookings(); void saveInventoryItems(util::Map<std::string, TrackedRecord<InventoryItem>>& inventoryItems);
void saveJobCards(); void saveServiceBookings(util::Map<std::string, TrackedRecord<ServiceBooking>>& bookings);
void saveInvoices(); void saveJobCards(util::Map<std::string, TrackedRecord<JobCard>>& jobCards);
void saveServiceManagementObservers(util::Map<std::string, User*>& observers); void saveInvoices(util::Map<std::string, TrackedRecord<Invoice>>& invoices);
void savePaymentManagementObservers(util::Map<std::string, User*>& observers); void savePayments(util::Map<std::string, TrackedRecord<Payment>>& payments);
void saveInventoryManagementObservers(util::Map<std::string, User*>& observers); void saveServiceManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& observers);
void savePaymentManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& observers);
void saveInventoryManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& observers);
bool lockDataStore(); bool lockDataStore();
bool unlockDataStore(); bool unlockDataStore();
private: private:
@@ -83,10 +78,6 @@ private:
util::Map<std::string, TrackedRecord<TObject>> loadRecords(MappingInfo& mapping); util::Map<std::string, TrackedRecord<TObject>> loadRecords(MappingInfo& mapping);
template<typename TObject, typename TSerialized> template<typename TObject, typename TSerialized>
void saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records); void saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records);
template<typename TObject> void clearCache(util::Map<std::string, TrackedRecord<TObject>>&cache);
template<typename TObject> void refreshCache(util::Map<std::string, TrackedRecord<TObject>>&cache, util::Map<std::string, TrackedRecord<TObject>>&refreshedCache);
util::Map<std::string, User*> getObservers(MappingInfo& mapping);
void saveObservers(MappingInfo& mapping, util::Map<std::string, User*>& observers);
}; };
/* /*
@@ -132,7 +123,9 @@ Description: Persists all modified and newly added records
shared-memory mapping. Modified records overwrite shared-memory mapping. Modified records overwrite
their existing slots, while new records are their existing slots, while new records are
appended to the end of the mapping. Records marked appended to the end of the mapping. Records marked
as CLEAN are ignored. as CLEAN are ignored. After persistence, all
temporary objects owned by the tracked records are
destroyed to release memory.
Parameter: Parameter:
- mapping: Reference to the mapping where records are - mapping: Reference to the mapping where records are
stored. stored.
@@ -165,82 +158,14 @@ template<typename TObject, typename TSerialized> void DataStore::saveRecords(Map
continue; continue;
} }
size_t recordCount = SharedMemory::getRecordCount(mapping); size_t recordCount = SharedMemory::getRecordCount(mapping);
TSerialized* destination = static_cast<TSerialized*>(SharedMemory::getRecordAddress(mapping,recordCount)); TSerialized* destination = static_cast<TSerialized*>(SharedMemory::getRecordAddress(mapping, recordCount));
*destination = serialized; *destination = serialized;
SharedMemory::setRecordCount(mapping, recordCount + 1); SharedMemory::setRecordCount(mapping, recordCount + 1);
record.slotIndex = recordCount;
} }
record.state = RecordState::CLEAN;
} }
} for (int index = 0; index < records.getSize(); ++index)
/*
Function: clearCache
Description: Releases all objects owned by the cache and
clears the cache contents.
Parameters:
- cache: Cache to be cleared.
Returns:
- None
*/
template<typename TObject>
void DataStore::clearCache(util::Map<std::string, TrackedRecord<TObject>>&cache)
{
for (int index = 0; index < cache.getSize(); ++index)
{ {
delete cache.getValueAt(index).data; delete records.getValueAt(index).data;
cache.getValueAt(index).data = nullptr; records.getValueAt(index).data = nullptr;
}
cache.clear();
}
/*
Function: refreshCache
Description: Refreshes the cache while preserving object addresses
for records that already exist. Existing objects are
updated in-place so that pointers held elsewhere remain
valid after the refresh.
Parameters:
- cache: Existing cache to refresh.
- refreshedCache: Newly loaded cache contents.
Returns:
- None
*/
template<typename TObject>
void DataStore::refreshCache(util::Map<std::string, TrackedRecord<TObject>>& cache, util::Map<std::string, TrackedRecord<TObject>>& refreshedCache)
{
util::Map<std::string, TrackedRecord<TObject>> oldCache = cache;
cache.clear();
for (int index = 0; index < refreshedCache.getSize(); ++index)
{
const std::string& id = refreshedCache.getKeyAt(index);
TrackedRecord<TObject>& refreshedRecord = refreshedCache.getValueAt(index);
int oldIndex = oldCache.find(id);
if (oldIndex != -1)
{
TrackedRecord<TObject>& oldRecord = oldCache.getValueAt(oldIndex);
*oldRecord.data = *refreshedRecord.data;
oldRecord.slotIndex = refreshedRecord.slotIndex;
oldRecord.state = refreshedRecord.state;
delete refreshedRecord.data;
refreshedRecord.data = oldRecord.data;
}
cache.insert(id, refreshedRecord);
}
for (int index = 0; index < oldCache.getSize(); ++index)
{
const std::string& id = oldCache.getKeyAt(index);
const TrackedRecord<TObject>& localTrackedRecord = oldCache.getValueAt(index);
if (cache.find(id) == -1)
{
if (localTrackedRecord.state == RecordState::NEW_RECORD)
{
cache.insert(id, localTrackedRecord);
}
else
{
delete localTrackedRecord.data;
}
}
} }
} }
@@ -1,28 +0,0 @@
/*
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;
};
@@ -10,7 +10,6 @@ Created: 11-June-2026
*/ */
#include "SharedMemory.h" #include "SharedMemory.h"
#include "Windows.h"
#include "Config.h" #include "Config.h"
/* /*
@@ -320,7 +319,7 @@ bool SharedMemory::ensureCapacityForInsert(MappingInfo& mapping)
{ {
return true; return true;
} }
return resizeMapping(mapping, capacity * config::file::GROWTH_FACTOR); return resizeMapping(mapping, capacity * 2);
} }
/* /*
@@ -9,6 +9,7 @@ Date: 19-May-2026
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include "SerializedRecords.h"
#include "ComboPackage.h" #include "ComboPackage.h"
#include "Service.h" #include "Service.h"
#include "Factory.h" #include "Factory.h"
@@ -270,72 +271,38 @@ static util::Vector<std::string> getServiceIDsAsVector(const std::string& servic
/* /*
Function: serialize Function: serialize
Description: Serializes the combo package into a CSV-formatted string. Description: Serializes the ComboPackage object into a SerializedComboPackage record.
Parameters: Parameters:
- None - None
Returns: Returns:
- std::string: Serialized combo package record - SerializedComboPackage: Serialized representation of the combo package
*/ */
std::string ComboPackage::serialize() const SerializedComboPackage ComboPackage::serialize() const
{ {
std::ostringstream serializedComboPackage; SerializedComboPackage serialized = {};
serializedComboPackage << m_id << ',' strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str());
<< m_packageName << ',' strcpy_s(serialized.packageName, sizeof(serialized.packageName), m_packageName.c_str());
<< m_discountPercentage << ',' strcpy_s(serialized.serviceIDs, sizeof(serialized.serviceIDs), getServiceIDsAsString(m_serviceIDs).c_str());
<< getServiceIDsAsString(m_serviceIDs) << ',' serialized.discountPercentage = m_discountPercentage;
<< util::getStateString(m_status); serialized.status = m_status;
return serializedComboPackage.str(); return serialized;
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a CSV-formatted string into a ComboPackage object. Description: Deserializes a SerializedComboPackage record into a ComboPackage object.
Parameters: Parameters:
- record: const std::string&, serialized combo package record - serializedComboPackage: const SerializedComboPackage&, serialized combo package record
Returns: Returns:
- ComboPackage*: Pointer to the deserialized ComboPackage object - ComboPackage*: Pointer to the deserialized ComboPackage object
Throws:
- std::runtime_error if data is invalid
*/ */
ComboPackage* ComboPackage::deserialize(const std::string& record) ComboPackage* ComboPackage::deserialize(const SerializedComboPackage& serializedComboPackage)
{ {
std::string id, packageName; util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serializedComboPackage.serviceIDs);
std::string discountPercentageString, serviceIDsString, statusString;
double discountPercentage;
std::istringstream serializedComboPackage(record);
getline(serializedComboPackage, id, ',');
getline(serializedComboPackage, packageName, ',');
getline(serializedComboPackage, discountPercentageString, ',');
getline(serializedComboPackage, serviceIDsString, ',');
getline(serializedComboPackage, statusString, ',');
try
{
discountPercentage = std::stod(discountPercentageString);
}
catch (...)
{
throw std::runtime_error("Invalid combo package data");
}
util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serviceIDsString);
util::State status = util::getState(statusString);
return Factory::getObject<ComboPackage>( return Factory::getObject<ComboPackage>(
id, serializedComboPackage.id,
packageName, serializedComboPackage.packageName,
discountPercentage, serializedComboPackage.discountPercentage,
serviceIDs, serviceIDs,
status serializedComboPackage.status);
); }
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for combo package serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,PackageName,DiscountPercentage,ServiceIDs,Status")
*/
std::string ComboPackage::getHeaders()
{
return "ID,PackageName,DiscountPercentage,ServiceIDs,Status";
}
@@ -12,7 +12,7 @@ Date: 19-May-2026
#include "Enums.h" #include "Enums.h"
class Service; class Service;
struct SerializedComboPackage; class SerializedComboPackage;
class ComboPackage class ComboPackage
{ {
@@ -39,7 +39,6 @@ public:
void setDiscountPercentage(double discountPercentage); void setDiscountPercentage(double discountPercentage);
void setServices(const util::Map<std::string, Service*>& services); void setServices(const util::Map<std::string, Service*>& services);
void setState(util::State status); void setState(util::State status);
std::string serialize() const; SerializedComboPackage serialize() const;
static ComboPackage* deserialize(const std::string&); static ComboPackage* deserialize(const SerializedComboPackage&);
static std::string getHeaders();
}; };
@@ -8,6 +8,7 @@ Date: 19-May-2026
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include "SerializedRecords.h"
#include "Factory.h" #include "Factory.h"
#include "StringHelper.h" #include "StringHelper.h"
#include "InventoryItem.h" #include "InventoryItem.h"
@@ -206,73 +207,37 @@ void InventoryItem::setState(util::State status)
/* /*
Function: serialize Function: serialize
Description: Serializes the inventory item into a CSV-formatted string. Description: Serializes the InventoryItem object into a SerializedInventoryItem record.
Parameters: Parameters:
- None - None
Returns: Returns:
- std::string: Serialized inventory item record - SerializedInventoryItem: Serialized representation of the inventory item
*/ */
std::string InventoryItem::serialize() const SerializedInventoryItem InventoryItem::serialize() const
{ {
std::ostringstream serializedInventoryItem; SerializedInventoryItem serialized = {};
serializedInventoryItem << m_id << ',' strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str());
<< m_partName << ',' strcpy_s(serialized.partName, sizeof(serialized.partName), m_partName.c_str());
<< m_quantity << ',' serialized.quantity = m_quantity;
<< m_price << ',' serialized.price = m_price;
<< util::getStateString(m_status); serialized.status = m_status;
return serializedInventoryItem.str(); return serialized;
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a CSV-formatted string into an InventoryItem object. Description: Deserializes a SerializedInventoryItem record into an InventoryItem object.
Parameters: Parameters:
- record: const std::string&, serialized inventory item record - serializedInventoryItem: const SerializedInventoryItem&, serialized inventory item record
Returns: Returns:
- InventoryItem*: Pointer to the deserialized InventoryItem object - InventoryItem*: Pointer to the deserialized InventoryItem object
Throws:
- std::runtime_error if data is invalid
*/ */
InventoryItem* InventoryItem::deserialize(const std::string& record) InventoryItem* InventoryItem::deserialize(const SerializedInventoryItem& serializedInventoryItem)
{ {
std::string id, partName;
std::string quantityString, priceString, statusString;
int quantity;
double price;
std::istringstream serializedInventoryItem(record);
getline(serializedInventoryItem, id, ',');
getline(serializedInventoryItem, partName, ',');
getline(serializedInventoryItem, quantityString, ',');
getline(serializedInventoryItem, priceString, ',');
getline(serializedInventoryItem, statusString, ',');
try
{
quantity = std::stoi(quantityString);
price = std::stod(priceString);
}
catch (...)
{
throw std::runtime_error("Invalid inventory item data");
}
util::State status = util::getState(statusString);
return Factory::getObject<InventoryItem>( return Factory::getObject<InventoryItem>(
id, serializedInventoryItem.id,
partName, serializedInventoryItem.partName,
quantity, serializedInventoryItem.quantity,
price, serializedInventoryItem.price,
status serializedInventoryItem.status);
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for inventory item serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,PartName,Quantity,Price,Status")
*/
std::string InventoryItem::getHeaders()
{
return "ID,PartName,Quantity,Price,Status";
} }
@@ -6,11 +6,12 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "Enums.h" #include "Enums.h"
struct SerializedInventoryItem;
class InventoryItem class InventoryItem
{ {
private: private:
@@ -34,7 +35,6 @@ public:
void setQuantity(int quantity); void setQuantity(int quantity);
void setPrice(double price); void setPrice(double price);
void setState(util::State status); void setState(util::State status);
std::string serialize() const; SerializedInventoryItem serialize() const;
static InventoryItem* deserialize(const std::string&); static InventoryItem* deserialize(const SerializedInventoryItem&);
static std::string getHeaders();
}; };
@@ -9,6 +9,7 @@ Date: 19-May-2026
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include "SerializedRecords.h"
#include "Invoice.h" #include "Invoice.h"
#include "Factory.h" #include "Factory.h"
#include "InventoryItem.h" #include "InventoryItem.h"
@@ -473,100 +474,50 @@ static util::Vector<std::string> getPartIDsAsVector(const std::string& partIDsSt
/* /*
Function: serialize Function: serialize
Description: Serializes the invoice into a CSV-formatted string. Description: Serializes the Invoice object into a SerializedInvoice record.
Parameters: Parameters:
- None - None
Returns: Returns:
- std::string: Serialized invoice record - SerializedInvoice: Serialized representation of the invoice
*/ */
std::string Invoice::serialize() const SerializedInvoice Invoice::serialize() const
{ {
std::ostringstream serializedInvoice; SerializedInvoice serialized = {};
serializedInvoice << m_id << ',' strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str());
<< m_bookingId << ',' strcpy_s(serialized.bookingId, sizeof(serialized.bookingId), m_bookingId.c_str());
<< m_invoiceDate.toString() << ',' strcpy_s(serialized.partIDs, sizeof(serialized.partIDs), getPartIDsAsString(m_partIDs).c_str());
<< m_laborCost << ',' serialized.invoiceDate = m_invoiceDate;
<< getPartIDsAsString(m_partIDs) << ',' serialized.laborCost = m_laborCost;
<< m_partsCost << ',' serialized.partsCost = m_partsCost;
<< m_discountPercentage << ',' serialized.discountPercentage = m_discountPercentage;
<< m_totalAmount << ',' serialized.totalAmount = m_totalAmount;
<< m_paymentDate.toString() << ',' serialized.paymentDate = m_paymentDate;
<< util::getPaymentModeString(m_paymentMethod) << ',' serialized.paymentMethod = m_paymentMethod;
<< util::getPaymentStatusString(m_status); serialized.status = m_status;
return serializedInvoice.str(); return serialized;
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a CSV-formatted string into an Invoice object. Description: Deserializes a SerializedInvoice record into an Invoice object.
Parameters: Parameters:
- record: const std::string&, serialized invoice record - serializedInvoice: const SerializedInvoice&, serialized invoice record
Returns: Returns:
- Invoice*: Pointer to the deserialized Invoice object - Invoice*: Pointer to the deserialized Invoice object
Throws:
- std::runtime_error if data is invalid
*/ */
Invoice* Invoice::deserialize(const std::string& record) Invoice* Invoice::deserialize(const SerializedInvoice& serializedInvoice)
{ {
std::string id, bookingId; util::Vector<std::string> partIDs = getPartIDsAsVector(serializedInvoice.partIDs);
std::string invoiceDateString, laborCostString, partIDsString;
std::string partsCostString, discountPercentageString, totalAmountString;
std::string paymentDateString, paymentMethodString, statusString;
double laborCost, partsCost, discountPercentage, totalAmount;
std::istringstream serializedInvoice(record);
getline(serializedInvoice, id, ',');
getline(serializedInvoice, bookingId, ',');
getline(serializedInvoice, invoiceDateString, ',');
getline(serializedInvoice, laborCostString, ',');
getline(serializedInvoice, partIDsString, ',');
getline(serializedInvoice, partsCostString, ',');
getline(serializedInvoice, discountPercentageString, ',');
getline(serializedInvoice, totalAmountString, ',');
getline(serializedInvoice, paymentDateString, ',');
getline(serializedInvoice, paymentMethodString, ',');
getline(serializedInvoice, statusString, ',');
util::Timestamp invoiceDate;
util::Timestamp paymentDate;
try
{
invoiceDate = util::Timestamp::fromString(invoiceDateString);
paymentDate = util::Timestamp::fromString(paymentDateString);
laborCost = std::stod(laborCostString);
partsCost = std::stod(partsCostString);
discountPercentage = std::stod(discountPercentageString);
totalAmount = std::stod(totalAmountString);
}
catch (...)
{
throw std::runtime_error("Invalid invoice data");
}
util::Vector<std::string> partIDs = getPartIDsAsVector(partIDsString);
util::PaymentMode paymentMethod = util::getPaymentMode(paymentMethodString);
util::PaymentStatus status = util::getPaymentStatus(statusString);
return Factory::getObject<Invoice>( return Factory::getObject<Invoice>(
id, serializedInvoice.id,
bookingId, serializedInvoice.bookingId,
invoiceDate, serializedInvoice.invoiceDate,
partIDs, partIDs,
laborCost, serializedInvoice.laborCost,
partsCost, serializedInvoice.partsCost,
discountPercentage, serializedInvoice.discountPercentage,
totalAmount, serializedInvoice.totalAmount,
paymentDate, serializedInvoice.paymentDate,
paymentMethod, serializedInvoice.paymentMethod,
status serializedInvoice.status);
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for invoice serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,BookingID,InvoiceDate,LaborCost,PartIDs,PartsCost,DiscountPercentage,TotalAmount,PaymentDate,PaymentMethod,Status")
*/
std::string Invoice::getHeaders()
{
return "ID,BookingID,InvoiceDate,LaborCost,PartIDs,PartsCost,DiscountPercentage,TotalAmount,PaymentDate,PaymentMethod,Status";
} }
@@ -16,6 +16,7 @@ Date: 19-May-2026
class ServiceBooking; class ServiceBooking;
class InventoryItem; class InventoryItem;
struct SerializedInvoice;
class Invoice class Invoice
{ {
@@ -87,7 +88,6 @@ public:
void setPaymentDate(const util::Timestamp& paymentDate); void setPaymentDate(const util::Timestamp& paymentDate);
void setPaymentMethod(util::PaymentMode paymentMethod); void setPaymentMethod(util::PaymentMode paymentMethod);
void setStatus(util::PaymentStatus status); void setStatus(util::PaymentStatus status);
std::string serialize() const; SerializedInvoice serialize() const;
static Invoice* deserialize(const std::string&); static Invoice* deserialize(const SerializedInvoice&);
static std::string getHeaders();
}; };
@@ -9,6 +9,7 @@ Date:19-May-2026
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include "SerializedRecords.h"
#include "JobCard.h" #include "JobCard.h"
#include "Factory.h" #include "Factory.h"
#include "StringHelper.h" #include "StringHelper.h"
@@ -351,79 +352,41 @@ void JobCard::setCompletionDate(const util::Timestamp& completionDate)
/* /*
Function: serialize Function: serialize
Description: Serializes the job card into a CSV-formatted string. Description: Serializes the JobCard object into a SerializedJobCard record.
Parameters: Parameters:
- None - None
Returns: Returns:
- std::string: Serialized job card record - SerializedJobCard: Serialized representation of the job card
*/ */
std::string JobCard::serialize() const SerializedJobCard JobCard::serialize() const
{ {
std::ostringstream serializedJobCard; SerializedJobCard serialized = {};
serializedJobCard << m_id << ',' strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str());
<< m_bookingId << ',' strcpy_s(serialized.bookingId, sizeof(serialized.bookingId), m_bookingId.c_str());
<< m_serviceId << ',' strcpy_s(serialized.serviceId, sizeof(serialized.serviceId), m_serviceId.c_str());
<< m_technicianId << ',' strcpy_s(serialized.technicianId, sizeof(serialized.technicianId), m_technicianId.c_str());
<< m_assignedDate.toString() << ',' serialized.assignedDate = m_assignedDate;
<< util::getServiceJobStatusString(m_status) << ',' serialized.status = m_status;
<< m_completionDate.toString(); serialized.completionDate = m_completionDate;
return serializedJobCard.str(); return serialized;
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a CSV-formatted string into a JobCard object. Description: Deserializes a SerializedJobCard record into a JobCard object.
Parameters: Parameters:
- record: const std::string&, serialized job card record - serializedJobCard: const SerializedJobCard&, serialized job card record
Returns: Returns:
- JobCard*: Pointer to the deserialized JobCard object - JobCard*: Pointer to the deserialized JobCard object
Throws:
- std::runtime_error if timestamp parsing fails
*/ */
JobCard* JobCard::deserialize(const std::string& record) JobCard* JobCard::deserialize(const SerializedJobCard& serializedJobCard)
{ {
std::string id, bookingId, serviceId, technicianId;
std::string assignedDateString, statusString, completionDateString;
std::istringstream serializedJobCard(record);
getline(serializedJobCard, id, ',');
getline(serializedJobCard, bookingId, ',');
getline(serializedJobCard, serviceId, ',');
getline(serializedJobCard, technicianId, ',');
getline(serializedJobCard, assignedDateString, ',');
getline(serializedJobCard, statusString, ',');
getline(serializedJobCard, completionDateString, ',');
util::Timestamp assignedDate;
util::Timestamp completionDate;
try
{
assignedDate = util::Timestamp::fromString(assignedDateString);
completionDate = util::Timestamp::fromString(completionDateString);
}
catch (...)
{
throw std::runtime_error("Invalid timestamp");
}
util::ServiceJobStatus status = util::getServiceJobStatus(statusString);
return Factory::getObject<JobCard>( return Factory::getObject<JobCard>(
id, serializedJobCard.id,
bookingId, serializedJobCard.bookingId,
serviceId, serializedJobCard.serviceId,
technicianId, serializedJobCard.technicianId,
assignedDate, serializedJobCard.assignedDate,
status, serializedJobCard.status,
completionDate serializedJobCard.completionDate);
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for job card serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,BookingID,ServiceID,TechnicianID,AssignedDate,Status,CompletionDate")
*/
std::string JobCard::getHeaders()
{
return "ID,BookingID,ServiceID,TechnicianID,AssignedDate,Status,CompletionDate";
} }
@@ -15,6 +15,7 @@ Date:19-May-2026
class ServiceBooking; class ServiceBooking;
class Service; class Service;
class User; class User;
struct SerializedJobCard;
class JobCard class JobCard
{ {
@@ -70,7 +71,6 @@ public:
void setAssignedDate(const util::Timestamp& assignedDate); void setAssignedDate(const util::Timestamp& assignedDate);
void setStatus(util::ServiceJobStatus status); void setStatus(util::ServiceJobStatus status);
void setCompletionDate(const util::Timestamp& completionDate); void setCompletionDate(const util::Timestamp& completionDate);
std::string serialize() const; SerializedJobCard serialize() const;
static JobCard* deserialize(const std::string&); static JobCard* deserialize(const SerializedJobCard&);
static std::string getHeaders();
}; };
@@ -1,7 +1,7 @@
/* /*
File: Notification.cpp File: Notification.cpp
Description: Implements the Notification class which represents system notifications in the Vehicle Service Management System. Description: Implements the Notification class which represents system notifications in the Vehicle Service Management System.
Provides constructors, accessors, and mutators for notification details such as ID, recipientID, title, message, and timestamp. Provides constructors, accessors, and mutators for notification details such as ID, recipient, title, message, and timestamp.
Author: Trenser Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
@@ -23,8 +23,8 @@ Returns:
- A new Notification object. - A new Notification object.
*/ */
Notification::Notification() Notification::Notification()
: m_id("NOT" + std::to_string(++m_uid)), : m_id("NOT" + std::to_string(++m_uid)),
m_state(util::State::ACTIVE) {} m_recipient(nullptr), m_state(util::State::ACTIVE) {}
/* /*
Function: Notification Function: Notification
@@ -38,14 +38,14 @@ Parameters:
Returns: Returns:
- A new Notification object. - A new Notification object.
*/ */
Notification::Notification(const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt) Notification::Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt)
: m_id("NOT" + std::to_string(++m_uid)), : m_id("NOT" + std::to_string(++m_uid)),
m_recipientUserId(recipientUserId), m_recipientUserId(recipientUserId),
m_recipient(recipient),
m_title(title), m_title(title),
m_message(message), m_message(message),
m_state(util::State::ACTIVE), m_state(util::State::ACTIVE),
m_createdAt(createdAt) { m_createdAt(createdAt){}
}
/* /*
Function: Notification (parameterized constructor with ID) Function: Notification (parameterized constructor with ID)
@@ -63,6 +63,7 @@ Returns:
Notification::Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt, const util::State& state) Notification::Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt, const util::State& state)
: m_id(id), : m_id(id),
m_recipientUserId(recipientUserId), m_recipientUserId(recipientUserId),
m_recipient(nullptr),
m_title(title), m_title(title),
m_message(message), m_message(message),
m_createdAt(createdAt), m_createdAt(createdAt),
@@ -81,7 +82,7 @@ Description: Retrieves the unique ID of the notification.
Returns: Returns:
- const std::string& representing the notification ID. - const std::string& representing the notification ID.
*/ */
const std::string& Notification::getId() const const std::string& Notification::getId() const
{ {
return m_id; return m_id;
} }
@@ -97,6 +98,17 @@ const std::string& Notification::getRecipientUserId() const
return m_recipientUserId; return m_recipientUserId;
} }
/*
Function: getRecipient
Description: Retrieves the pointer to the recipient user.
Returns:
- User* representing the recipient.
*/
User* Notification::getRecipient() const
{
return m_recipient;
}
/* /*
Function: getTitle Function: getTitle
Description: Retrieves the title of the notification. Description: Retrieves the title of the notification.
@@ -130,17 +142,6 @@ const util::Timestamp& Notification::getCreatedAt() const
return m_createdAt; return m_createdAt;
} }
/*
Function: getState
Description: Retrieves the Notification state
Returns:
- const util::Timestamp& representing the creation timestamp.
*/
util::State Notification::getState() const
{
return m_state;
}
/* /*
Function: setId Function: setId
Description: Sets the unique ID of the notification. Description: Sets the unique ID of the notification.
@@ -167,6 +168,19 @@ void Notification::setRecipientUserId(const std::string& recipientUserId)
m_recipientUserId = recipientUserId; m_recipientUserId = recipientUserId;
} }
/*
Function: setRecipient
Description: Sets the recipient user pointer for the notification.
Parameters:
- recipient: Pointer to the User object.
Returns:
- void
*/
void Notification::setRecipient(User* recipient)
{
m_recipient = recipient;
}
/* /*
Function: setTitle Function: setTitle
Description: Sets the title of the notification. Description: Sets the title of the notification.
@@ -206,19 +220,6 @@ void Notification::setCreatedAt(const util::Timestamp& createdAt)
m_createdAt = createdAt; m_createdAt = createdAt;
} }
/*
Function: setState
Description: Sets the Notification state.
Parameters:
- state: Notification state value.
Returns:
- void
*/
void Notification::setState(util::State state)
{
m_state = state;
}
/* /*
Function: serialize Function: serialize
Description: Serializes the Notification object into a SerializedNotification record. Description: Serializes the Notification object into a SerializedNotification record.
@@ -20,25 +20,28 @@ private:
static int m_uid; static int m_uid;
std::string m_id; std::string m_id;
std::string m_recipientUserId; std::string m_recipientUserId;
User* m_recipient;
std::string m_title; std::string m_title;
std::string m_message; std::string m_message;
util::Timestamp m_createdAt; util::Timestamp m_createdAt;
util::State m_state; util::State m_state;
public: public:
Notification(); Notification();
Notification(const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt); Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt);
Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt, const util::State& state); Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt, const util::State& state);
const std::string& getId() const; const std::string& getId() const;
const std::string& getRecipientUserId() const; const std::string& getRecipientUserId() const;
User* getRecipient() const;
const std::string& getTitle() const; const std::string& getTitle() const;
const std::string& getMessage() const; const std::string& getMessage() const;
const util::Timestamp& getCreatedAt() const; const util::Timestamp& getCreatedAt() const;
void setId(const std::string& id); void setId(const std::string& id);
void setRecipientUserId(const std::string& recipientUserId); void setRecipientUserId(const std::string& recipientUserId);
void setRecipient(User* recipient);
void setTitle(const std::string& title); void setTitle(const std::string& title);
void setMessage(const std::string& message); void setMessage(const std::string& message);
void setCreatedAt(const util::Timestamp& createdAt); void setCreatedAt(const util::Timestamp& createdAt);
util::State getState() const; util::State getState();
void setState(util::State state); void setState(util::State state);
SerializedNotification serialize() const; SerializedNotification serialize() const;
static Notification* deserialize(const SerializedNotification&); static Notification* deserialize(const SerializedNotification&);
@@ -8,6 +8,7 @@ Date: 19-May-2026
*/ */
#include <sstream> #include <sstream>
#include "SerializedRecords.h"
#include "Service.h" #include "Service.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "StringHelper.h" #include "StringHelper.h"
@@ -266,72 +267,38 @@ static util::Vector<std::string> getInventoryItemIDsAsVector(const std::string&
/* /*
Function: serialize Function: serialize
Description: Serializes the service into a CSV-formatted string. Description: Serializes the Service object into a SerializedService record.
Parameters: Parameters:
- None - None
Returns: Returns:
- std::string: Serialized service record - SerializedService: Serialized representation of the service
*/ */
std::string Service::serialize() const SerializedService Service::serialize() const
{ {
std::ostringstream serializedService; SerializedService serialized = {};
serializedService << m_id << ',' strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str());
<< m_name << ',' strcpy_s(serialized.name, sizeof(serialized.name), m_name.c_str());
<< getInventoryItemIDsAsString(m_requiredInventoryItemIDs) << ',' strcpy_s(serialized.inventoryItemIDs, sizeof(serialized.inventoryItemIDs), getInventoryItemIDsAsString(m_requiredInventoryItemIDs).c_str());
<< m_laborCost << ',' serialized.laborCost = m_laborCost;
<< util::getStateString(m_status); serialized.status = m_status;
return serializedService.str(); return serialized;
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a CSV-formatted string into a Service object. Description: Deserializes a SerializedService record into a Service object.
Parameters: Parameters:
- record: const std::string&, serialized service record - serializedService: const SerializedService&, serialized service record
Returns: Returns:
- Service*: Pointer to the deserialized Service object - Service*: Pointer to the deserialized Service object
Throws:
- std::runtime_error if labor cost parsing fails
*/ */
Service* Service::deserialize(const std::string& record) Service* Service::deserialize(const SerializedService& serializedService)
{ {
std::string id, name; util::Vector<std::string> inventoryItemIDs = getInventoryItemIDsAsVector(serializedService.inventoryItemIDs);
std::string inventoryItemIDsString, laborCostString, statusString;
double laborCost;
std::istringstream serializedService(record);
getline(serializedService, id, ',');
getline(serializedService, name, ',');
getline(serializedService, inventoryItemIDsString, ',');
getline(serializedService, laborCostString, ',');
getline(serializedService, statusString, ',');
util::Vector<std::string> inventoryItemIDs = getInventoryItemIDsAsVector(inventoryItemIDsString);
try
{
laborCost = std::stod(laborCostString);
}
catch (...)
{
throw std::runtime_error("Invalid labor cost");
}
util::State status = util::getState(statusString);
return Factory::getObject<Service>( return Factory::getObject<Service>(
id, serializedService.id,
name, serializedService.name,
inventoryItemIDs, inventoryItemIDs,
laborCost, serializedService.laborCost,
status serializedService.status);
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for service serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,Name,InventoryIDs,LaborCost,Status")
*/
std::string Service::getHeaders()
{
return "ID,Name,InventoryIDs,LaborCost,Status";
} }
@@ -6,7 +6,6 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
@@ -14,6 +13,7 @@ Date: 19-May-2026
#include "Enums.h" #include "Enums.h"
class InventoryItem; class InventoryItem;
struct SerializedService;
class Service class Service
{ {
@@ -40,7 +40,6 @@ public:
void setRequiredInventoryItems(const util::Map<std::string, InventoryItem*>& requiredInventoryItems); void setRequiredInventoryItems(const util::Map<std::string, InventoryItem*>& requiredInventoryItems);
void setLaborCost(double laborCost); void setLaborCost(double laborCost);
void setState(util::State status); void setState(util::State status);
std::string serialize() const; SerializedService serialize() const;
static Service* deserialize(const std::string&); static Service* deserialize(const SerializedService&);
static std::string getHeaders();
}; };
@@ -6,8 +6,10 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
#include "SerializedRecords.h"
#include "ServiceBooking.h" #include "ServiceBooking.h"
#include "Service.h" #include "Service.h"
#include "Enums.h" #include "Enums.h"
@@ -437,84 +439,46 @@ static util::Vector<std::string> getServiceIDsAsVector(const std::string& servic
/* /*
Function: serialize Function: serialize
Description: Serializes the service booking into a CSV-formatted string. Description: Serializes the ServiceBooking object into a SerializedServiceBooking record.
Parameters: Parameters:
- None - None
Returns: Returns:
- std::string: Serialized booking record - SerializedServiceBooking: Serialized representation of the service booking
*/ */
std::string ServiceBooking::serialize() const SerializedServiceBooking ServiceBooking::serialize() const
{ {
std::ostringstream serializedBooking; SerializedServiceBooking serialized = {};
serializedBooking << m_id << ',' strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str());
<< util::getServiceJobStatusString(m_status) << ',' strcpy_s(serialized.serviceIDs, sizeof(serialized.serviceIDs), getServiceIDsAsString(m_serviceIDs).c_str());
<< getServiceIDsAsString(m_serviceIDs) << ',' strcpy_s(serialized.customerId, sizeof(serialized.customerId), m_customerId.c_str());
<< m_customerId << ',' strcpy_s(serialized.vehicleNumber, sizeof(serialized.vehicleNumber), m_vehicleNumber.c_str());
<< m_vehicleNumber << ',' strcpy_s(serialized.vehicleBrand, sizeof(serialized.vehicleBrand), m_vehicleBrand.c_str());
<< m_vehicleBrand << ',' strcpy_s(serialized.vehicleModel, sizeof(serialized.vehicleModel), m_vehicleModel.c_str());
<< m_vehicleModel << ',' strcpy_s(serialized.assignedTechnicianId, sizeof(serialized.assignedTechnicianId), m_assignedTechnicianId.c_str());
<< m_assignedTechnicianId << ',' serialized.status = m_status;
<< m_discountPercentage << ','; serialized.discountPercentage = m_discountPercentage;
return serializedBooking.str(); return serialized;
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a CSV-formatted string into a ServiceBooking object. Description: Deserializes a SerializedServiceBooking record into a ServiceBooking object.
Parameters: Parameters:
- record: const std::string&, serialized booking record - serializedServiceBooking: const SerializedServiceBooking&, serialized service booking record
Returns: Returns:
- ServiceBooking*: Pointer to the deserialized ServiceBooking object - ServiceBooking*: Pointer to the deserialized ServiceBooking object
Throws:
- std::runtime_error if discount percentage parsing fails
*/ */
ServiceBooking* ServiceBooking::deserialize(const std::string& record) ServiceBooking* ServiceBooking::deserialize(const SerializedServiceBooking& serializedServiceBooking)
{ {
std::string id, customerId, vehicleNumber, vehicleBrand, vehicleModel, assignedTechnicianId; util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serializedServiceBooking.serviceIDs);
std::string serviceJobStatusString, serviceIDsString, discountPercentageString;
double discountPercentage;
std::istringstream serializedBooking(record);
getline(serializedBooking, id, ',');
getline(serializedBooking, serviceJobStatusString, ',');
getline(serializedBooking, serviceIDsString, ',');
getline(serializedBooking, customerId, ',');
getline(serializedBooking, vehicleNumber, ',');
getline(serializedBooking, vehicleBrand, ',');
getline(serializedBooking, vehicleModel, ',');
getline(serializedBooking, assignedTechnicianId, ',');
getline(serializedBooking, discountPercentageString, ',');
util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serviceIDsString);
try
{
discountPercentage = std::stod(discountPercentageString);
}
catch (...)
{
throw std::runtime_error("Invalid discount percentage");
}
util::ServiceJobStatus status = util::getServiceJobStatus(serviceJobStatusString);
return Factory::getObject<ServiceBooking>( return Factory::getObject<ServiceBooking>(
id, serializedServiceBooking.id,
status, serializedServiceBooking.status,
serviceIDs, serviceIDs,
customerId, serializedServiceBooking.customerId,
vehicleNumber, serializedServiceBooking.vehicleNumber,
vehicleBrand, serializedServiceBooking.vehicleBrand,
vehicleModel, serializedServiceBooking.vehicleModel,
assignedTechnicianId, serializedServiceBooking.assignedTechnicianId,
discountPercentage serializedServiceBooking.discountPercentage);
);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for service booking serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,Status,ServiceIDs,CustomerID,VehicleNumber,VehicleBrand,VehicleModel,AssignedTechnicianID,DiscountPercentage")
*/
std::string ServiceBooking::getHeaders()
{
return "ID,Status,ServiceIDs,CustomerID,VehicleNumber,VehicleBrand,VehicleModel,AssignedTechnicianID,DiscountPercentage";
} }
@@ -6,6 +6,7 @@ Description: Header file declaring the ServiceBooking class, which represents
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
@@ -14,6 +15,7 @@ Date:19-May-2026
class Service; class Service;
class User; class User;
struct SerializedServiceBooking;
class ServiceBooking class ServiceBooking
{ {
@@ -78,7 +80,6 @@ public:
void setAssignedTechnicianId(const std::string& assignedTechnicianId); void setAssignedTechnicianId(const std::string& assignedTechnicianId);
void setAssignedTechnician(User* assignedTechnician); void setAssignedTechnician(User* assignedTechnician);
void setDiscountPercentage(double discountPercentage); void setDiscountPercentage(double discountPercentage);
std::string serialize() const; SerializedServiceBooking serialize() const;
static ServiceBooking* deserialize(const std::string&); static ServiceBooking* deserialize(const SerializedServiceBooking&);
static std::string getHeaders();
}; };
@@ -29,8 +29,7 @@ Returns:
User::User() User::User()
: m_id("USR" + std::to_string(++m_uid)), : m_id("USR" + std::to_string(++m_uid)),
m_type(util::UserType::CUSTOMER), m_type(util::UserType::CUSTOMER),
m_status(util::State::ACTIVE) { m_status(util::State::ACTIVE) {}
}
/* /*
Function: User Function: User
@@ -53,8 +52,7 @@ User::User(const std::string& userName, const std::string& password, const std::
m_phone(phone), m_phone(phone),
m_email(email), m_email(email),
m_type(role), m_type(role),
m_status(util::State::ACTIVE) { m_status(util::State::ACTIVE) {}
}
/* /*
Function: User (parameterized constructor with ID) Function: User (parameterized constructor with ID)
@@ -89,6 +87,23 @@ User::User(const std::string& userId, const std::string& userName, const std::st
} }
} }
/*
Function: ~User
Description: Destructor that cleans up dynamically allocated notifications associated with the user.
Parameters:
- None
Returns:
- void
*/
User::~User()
{
auto values = m_notifications.getValues();
for (int index = 0; index < values.getSize(); index++)
{
delete values[index];
}
}
/* /*
Function: getId Function: getId
Description: Retrieves the unique ID of the user. Description: Retrieves the unique ID of the user.
@@ -155,6 +170,17 @@ const std::string& User::getEmail() const
return m_email; return m_email;
} }
/*
Function: getNotifications
Description: Retrieves the map of notifications associated with the user.
Returns:
- util::Map<std::string, Notification*>& representing the notifications.
*/
util::Map<std::string, Notification*>& User::getNotifications()
{
return m_notifications;
}
/* /*
Function: getUserType Function: getUserType
Description: Retrieves the role of the user. Description: Retrieves the role of the user.
@@ -255,6 +281,22 @@ void User::setEmail(const std::string& email)
m_email = email; m_email = email;
} }
/*
Function: addNotification
Description: Adds a new notification to the users notification map.
Parameters:
- notification: Pointer to the Notification object.
Returns:
- void
*/
void User::addNotification(Notification* notification)
{
if (notification)
{
m_notifications.insert(notification->getId(), notification);
}
}
/* /*
Function: setRole Function: setRole
Description: Sets the role of the user. Description: Sets the role of the user.
@@ -26,19 +26,21 @@ private:
std::string m_name; std::string m_name;
std::string m_phone; std::string m_phone;
std::string m_email; std::string m_email;
util::Map<std::string, Notification*> m_notifications;
util::UserType m_type; util::UserType m_type;
util::State m_status; util::State m_status;
public: public:
User(); User();
User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role); User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role);
User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status); User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status);
~User() = default; ~User();
const std::string& getId() const; const std::string& getId() const;
const std::string& getUserName() const; const std::string& getUserName() const;
const std::string& getPassword() const; const std::string& getPassword() const;
const std::string& getName() const; const std::string& getName() const;
const std::string& getPhone() const; const std::string& getPhone() const;
const std::string& getEmail() const; const std::string& getEmail() const;
util::Map<std::string, Notification*>& getNotifications();
util::UserType getUserType() const; util::UserType getUserType() const;
util::State getState() const; util::State getState() const;
void setId(const std::string& id); void setId(const std::string& id);
@@ -47,6 +49,7 @@ public:
void setName(const std::string& name); void setName(const std::string& name);
void setPhone(const std::string& phone); void setPhone(const std::string& phone);
void setEmail(const std::string& email); void setEmail(const std::string& email);
void addNotification(Notification* notification) override;
void setRole(util::UserType role); void setRole(util::UserType role);
void setState(util::State status); void setState(util::State status);
SerializedUser serialize() const; SerializedUser serialize() const;
@@ -10,8 +10,6 @@ Date:19-May-2026
#include <stdexcept> #include <stdexcept>
#include "AuthenticationManagementService.h" #include "AuthenticationManagementService.h"
#include "User.h" #include "User.h"
#include "Utility.h"
#include "DataStoreLockGuard.h"
User* AuthenticationManagementService::m_authenticatedUser = nullptr; User* AuthenticationManagementService::m_authenticatedUser = nullptr;
@@ -26,12 +24,11 @@ Return type: bool - true if login successful, false otherwise
*/ */
bool AuthenticationManagementService::login(const std::string& username, const std::string& password) bool AuthenticationManagementService::login(const std::string& username, const std::string& password)
{ {
DataStoreLockGuard lock(m_dataStore); util::Map<std::string, User*> users = m_dataStore.getUsers();
auto& trackedUserMap = m_dataStore.getUsers(); int usersMapSize = users.getSize();
int trackedUserMapSize = trackedUserMap.getSize(); for (int index = 0; index < usersMapSize; index++)
for (int index = 0; index < trackedUserMapSize; index++)
{ {
User* user = trackedUserMap.getValueAt(index).data; User* user = users.getValueAt(index);
if (username == user->getUserName()) if (username == user->getUserName())
{ {
if (password == user->getPassword()) if (password == user->getPassword())
@@ -77,18 +74,9 @@ Return type: void
*/ */
void AuthenticationManagementService::changePassword(const std::string& newPassword) void AuthenticationManagementService::changePassword(const std::string& newPassword)
{ {
DataStoreLockGuard lock(m_dataStore);
auto& trackedUsersMap = m_dataStore.getUsers();
if (m_authenticatedUser == nullptr) if (m_authenticatedUser == nullptr)
{ {
throw std::runtime_error("There is no user currently logged in!"); throw std::runtime_error("There is no user currently logged in!");
} }
int index = trackedUsersMap.find(m_authenticatedUser->getId());
if (index == -1)
{
throw std::runtime_error("User does not exist!\n");
}
m_authenticatedUser->setPassword(newPassword); m_authenticatedUser->setPassword(newPassword);
trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED;
m_dataStore.saveUsers();
} }
@@ -12,13 +12,14 @@ Date: 22-May-2026
#include "Config.h" #include "Config.h"
#include "Enums.h" #include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "InventoryManagementService.h" #include "InventoryManagementService.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "User.h" #include "User.h"
#include "Utility.h" #include "Utility.h"
#include "Vector.h" #include "Vector.h"
#include "DataStoreLockGuard.h"
util::Map<std::string, User*> InventoryManagementService::m_observers{}; util::Map<std::string, User*> InventoryManagementService::m_observers{};
@@ -89,6 +90,95 @@ void InventoryManagementService::sendLowStockAlerts()
} }
} }
/*
Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the
InventoryManagementService.
Parameters:
- None
Returns:
- util::Vector<std::string>: Vector of observer user IDs
*/
util::Vector<std::string> InventoryManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
/*
Function: loadInventoryItems
Description: Loads inventory items from persistent storage into the datastore.
Uses FileManager to deserialize inventory items from the configured file.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::loadInventoryItems()
{
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
auto& inventoryItems = m_dataStore.getInventoryItems();
auto inventoryItemsMap = inventoryItemFileManager.load();
int numberOfInventoryItems = inventoryItemsMap.getSize();
for (int index = 0; index < numberOfInventoryItems; index++)
{
inventoryItems[inventoryItemsMap.getKeyAt(index)] = inventoryItemsMap.getValueAt(index);
}
}
/*
Function: saveInventoryItems
Description: Saves inventory items from the datastore to persistent storage.
Uses FileManager to serialize inventory items into the configured file.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::saveInventoryItems()
{
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
auto& inventoryItems = m_dataStore.getInventoryItems();
inventoryItemFileManager.save(inventoryItems);
}
/*
Function: loadObservers
Description: Loads observer IDs from persistent storage and attaches corresponding
users as observers to the InventoryManagementService.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::loadObservers()
{
util::loadObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this, m_dataStore);
}
/*
Function: saveObservers
Description: Saves the current observer IDs of the InventoryManagementService
to persistent storage for future retrieval.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::saveObservers()
{
util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this);
}
/* /*
Function: addInventoryItem Function: addInventoryItem
Description: Creates a new inventory item using the Factory and inserts it Description: Creates a new inventory item using the Factory and inserts it
@@ -181,9 +271,6 @@ Returns:
*/ */
void InventoryManagementService::attach(User* user) void InventoryManagementService::attach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getInventoryManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -192,7 +279,6 @@ void InventoryManagementService::attach(User* user)
m_observers[userID] = user; m_observers[userID] = user;
} }
} }
m_dataStore.saveInventoryManagementObservers(m_observers);
} }
/* /*
@@ -205,9 +291,6 @@ Returns:
*/ */
void InventoryManagementService::detach(User* user) void InventoryManagementService::detach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getInventoryManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -216,7 +299,6 @@ void InventoryManagementService::detach(User* user)
m_observers.remove(userID); m_observers.remove(userID);
} }
} }
m_dataStore.saveInventoryManagementObservers(m_observers);
} }
/* /*
@@ -233,27 +315,27 @@ Throws:
*/ */
void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message) void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{ {
if (!user) if (user)
{ {
return; if (m_observers.find(user->getId()) != -1)
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
} }
DataStoreLockGuard lock(m_dataStore);
m_observers = m_dataStore.getInventoryManagementObservers();
if (m_observers.find(user->getId()) == -1)
{
return;
}
Notification* notification = Factory::getObject<Notification>(
user->getId(),
title,
message,
util::Timestamp());
if (!notification)
{
throw std::runtime_error("Failed to create notification");
}
auto& trackedNotificationsMap = m_dataStore.getNotifications();
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
m_dataStore.saveNotifications();
} }
@@ -21,6 +21,7 @@ class InventoryManagementService : public NotificationManagementService
private: private:
DataStore& m_dataStore; DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers; static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public: public:
InventoryManagementService() : m_dataStore(DataStore::getInstance()) {} InventoryManagementService() : m_dataStore(DataStore::getInstance()) {}
util::Map<std::string, InventoryItem*> getInventoryItems(); util::Map<std::string, InventoryItem*> getInventoryItems();
@@ -32,4 +33,8 @@ public:
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
void detach(User* user) override; void detach(User* user) override;
void loadInventoryItems();
void saveInventoryItems();
void loadObservers();
void saveObservers();
}; };
@@ -0,0 +1 @@
#include "NotificationManagementService.h"
@@ -19,4 +19,5 @@ public:
virtual void sendNotification(User* recipient, const std::string& title, const std::string& message) = 0; virtual void sendNotification(User* recipient, const std::string& title, const std::string& message) = 0;
virtual void attach(User* user) = 0; virtual void attach(User* user) = 0;
virtual void detach(User* user) = 0; virtual void detach(User* user) = 0;
virtual util::Vector<std::string> getObserverIDs() = 0;
}; };
@@ -11,6 +11,7 @@ Date: 20-May-2026
#include "Config.h" #include "Config.h"
#include "Enums.h" #include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "Invoice.h" #include "Invoice.h"
#include "JobCard.h" #include "JobCard.h"
@@ -20,7 +21,6 @@ Date: 20-May-2026
#include "Timestamp.h" #include "Timestamp.h"
#include "User.h" #include "User.h"
#include "Utility.h" #include "Utility.h"
#include "DataStoreLockGuard.h"
util::Map<std::string, User*> PaymentManagementService::m_observers{}; util::Map<std::string, User*> PaymentManagementService::m_observers{};
@@ -34,9 +34,6 @@ Returns:
*/ */
void PaymentManagementService::attach(User* user) void PaymentManagementService::attach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getPaymentManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -45,7 +42,6 @@ void PaymentManagementService::attach(User* user)
m_observers[userID] = user; m_observers[userID] = user;
} }
} }
m_dataStore.savePaymentManagementObservers(m_observers);
} }
/* /*
@@ -58,9 +54,6 @@ Returns:
*/ */
void PaymentManagementService::detach(User* user) void PaymentManagementService::detach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getPaymentManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -69,7 +62,6 @@ void PaymentManagementService::detach(User* user)
m_observers.remove(userID); m_observers.remove(userID);
} }
} }
m_dataStore.savePaymentManagementObservers(m_observers);
} }
/* /*
@@ -86,28 +78,28 @@ Throws:
*/ */
void PaymentManagementService::sendNotification(User* user, const std::string& title, const std::string& message) void PaymentManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{ {
if (!user) if (user)
{ {
return; if (m_observers.find(user->getId()) != -1)
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
} }
DataStoreLockGuard lock(m_dataStore);
m_observers = m_dataStore.getPaymentManagementObservers();
if (m_observers.find(user->getId()) == -1)
{
return;
}
Notification* notification = Factory::getObject<Notification>(
user->getId(),
title,
message,
util::Timestamp());
if (!notification)
{
throw std::runtime_error("Failed to create notification");
}
auto& trackedNotificationsMap = m_dataStore.getNotifications();
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
m_dataStore.saveNotifications();
} }
/* /*
@@ -148,6 +140,123 @@ void PaymentManagementService::sendPaymentReminders()
} }
} }
/*
Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the
PaymentManagementService.
Parameters:
- None
Returns:
- util::Vector<std::string>: Vector of observer user IDs
*/
util::Vector<std::string> PaymentManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
/*
Function: loadInvoices
Description: Loads invoices from persistent storage into the datastore.
Validates associated service bookings and inventory parts before
attaching them to each invoice. Throws exceptions if invalid IDs
are encountered.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a booking ID or part ID is invalid
*/
void PaymentManagementService::loadInvoices()
{
util::FileManager<Invoice> invoiceFileManager(config::file::INVOICE_FILE);
auto& invoices = m_dataStore.getInvoices();
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& inventoryItems = m_dataStore.getInventoryItems();
auto invoicesMap = invoiceFileManager.load();
for (int invoiceIndex = 0; invoiceIndex < invoicesMap.getSize(); invoiceIndex++)
{
Invoice* invoice = invoicesMap.getValueAt(invoiceIndex);
int bookingIndex = serviceBookings.find(invoice->getBookingId());
if (bookingIndex == -1)
{
throw std::runtime_error("Invalid Booking ID");
}
ServiceBooking* booking = serviceBookings.getValueAt(bookingIndex);
invoice->setBooking(booking);
util::Map<std::string, InventoryItem*> invoiceParts;
auto& partIDs = invoice->getPartIDs();
for (int partIndex = 0; partIndex < partIDs.getSize(); partIndex++)
{
const std::string& partID = partIDs[partIndex];
int inventoryIndex = inventoryItems.find(partID);
if (inventoryIndex == -1)
{
throw std::runtime_error("Invalid Part ID");
}
invoiceParts[partID] = inventoryItems.getValueAt(inventoryIndex);
}
invoice->setParts(invoiceParts);
invoices[invoice->getId()] = invoice;
}
}
/*
Function: saveInvoices
Description: Saves invoices from the datastore to persistent storage.
Uses FileManager to serialize invoices into the configured file.
Parameters:
- None
Returns:
- void
*/
void PaymentManagementService::saveInvoices()
{
util::FileManager<Invoice> invoiceFileManager(config::file::INVOICE_FILE);
auto& invoices = m_dataStore.getInvoices();
invoiceFileManager.save(invoices);
}
/*
Function: loadObservers
Description: Loads observer IDs from persistent storage and attaches corresponding
users as observers to the PaymentManagementService.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if an observer ID is invalid (not found in datastore)
*/
void PaymentManagementService::loadObservers()
{
util::loadObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this, m_dataStore);
}
/*
Function: saveObservers
Description: Saves the current observer IDs of the PaymentManagementService
to persistent storage for future retrieval.
Parameters:
- None
Returns:
- void
*/
void PaymentManagementService::saveObservers()
{
util::saveObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this);
}
/* /*
Function: createInventoryItemsMap (static helper) Function: createInventoryItemsMap (static helper)
Description: Builds a map of inventory items required for a given service and adds them to the bookings inventory map. Description: Builds a map of inventory items required for a given service and adds them to the bookings inventory map.
@@ -22,6 +22,7 @@ class PaymentManagementService : public NotificationManagementService
private: private:
DataStore& m_dataStore; DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers; static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public: public:
PaymentManagementService() : m_dataStore(DataStore::getInstance()) {} PaymentManagementService() : m_dataStore(DataStore::getInstance()) {}
void generateInvoice(ServiceBooking* booking); void generateInvoice(ServiceBooking* booking);
@@ -33,4 +34,8 @@ public:
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
void detach(User* user) override; void detach(User* user) override;
void loadInvoices();
void saveInvoices();
void loadObservers();
void saveObservers();
}; };
@@ -14,6 +14,7 @@ Date:19-May-2026
#include "DataStore.h" #include "DataStore.h"
#include "Enums.h" #include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "JobCard.h" #include "JobCard.h"
#include "NotificationManagementService.h" #include "NotificationManagementService.h"
@@ -25,7 +26,6 @@ Date:19-May-2026
#include "User.h" #include "User.h"
#include "UserManagementService.h" #include "UserManagementService.h"
#include "Utility.h" #include "Utility.h"
#include "DataStoreLockGuard.h"
/* /*
Function: purchaseService Function: purchaseService
@@ -122,9 +122,6 @@ Returns:
*/ */
void ServiceManagementService::attach(User* user) void ServiceManagementService::attach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getServiceManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -133,7 +130,6 @@ void ServiceManagementService::attach(User* user)
m_observers[userID] = user; m_observers[userID] = user;
} }
} }
m_dataStore.saveServiceManagementObservers(m_observers);
} }
/* /*
@@ -146,9 +142,6 @@ Returns:
*/ */
void ServiceManagementService::detach(User* user) void ServiceManagementService::detach(User* user)
{ {
DataStoreLockGuard lock(m_dataStore);
m_observers.clear();
m_observers = m_dataStore.getServiceManagementObservers();
if (user) if (user)
{ {
const std::string& userID = user->getId(); const std::string& userID = user->getId();
@@ -157,7 +150,6 @@ void ServiceManagementService::detach(User* user)
m_observers.remove(userID); m_observers.remove(userID);
} }
} }
m_dataStore.saveServiceManagementObservers(m_observers);
} }
/* /*
@@ -174,28 +166,345 @@ Throws:
*/ */
void ServiceManagementService::sendNotification(User* user, const std::string& title, const std::string& message) void ServiceManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{ {
if (!user) if (user)
{
if (m_observers.find(user->getId()) != -1)
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
}
}
/*
Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the
ServiceManagementService.
Parameters:
- None
Returns:
- util::Vector<std::string>: Vector of observer user IDs
*/
util::Vector<std::string> ServiceManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
/*
Function: loadServices
Description: Loads services from persistent storage into the datastore.
Validates required inventory items and attaches them to each service.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if an inventory item ID is invalid
*/
void ServiceManagementService::loadServices()
{
util::FileManager<Service> serviceFileManager(config::file::SERVICE_FILE);
auto& services = m_dataStore.getServices();
auto& inventoryItems = m_dataStore.getInventoryItems();
auto servicesMap = serviceFileManager.load();
for (int serviceIndex = 0; serviceIndex < servicesMap.getSize(); serviceIndex++)
{ {
return; Service* service = servicesMap.getValueAt(serviceIndex);
services[service->getId()] = service;
util::Map<std::string, InventoryItem*> inventoryItemsMap;
auto& inventoryItemIDs = service->getRequiredInventoryItemIDs();
for (int inventoryItemIndex = 0; inventoryItemIndex < inventoryItemIDs.getSize(); inventoryItemIndex++)
{
const std::string& inventoryItemID = inventoryItemIDs[inventoryItemIndex];
int index = inventoryItems.find(inventoryItemID);
if (index == -1)
{
throw std::runtime_error("Invalid Inventory Item ID");
}
inventoryItemsMap[inventoryItemID] = inventoryItems.getValueAt(index);
}
service->setRequiredInventoryItems(inventoryItemsMap);
} }
DataStoreLockGuard lock(m_dataStore); }
m_observers = m_dataStore.getServiceManagementObservers();
if (m_observers.find(user->getId()) == -1) /*
Function: saveServices
Description: Saves services from the datastore to persistent storage.
Uses FileManager to serialize services into the configured file.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveServices()
{
util::FileManager<Service> serviceFileManager(config::file::SERVICE_FILE);
auto& services = m_dataStore.getServices();
serviceFileManager.save(services);
}
/*
Function: loadComboPackages
Description: Loads combo packages from persistent storage into the datastore.
Validates associated services and attaches them to each package.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a service ID is invalid
*/
void ServiceManagementService::loadComboPackages()
{
util::FileManager<ComboPackage> comboPackageFileManager(config::file::COMBOPACKAGE_FILE);
auto& comboPackages = m_dataStore.getComboPackages();
auto& services = m_dataStore.getServices();
auto comboPackagesMap = comboPackageFileManager.load();
for (int packageIndex = 0; packageIndex < comboPackagesMap.getSize(); packageIndex++)
{ {
return; ComboPackage* comboPackage = comboPackagesMap.getValueAt(packageIndex);
util::Map<std::string, Service*> packageServices;
auto& serviceIDs = comboPackage->getServiceIDs();
for (int serviceIndex = 0; serviceIndex < serviceIDs.getSize(); serviceIndex++)
{
const std::string& serviceID = serviceIDs[serviceIndex];
int serviceMapIndex = services.find(serviceID);
if (serviceMapIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
packageServices[serviceID] = services.getValueAt(serviceMapIndex);
}
comboPackage->setServices(packageServices);
comboPackages[comboPackage->getId()] = comboPackage;
} }
Notification* notification = Factory::getObject<Notification>( }
user->getId(),
title, /*
message, Function: saveComboPackages
util::Timestamp()); Description: Saves combo packages from the datastore to persistent storage.
if (!notification) Uses FileManager to serialize combo packages into the configured file.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveComboPackages()
{
util::FileManager<ComboPackage> comboPackageFileManager(config::file::COMBOPACKAGE_FILE);
auto& comboPackages = m_dataStore.getComboPackages();
comboPackageFileManager.save(comboPackages);
}
/*
Function: loadServiceBookings
Description: Loads service bookings from persistent storage into the datastore.
Validates associated services, customers, and technicians before
attaching them to each booking.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a service ID, customer ID, or technician ID is invalid
- std::runtime_error if a user is not of the expected type (customer/technician)
*/
void ServiceManagementService::loadServiceBookings()
{
util::FileManager<ServiceBooking> bookingFileManager(config::file::SERVICEBOOKING_FILE);
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& services = m_dataStore.getServices();
auto& users = m_dataStore.getUsers();
auto bookingsMap = bookingFileManager.load();
for (int bookingIndex = 0; bookingIndex < bookingsMap.getSize(); bookingIndex++)
{ {
throw std::runtime_error("Failed to create notification"); ServiceBooking* booking = bookingsMap.getValueAt(bookingIndex);
util::Map<std::string, Service*> bookingServices;
auto& serviceIDs = booking->getServiceIDs();
for (int serviceIndex = 0; serviceIndex < serviceIDs.getSize(); serviceIndex++)
{
const std::string& serviceID = serviceIDs[serviceIndex];
int serviceMapIndex = services.find(serviceID);
if (serviceMapIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
bookingServices[serviceID] = services.getValueAt(serviceMapIndex);
}
booking->setServices(bookingServices);
int customerIndex = users.find(booking->getCustomerId());
if (customerIndex == -1)
{
throw std::runtime_error("Invalid Customer ID");
}
User* customer = users.getValueAt(customerIndex);
if (customer->getUserType() != util::UserType::CUSTOMER)
{
throw std::runtime_error("User is not a customer");
}
booking->setCustomer(customer);
const std::string& technicianId = booking->getAssignedTechnicianId();
if (!technicianId.empty())
{
int technicianIndex = users.find(technicianId);
if (technicianIndex == -1)
{
throw std::runtime_error("Invalid Technician ID");
}
User* technician = users.getValueAt(technicianIndex);
if (technician->getUserType() != util::UserType::TECHNICIAN)
{
throw std::runtime_error("User is not a technician");
}
booking->setAssignedTechnician(technician);
}
serviceBookings[booking->getId()] = booking;
} }
auto& trackedNotificationsMap = m_dataStore.getNotifications(); }
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
m_dataStore.saveNotifications(); /*
Function: saveServiceBookings
Description: Saves service bookings from the datastore to persistent storage.
Uses FileManager to serialize bookings into the configured file.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveServiceBookings()
{
util::FileManager<ServiceBooking> bookingFileManager(config::file::SERVICEBOOKING_FILE);
auto& serviceBookings = m_dataStore.getServiceBookings();
bookingFileManager.save(serviceBookings);
}
/*
Function: loadJobCards
Description: Loads job cards from persistent storage into the datastore.
Validates associated bookings, services, and technicians before
attaching them to each job card.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a booking ID, service ID, or technician ID is invalid
- std::runtime_error if a service does not belong to the booking
- std::runtime_error if a user is not a technician
*/
void ServiceManagementService::loadJobCards()
{
util::FileManager<JobCard> jobCardFileManager(config::file::JOBCARD_FILE);
auto& jobCards = m_dataStore.getJobCards();
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& services = m_dataStore.getServices();
auto& users = m_dataStore.getUsers();
auto jobCardsMap = jobCardFileManager.load();
for (int jobCardIndex = 0; jobCardIndex < jobCardsMap.getSize(); jobCardIndex++)
{
JobCard* jobCard = jobCardsMap.getValueAt(jobCardIndex);
int bookingIndex = serviceBookings.find(jobCard->getBookingId());
if (bookingIndex == -1)
{
throw std::runtime_error("Invalid Booking ID");
}
ServiceBooking* booking = serviceBookings.getValueAt(bookingIndex);
jobCard->setBooking(booking);
int serviceIndex = services.find(jobCard->getServiceId());
if (serviceIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
Service* service = services.getValueAt(serviceIndex);
if (booking->getServices().find(jobCard->getServiceId()) == -1)
{
throw std::runtime_error("Service does not belong to booking");
}
jobCard->setService(service);
int technicianIndex = users.find(jobCard->getTechnicianId());
if (technicianIndex == -1)
{
throw std::runtime_error("Invalid Technician ID");
}
User* technician = users.getValueAt(technicianIndex);
if (technician->getUserType() != util::UserType::TECHNICIAN)
{
throw std::runtime_error("User is not a technician");
}
jobCard->setTechnician(technician);
jobCards[jobCard->getId()] = jobCard;
}
}
/*
Function: saveJobCards
Description: Saves job cards from the datastore to persistent storage.
Uses FileManager to serialize job cards into the configured file.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveJobCards()
{
util::FileManager<JobCard> jobCardFileManager(config::file::JOBCARD_FILE);
auto& jobCards = m_dataStore.getJobCards();
jobCardFileManager.save(jobCards);
}
/*
Function: loadObservers
Description: Loads observer IDs from persistent storage and attaches corresponding
users as observers to the ServiceManagementService.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if an observer ID is invalid (not found in datastore)
*/
void ServiceManagementService::loadObservers()
{
util::loadObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this, m_dataStore);
}
/*
Function: saveObservers
Description: Saves the current observer IDs of the ServiceManagementService
to persistent storage for future retrieval.
Parameters:
- None
Returns:
- void
*/
void ServiceManagementService::saveObservers()
{
util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this);
} }
/* /*
@@ -23,6 +23,7 @@ class ServiceManagementService : public NotificationManagementService
private: private:
DataStore& m_dataStore; DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers; static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public: public:
ServiceManagementService() : m_dataStore(DataStore::getInstance()) {} ServiceManagementService() : m_dataStore(DataStore::getInstance()) {}
util::Map<std::string, Service*> getServices(); util::Map<std::string, Service*> getServices();
@@ -44,4 +45,14 @@ public:
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
void detach(User* user) override; void detach(User* user) override;
void loadServices();
void saveServices();
void loadComboPackages();
void saveComboPackages();
void loadServiceBookings();
void saveServiceBookings();
void loadJobCards();
void saveJobCards();
void loadObservers();
void saveObservers();
}; };
@@ -11,6 +11,7 @@ Date:19-May-2026
#include "Config.h" #include "Config.h"
#include "Enums.h" #include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h"
#include "InventoryManagementService.h" #include "InventoryManagementService.h"
#include "Notification.h" #include "Notification.h"
#include "PaymentManagementService.h" #include "PaymentManagementService.h"
@@ -19,9 +20,6 @@ Date:19-May-2026
#include "UserManagementService.h" #include "UserManagementService.h"
#include "Vector.h" #include "Vector.h"
#include "Validator.h" #include "Validator.h"
#include "Utility.h"
#include "TrackedRecord.h"
#include "DataStoreLockGuard.h"
/* /*
Function: ensureAdminExists Function: ensureAdminExists
@@ -33,13 +31,12 @@ Return type: void
*/ */
void UserManagementService::ensureAdminExists() void UserManagementService::ensureAdminExists()
{ {
DataStoreLockGuard lock(m_dataStore);
auto& usersMap = m_dataStore.getUsers(); auto& usersMap = m_dataStore.getUsers();
int usersMapSize = usersMap.getSize(); int usersMapSize = usersMap.getSize();
bool isAdminFound = false; bool isAdminFound = false;
for (int index = 0; index < usersMapSize; index++) for (int index = 0; index < usersMapSize; index++)
{ {
User* user = usersMap.getValueAt(index).data; User* user = usersMap.getValueAt(index);
if (user && user->getUserType() == util::UserType::ADMIN) if (user && user->getUserType() == util::UserType::ADMIN)
{ {
isAdminFound = true; isAdminFound = true;
@@ -76,9 +73,7 @@ void UserManagementService::createUser(const std::string& username, const std::s
InventoryManagementService inventoryManagementService; InventoryManagementService inventoryManagementService;
PaymentManagementService paymentManagementService; PaymentManagementService paymentManagementService;
ServiceManagementService serviceManagementService; ServiceManagementService serviceManagementService;
DataStoreLockGuard lock(m_dataStore); auto& usersMap = m_dataStore.getUsers();
auto& trackedUsersMap = m_dataStore.getUsers();
auto usersMap = util::getObjects(trackedUsersMap);
if (util::isUsernameDuplicate(username, usersMap)) if (util::isUsernameDuplicate(username, usersMap))
{ {
throw std::runtime_error("Username already exists"); throw std::runtime_error("Username already exists");
@@ -92,14 +87,13 @@ void UserManagementService::createUser(const std::string& username, const std::s
throw std::runtime_error("Phone already exists"); throw std::runtime_error("Phone already exists");
} }
User* newUser = Factory::getObject<User>(username, password, name, phone, email, type); User* newUser = Factory::getObject<User>(username, password, name, phone, email, type);
trackedUsersMap.insert(newUser->getId(), util::createNewRecord(newUser)); usersMap.insert(newUser->getId(), newUser);
paymentManagementService.attach(newUser); paymentManagementService.attach(newUser);
serviceManagementService.attach(newUser); serviceManagementService.attach(newUser);
if (newUser->getUserType() == util::UserType::ADMIN) if (newUser->getUserType() == util::UserType::ADMIN)
{ {
inventoryManagementService.attach(newUser); inventoryManagementService.attach(newUser);
} }
m_dataStore.saveUsers();
} }
/* /*
@@ -113,24 +107,19 @@ Return type: void
*/ */
void UserManagementService::updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone) void UserManagementService::updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone)
{ {
DataStoreLockGuard lock(m_dataStore); auto& usersMap = m_dataStore.getUsers();
auto& trackedUsersMap = m_dataStore.getUsers(); int index = usersMap.find(userID);
auto usersMap = util::getObjects(trackedUsersMap);
int index = trackedUsersMap.find(userID);
if (index == -1) if (index == -1)
{ {
throw std::runtime_error("User does not exist!\n"); throw std::runtime_error("User does not exist!\n");
} }
User* user = trackedUsersMap.getValueAt(index).data; User* user = usersMap.getValueAt(index);
bool isModified = false;
if (email != user->getEmail()) if (email != user->getEmail())
{ {
if (util::isEmailDuplicate(email, usersMap)) if (util::isEmailDuplicate(email, usersMap))
{ {
throw std::runtime_error("Email already exists!\n"); throw std::runtime_error("Email already exists!\n");
} }
user->setEmail(email);
isModified = true;
} }
if (phone != user->getPhone()) if (phone != user->getPhone())
{ {
@@ -138,14 +127,9 @@ void UserManagementService::updateUserDetails(const std::string& userID, const s
{ {
throw std::runtime_error("Phone number already exists!\n"); throw std::runtime_error("Phone number already exists!\n");
} }
user->setPhone(phone);
isModified = true;
}
if (isModified)
{
trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED;
m_dataStore.saveUsers();
} }
user->setEmail(email);
user->setPhone(phone);
} }
/* /*
@@ -160,25 +144,20 @@ Throws:
*/ */
util::Vector<Notification*> UserManagementService::getUserNotifications(const std::string& userID) util::Vector<Notification*> UserManagementService::getUserNotifications(const std::string& userID)
{ {
DataStoreLockGuard lock(m_dataStore); auto& usersMap = m_dataStore.getUsers();
auto& trackedUsersMap = m_dataStore.getUsers(); if (usersMap.find(userID) == -1)
if (trackedUsersMap.find(userID) == -1)
{ {
throw std::runtime_error("No user found with given UserID"); throw std::runtime_error("No user found with given UserID");
} }
User* user = trackedUsersMap[userID].data; User* user = usersMap[userID];
if (user) if (user)
{ {
auto& trackedNotificationMap = m_dataStore.getNotifications(); auto& notifications = user->getNotifications();
int numberOfNotifications = trackedNotificationMap.getSize(); int numberOfNotifications = notifications.getSize();
util::Vector<Notification*> notificationsVector; util::Vector<Notification*> notificationsVector;
for (int index = 0; index < numberOfNotifications; index++) for (int index = 0; index < numberOfNotifications; index++)
{ {
Notification* notification = trackedNotificationMap.getValueAt(index).data; notificationsVector.push_back(notifications.getValueAt(index));
if (notification->getRecipientUserId() == userID && notification->getState() == util::State::ACTIVE)
{
notificationsVector.push_back(notification);
}
} }
return notificationsVector; return notificationsVector;
} }
@@ -190,39 +169,97 @@ util::Vector<Notification*> UserManagementService::getUserNotifications(const st
/* /*
Function: deleteNotification Function: deleteNotification
Description: Marks a specific notification associated with a given user Description: Deletes a specific notification associated with a given user ID.
as inactive.
Parameters: Parameters:
- notificationID: The unique ID of the notification to be deleted. - notificationID: The unique ID of the notification to be deleted.
- userID: The unique ID of the user whose notification is to be deleted. - userID: The unique ID of the user whose notification is to be deleted.
Returns: Returns:
- void - void
Throws: Throws:
- std::runtime_error if no user is found with the given UserID or - std::runtime_error if no user is found with the given UserID or if no notification is found with the given NotificationID.
if no notification is found with the given NotificationID.
*/ */
void UserManagementService::deleteNotification(const std::string& notificationID, const std::string& userID) void UserManagementService::deleteNotification(const std::string& notificationID, const std::string& userID)
{ {
DataStoreLockGuard lock(m_dataStore); auto& usersMap = m_dataStore.getUsers();
auto& trackedUsersMap = m_dataStore.getUsers(); if (usersMap.find(userID) == -1)
auto& trackedNotificationsMap = m_dataStore.getNotifications();
int userIndex = trackedUsersMap.find(userID);
if (userIndex == -1)
{ {
throw std::runtime_error("No user found with given UserID"); throw std::runtime_error("No user found with given UserID");
} }
int notificationIndex = trackedNotificationsMap.find(notificationID); User* user = usersMap[userID];
if (notificationIndex == -1) auto& notifications = user->getNotifications();
if (notifications.find(notificationID) == -1)
{ {
throw std::runtime_error("No notification found with given NotificationID"); throw std::runtime_error("No notification found with given NotificationID");
} }
Notification* notification = trackedNotificationsMap.getValueAt(notificationIndex).data; notifications.remove(notificationID);
if (notification->getRecipientUserId() == userID) }
{
notification->setState(util::State::INACTIVE); /*
trackedNotificationsMap.getValueAt(notificationIndex).state = RecordState::MODIFIED; Function: loadUsers
m_dataStore.saveNotifications(); Description: Loads users and notifications from persistent storage into the datastore.
} Validates that each notifications recipient exists and attaches the
notification to the corresponding user.
Parameters:
- None
Returns:
- void
Throws:
- std::runtime_error if a notification recipient user ID is invalid
*/
void UserManagementService::loadUsers()
{
util::FileManager<User> userFileManager(config::file::USER_FILE);
util::FileManager<Notification> notificationFileManager(config::file::NOTIFICATION_FILE);
auto& users = m_dataStore.getUsers();
auto usersMap = userFileManager.load();
auto notificationsMap = notificationFileManager.load();
int numberOfUsers = usersMap.getSize();
int numberOfNotifications = notificationsMap.getSize();
for (int index = 0; index < numberOfUsers; index++)
{
users[usersMap.getKeyAt(index)] = usersMap.getValueAt(index);
}
for (int index = 0; index < numberOfNotifications; index++)
{
Notification* notification = notificationsMap.getValueAt(index);
const std::string& recipientUserId = notification->getRecipientUserId();
int userIndex = users.find(recipientUserId);
if (userIndex == -1)
{
throw std::runtime_error("Invalid recipient user ID");
}
User* user = users.getValueAt(userIndex);
user->addNotification(notification);
}
}
/*
Function: saveUsers
Description: Saves users and their notifications from the datastore to persistent storage.
Collects notifications from all users into a single map before saving.
Parameters:
- None
Returns:
- void
*/
void UserManagementService::saveUsers()
{
util::FileManager<User> userFileManager(config::file::USER_FILE);
util::FileManager<Notification> notificationFileManager(config::file::NOTIFICATION_FILE);
auto& users = m_dataStore.getUsers();
util::Map<std::string, Notification*> notifications;
for (int userIndex = 0; userIndex < users.getSize(); userIndex++)
{
User* user = users.getValueAt(userIndex);
auto& userNotifications = user->getNotifications();
for (int notificationIndex = 0; notificationIndex < userNotifications.getSize(); notificationIndex++)
{
notifications[userNotifications.getKeyAt(notificationIndex)] =
userNotifications.getValueAt(notificationIndex);
}
}
userFileManager.save(users);
notificationFileManager.save(notifications);
} }
/* /*
@@ -233,9 +270,7 @@ Return type: util::Map<std::string, User*>
*/ */
util::Map<std::string, User*> UserManagementService::getUsers() util::Map<std::string, User*> UserManagementService::getUsers()
{ {
DataStoreLockGuard lock(m_dataStore); return m_dataStore.getUsers();
auto users = util::getObjects(m_dataStore.getUsers());
return users;
} }
/* /*
@@ -246,12 +281,10 @@ Return type: User*
*/ */
User* UserManagementService::getUser(const std::string& userID) User* UserManagementService::getUser(const std::string& userID)
{ {
DataStoreLockGuard lock(m_dataStore); int index = m_dataStore.getUsers().find(userID);
auto& trackedUsersMap = m_dataStore.getUsers();
int index = trackedUsersMap.find(userID);
if (index != -1) if (index != -1)
{ {
return trackedUsersMap.getValueAt(index).data; return m_dataStore.getUsers().getValueAt(index);
} }
return nullptr; return nullptr;
} }
@@ -267,53 +300,35 @@ void UserManagementService::removeUser(const std::string& userID)
InventoryManagementService inventoryManagementService; InventoryManagementService inventoryManagementService;
PaymentManagementService paymentManagementService; PaymentManagementService paymentManagementService;
ServiceManagementService serviceManagementService; ServiceManagementService serviceManagementService;
DataStoreLockGuard lock(m_dataStore); int index = m_dataStore.getUsers().find(userID);
auto& trackedUsersMap = m_dataStore.getUsers();
int index = trackedUsersMap.find(userID);
if (index != -1) if (index != -1)
{ {
User* user = trackedUsersMap.getValueAt(index).data; User* user = m_dataStore.getUsers().getValueAt(index);
if (user != nullptr) if (user != nullptr)
{ {
if (user->getUserType() == util::UserType::CUSTOMER) if (user->getUserType() == util::UserType::CUSTOMER)
{ {
serviceManagementService.cancelCustomerServiceBookings(userID); serviceManagementService.cancelCustomerServiceBookings(userID);
} }
if (user->getUserType() == util::UserType::TECHNICIAN) if (user->getUserType() == util::UserType::TECHNICIAN)
{ {
serviceManagementService.cancelTechnicianJobs(userID); serviceManagementService.cancelTechnicianJobs(userID);
} }
user->setState(util::State::INACTIVE);
inventoryManagementService.detach(user); inventoryManagementService.detach(user);
paymentManagementService.detach(user); paymentManagementService.detach(user);
serviceManagementService.detach(user); serviceManagementService.detach(user);
user->setState(util::State::INACTIVE);
trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED;
m_dataStore.saveUsers();
} }
} }
} }
/* util::Map<std::string, User*> UserManagementService::getUsers(util::UserType type)
Function: getUsers
Description: Retrieves all active users of the specified type from
the DataStore.
Parameters:
- type: The user type to filter by
(ADMIN, CUSTOMER, or TECHNICIAN).
Returns:
- util::Map<std::string, User*>:
Collection of active users matching the specified type,
keyed by user ID.
*/
util::Map<std::string, User*> UserManagementService::getUsers(util::UserType type)
{ {
DataStoreLockGuard lock(m_dataStore); util::Map<std::string, User*>& currentUsers = m_dataStore.getUsers();
auto& trackedUsersMap = m_dataStore.getUsers();
util::Map<std::string, User*> currentUsers = util::getObjects(trackedUsersMap);
util::Map<std::string, User*> filteredUsersMap; util::Map<std::string, User*> filteredUsersMap;
for (int index = 0; index < currentUsers.getSize(); index++) for (int iterator = 0; iterator < currentUsers.getSize(); iterator++)
{ {
User* currentUser = currentUsers.getValueAt(index); User* currentUser = currentUsers.getValueAt(iterator);
if (currentUser && currentUser->getState() == util::State::ACTIVE && currentUser->getUserType() == type) if (currentUser && currentUser->getState() == util::State::ACTIVE && currentUser->getUserType() == type)
{ {
filteredUsersMap.insert(currentUser->getId(), currentUser); filteredUsersMap.insert(currentUser->getId(), currentUser);
@@ -31,4 +31,6 @@ public:
util::Vector<Notification*> getUserNotifications(const std::string& userID); util::Vector<Notification*> getUserNotifications(const std::string& userID);
void deleteNotification(const std::string& notificationID, const std::string& userID); void deleteNotification(const std::string& notificationID, const std::string& userID);
void ensureAdminExists(); void ensureAdminExists();
void loadUsers();
void saveUsers();
}; };
@@ -29,7 +29,6 @@ namespace config
namespace file namespace file
{ {
const size_t INITIAL_CAPACITY = 100; const size_t INITIAL_CAPACITY = 100;
const size_t GROWTH_FACTOR = 2;
constexpr const char* DIRECTORY = "files/"; constexpr const char* DIRECTORY = "files/";
constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.dat"; constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.dat";
constexpr const char* USER_FILE = "files/User.dat"; constexpr const char* USER_FILE = "files/User.dat";
@@ -43,4 +43,67 @@ namespace util
position++; position++;
} }
} }
/*
Function: loadRecords
Description: Loads records from a given file path into a vector of strings.
Skips the header line if present. Creates the file if it does not exist.
Parameters:
- filePath: const std::string&, path to the file
Returns:
- util::Vector<std::string>: Vector containing all records (excluding header)
Throws:
- None (creates file if missing)
*/
inline util::Vector<std::string> loadRecords(const std::string& filePath)
{
util::Vector<std::string> records;
std::ifstream file(filePath);
if (!file.is_open())
{
ensureDirectoryExists(filePath);
std::ofstream newFile(filePath);
newFile.close();
file.open(filePath);
}
std::string line;
bool isHeader = true;
while (std::getline(file, line))
{
if (isHeader)
{
isHeader = false;
continue;
}
records.push_back(line);
}
return records;
}
/*
Function: saveRecords
Description: Saves records to a given file path. Overwrites existing content
and writes a header line followed by all records.
Parameters:
- filePath: const std::string&, path to the file
- records: const util::Vector<std::string>&, vector of records to save
Returns:
- void
Throws:
- std::runtime_error if the file cannot be opened for writing
*/
inline void saveRecords(const std::string& filePath, const util::Vector<std::string>& records)
{
std::ofstream file(filePath, std::ios::trunc);
if (!file.is_open())
{
throw std::runtime_error("Failed to open file " + filePath);
}
file << "Values" << '\n';
int numberOfRecords = records.getSize();
for (int index = 0; index < numberOfRecords; index++)
{
file << records[index] << '\n';
}
}
} }
@@ -0,0 +1,119 @@
/*
File: FileManager.h
Description: Declares and implements a generic FileManager template class for
loading and saving objects to and from files. Uses serialization
and deserialization methods defined in the object type T.
Provides persistence support for system entities such as Users,
Services, InventoryItems, etc.
Author: Trenser
Date: 22-May-2026
*/
#pragma once
#include <stdexcept>
#include <string>
#include <fstream>
#include "Vector.h"
#include "Map.h"
#include "FileHelper.h"
namespace util
{
template <typename T> using objects = util::Map<std::string, T*>;
template <typename T>
class FileManager
{
private:
std::string m_filePath;
public:
FileManager() : m_filePath("") {}
FileManager(const std::string& filePath) : m_filePath(filePath) {}
objects<T> load();
void save(const objects<T>&);
};
/*
Function: load
Description: Loads records from the file into a map of objects.
Skips the header line, deserializes each record into an object of type T,
and stores them in a map keyed by object ID.
Parameters:
- None
Returns:
- util::Map<std::string, T*> containing deserialized objects
Throws:
- std::runtime_error if deserialization fails for any record
*/
template <typename T>
objects<T> FileManager<T>::load()
{
objects<T> records;
std::ifstream file(m_filePath);
if (!file.is_open())
{
ensureDirectoryExists(m_filePath);
std::ofstream newFile(m_filePath);
newFile.close();
file.open(m_filePath);
}
util::Vector<std::string> lines;
std::string line;
while (std::getline(file, line))
{
lines.push_back(line);
}
int numberOfLines = lines.getSize();
bool isHeader = true;
for (int lineIndex = 0; lineIndex < numberOfLines; lineIndex++)
{
const auto& record = lines[lineIndex];
if (isHeader)
{
isHeader = false;
continue;
}
auto object = T::deserialize(record);
if (!object)
{
throw std::runtime_error("Failed to deserialize record");
}
records[object->getId()] = object;
}
return records;
}
/*
Function: save
Description: Saves records to the file. Serializes each object of type T into a string,
writes a header line, and then writes all serialized records to the file.
Parameters:
- records: const util::Map<std::string, T*>&, map of objects to save
Returns:
- void
Throws:
- std::runtime_error if the file cannot be opened for writing
*/
template <typename T>
void FileManager<T>::save(const objects<T>& records)
{
util::Vector<std::string> lines;
lines.push_back(T::getHeaders());
int numberOfRecords = records.getSize();
for (int recordIndex = 0; recordIndex < numberOfRecords; recordIndex++)
{
const auto& record = records.getValueAt(recordIndex);
lines.push_back(record->serialize());
}
std::ofstream file(m_filePath, std::ios::trunc);
if (!file.is_open())
{
throw std::runtime_error("Failed to open file " + m_filePath);
}
int numberOfLines = lines.getSize();
for (int lineIndex = 0; lineIndex < numberOfLines; lineIndex++)
{
file << lines[lineIndex] << '\n';
}
}
}
@@ -28,7 +28,7 @@ namespace util
if (!(std::cin >> value)) if (!(std::cin >> value))
{ {
std::cin.clear(); std::cin.clear();
std::cin.ignore((std::numeric_limits<std::streamsize>::max)(), '\n'); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
throw std::runtime_error("Invalid console input"); throw std::runtime_error("Invalid console input");
} }
} }
@@ -54,79 +54,49 @@ namespace util
return cost; return cost;
} }
template<typename TObject> /*
Map<std::string, TObject*> getObjects(const Map<std::string, TrackedRecord<TObject>>& trackedRecords); Function: loadObservers
Description: Loads observer IDs from a file and attaches the corresponding users
template<typename TObject> to the notification management service. Validates that each observer ID
Map<std::string, const TObject*> getConstObjects(const Map<std::string, TrackedRecord<TObject>>& trackedRecords); exists in the datastore before attaching.
Parameters:
template<typename TObject> - filePath: const std::string&, path to the file containing observer IDs
TrackedRecord<TObject> createNewRecord(TObject* object); - service: NotificationManagementService*, pointer to the notification service
} - dataStore: DataStore&, reference to the datastore containing users
Returns:
/* - void
Function: getObjects Throws:
Description: Extracts the object pointers from a tracked-record - std::runtime_error if an observer ID is invalid (not found in datastore)
collection and returns them as a map keyed by the */
same identifiers. inline void loadObservers(const std::string& filePath, NotificationManagementService* service, DataStore& dataStore)
Parameters:
- trackedRecords: Collection of tracked records.
Returns:
- Map<std::string, TObject*>: Collection of object pointers.
*/
template<typename TObject>
util::Map<std::string, TObject*> util::getObjects(const util::Map<std::string, TrackedRecord<TObject>>& trackedRecords)
{
util::Map<std::string, TObject*> objects;
for (int index = 0; index < trackedRecords.getSize(); ++index)
{ {
const std::string& key = trackedRecords.getKeyAt(index); auto observerIDs = util::loadRecords(filePath);
TObject* object = trackedRecords.getValueAt(index).data; auto& users = dataStore.getUsers();
objects.insert(key, object); for (int index = 0; index < observerIDs.getSize(); index++)
{
const std::string& observerID = observerIDs[index];
int userIndex = users.find(observerID);
if (userIndex == -1)
{
throw std::runtime_error("Invalid Observer ID");
}
service->attach(users.getValueAt(userIndex));
}
} }
return objects;
}
/* /*
Function: getConstObjects Function: saveObservers
Description: Extracts the object pointers from a tracked-record Description: Saves the current observer IDs from the notification management service
collection and returns them as a read-only map to a file for persistence.
keyed by the same identifiers. Parameters:
Parameters: - filePath: const std::string&, path to the file where observer IDs will be saved
- trackedRecords: Collection of tracked records. - service: NotificationManagementService*, pointer to the notification service
Returns: Returns:
- Map<std::string, const TObject*>: - void
Collection of read-only object pointers. */
*/ inline void saveObservers(const std::string& filePath, NotificationManagementService* service)
template<typename TObject>
util::Map<std::string, const TObject*> util::getConstObjects(
const util::Map<std::string, TrackedRecord<TObject>>& trackedRecords)
{
util::Map<std::string, const TObject*> objects;
for (int index = 0; index < trackedRecords.getSize(); ++index)
{ {
const std::string& key = trackedRecords.getKeyAt(index); auto observerIDs = service->getObserverIDs();
const TObject* object = trackedRecords.getValueAt(index).data; util::saveRecords(filePath, observerIDs);
objects.insert(key, object);
} }
return objects;
}
/*
Function: createNewRecord
Description: Creates a tracked record for a newly created
object. The record is initialized with
NEW_RECORD state.
Parameters:
- object: Pointer to the newly created object.
Returns:
- TrackedRecord<TObject>: Initialized tracked record.
*/
template<typename TObject>
TrackedRecord<TObject> util::createNewRecord(TObject* object)
{
TrackedRecord<TObject> record;
record.data = object;
record.state = RecordState::NEW_RECORD;
return record;
} }
@@ -27,11 +27,8 @@ void UserInterface::run()
{ {
try try
{ {
if (!m_controller.initialize()) m_controller.loadSystemData();
{ m_controller.runSystemChecks();
std::cout << "Error: Failed to initialize the system!";
return;
}
bool isMenuActive = true; bool isMenuActive = true;
while (isMenuActive) while (isMenuActive)
{ {
@@ -52,7 +49,7 @@ void UserInterface::run()
util::pressEnter(); util::pressEnter();
} }
} }
m_controller.shutdown(); m_controller.saveSystemData();
} }
catch (const std::invalid_argument& exception) catch (const std::invalid_argument& exception)
{ {