Compare commits

..

1 Commits

Author SHA1 Message Date
joelthomastrenser 8a3ec278ce Merged PR 1159: Vehicle Service System v1.1.0.0
**New Features**

**Payment Confirmation Workflow**
- Added support for payment confirmation by administrators.

- Introduced a new PAID payment status.

- Implemented invoice confirmation flow from PAID → COMPLETED.

- Added invoice filtering based on payment status.

- Added admin menu option to confirm customer payments.

**Technician Job Status Workflow**
- Enhanced technician job management with multi-stage status updates.

- Added support for job status transitions:

- STARTED → IN_PROGRESS

- IN_PROGRESS → COMPLETED

- Added invoice generation and customer notification upon booking completion.

- Improved job visibility by displaying current job status.

**UI Improvements**
- Improved formatting and wording in the Technician Job Status workflow.

- Standardized status labels using "In Progress".

- Improved prompts, headings, and job selection messages.

- Enhanced readability of job listings.

**Bug Fixes**
- Fixed duplicate customer notifications when an assigned technician is removed.

- Prevented creation of duplicate usernames across all user states.

- Fixed authentication conflicts caused by reuse of deleted/disabled usernames.

- Improved booking cancellation handling for customer and technician removal scenarios.

- Updated cancellation logic to correctly handle bookings in IN_PROGRESS state.

Related work items: #1797, #1798, #1807, #1808, #1809
2026-06-01 18:57:46 +05:30
29 changed files with 574 additions and 1409 deletions
@@ -102,7 +102,7 @@
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)datastores\sharedmemory;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@@ -117,7 +117,7 @@
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;$(ProjectDir)datastores\sharedmemory;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>$(ProjectDir)models;$(ProjectDir)controllers;$(ProjectDir)factories;$(ProjectDir)views;$(ProjectDir)services;$(ProjectDir)utilities;$(ProjectDir)core\patterns;$(ProjectDir)datastores;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
@@ -129,7 +129,6 @@
<ClCompile Include="core\patterns\Observer.cpp" /> <ClCompile Include="core\patterns\Observer.cpp" />
<ClCompile Include="core\patterns\Subject.cpp" /> <ClCompile Include="core\patterns\Subject.cpp" />
<ClCompile Include="datastores\DataStore.cpp" /> <ClCompile Include="datastores\DataStore.cpp" />
<ClCompile Include="datastores\sharedmemory\SharedMemory.cpp" />
<ClCompile Include="models\ComboPackage.cpp" /> <ClCompile Include="models\ComboPackage.cpp" />
<ClCompile Include="models\InventoryItem.cpp" /> <ClCompile Include="models\InventoryItem.cpp" />
<ClCompile Include="models\Invoice.cpp" /> <ClCompile Include="models\Invoice.cpp" />
@@ -157,12 +156,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\sharedmemory\FileHeader.h" />
<ClInclude Include="datastores\sharedmemory\MappingInfo.h" />
<ClInclude Include="datastores\sharedmemory\RecordState.h" />
<ClInclude Include="datastores\sharedmemory\SerializedRecords.h" />
<ClInclude Include="datastores\sharedmemory\SharedMemory.h" />
<ClInclude Include="datastores\sharedmemory\TrackedRecord.h" />
<ClInclude Include="factories\Factory.h" /> <ClInclude Include="factories\Factory.h" />
<ClInclude Include="models\ComboPackage.h" /> <ClInclude Include="models\ComboPackage.h" />
<ClInclude Include="models\InventoryItem.h" /> <ClInclude Include="models\InventoryItem.h" />
@@ -64,12 +64,6 @@
<Filter Include="Source Files\Core\Patterns"> <Filter Include="Source Files\Core\Patterns">
<UniqueIdentifier>{8057b93d-51a9-42df-b06e-01ce395f6308}</UniqueIdentifier> <UniqueIdentifier>{8057b93d-51a9-42df-b06e-01ce395f6308}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Header Files\DataStores\SharedMemory">
<UniqueIdentifier>{ec639004-44c6-4bd6-9963-077adde82b5f}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\DataStores\SharedMemory">
<UniqueIdentifier>{7aa8722e-adfa-466e-8211-de63f3b7892b}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Trenser.VehicleServiceSystem.cpp"> <ClCompile Include="Trenser.VehicleServiceSystem.cpp">
@@ -147,9 +141,6 @@
<ClCompile Include="models\ComboPackage.cpp"> <ClCompile Include="models\ComboPackage.cpp">
<Filter>Source Files\Models</Filter> <Filter>Source Files\Models</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="datastores\sharedmemory\SharedMemory.cpp">
<Filter>Source Files\DataStores\SharedMemory</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="utilities\InputHelper.h"> <ClInclude Include="utilities\InputHelper.h">
@@ -260,23 +251,5 @@
<ClInclude Include="views\MenuHelper.h"> <ClInclude Include="views\MenuHelper.h">
<Filter>Header Files\Views</Filter> <Filter>Header Files\Views</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="datastores\sharedmemory\FileHeader.h">
<Filter>Header Files\DataStores\SharedMemory</Filter>
</ClInclude>
<ClInclude Include="datastores\sharedmemory\MappingInfo.h">
<Filter>Header Files\DataStores\SharedMemory</Filter>
</ClInclude>
<ClInclude Include="datastores\sharedmemory\RecordState.h">
<Filter>Header Files\DataStores\SharedMemory</Filter>
</ClInclude>
<ClInclude Include="datastores\sharedmemory\TrackedRecord.h">
<Filter>Header Files\DataStores\SharedMemory</Filter>
</ClInclude>
<ClInclude Include="datastores\sharedmemory\SerializedRecords.h">
<Filter>Header Files\DataStores\SharedMemory</Filter>
</ClInclude>
<ClInclude Include="datastores\sharedmemory\SharedMemory.h">
<Filter>Header Files\DataStores\SharedMemory</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -9,139 +9,6 @@ Date: 19-May-2026
*/ */
#include "DataStore.h" #include "DataStore.h"
#include "Config.h"
#include "SerializedRecords.h"
#include "FileHelper.h"
DataStore::DataStore() :
m_globalMutex(NULL) {}
/*
Function: initialize
Description: Initializes the shared-memory datastore.
Creates or opens the global datastore mutex,
configures all mapping metadata, and creates
or opens the file mappings used to persist
application data. After successful completion,
all datastore files are mapped into memory and
ready for use by the application.
Parameter: None
Return type: bool
- true : Initialization completed successfully.
- false : Failed to create the mutex or open
one or more file mappings.
*/
bool DataStore::initialize()
{
m_globalMutex = CreateMutexA(NULL, FALSE, "VehicleServiceSystemMutex");
if (m_globalMutex == NULL)
{
return false;
}
util::ensureDirectoryExists(config::file::DIRECTORY);
m_users.fileName = config::file::USER_FILE;
m_users.recordSize = sizeof(SerializedUser);
m_notifications.fileName = config::file::NOTIFICATION_FILE;
m_notifications.recordSize = sizeof(SerializedNotification);
m_services.fileName = config::file::SERVICE_FILE;
m_services.recordSize = sizeof(SerializedService);
m_comboPackages.fileName = config::file::COMBOPACKAGE_FILE;
m_comboPackages.recordSize = sizeof(SerializedComboPackage);
m_inventoryItems.fileName = config::file::INVENTORYITEM_FILE;
m_inventoryItems.recordSize = sizeof(SerializedInventoryItem);
m_serviceBookings.fileName = config::file::SERVICEBOOKING_FILE;
m_serviceBookings.recordSize = sizeof(SerializedServiceBooking);
m_jobCards.fileName = config::file::JOBCARD_FILE;
m_jobCards.recordSize = sizeof(SerializedJobCard);
m_invoices.fileName = config::file::INVOICE_FILE;
m_invoices.recordSize = sizeof(SerializedInvoice);
m_serviceManagementObservers.fileName = config::file::SERVICEMANAGEMENTOBSERVERS;
m_serviceManagementObservers.recordSize = sizeof(SerializedObserver);
m_paymentManagementObservers.fileName = config::file::PAYMENTMANAGEMENTOBSERVERS;
m_paymentManagementObservers.recordSize = sizeof(SerializedObserver);
m_inventoryManagementObservers.fileName = config::file::INVENTORYMANAGEMENTOBSERVERS;
m_inventoryManagementObservers.recordSize = sizeof(SerializedObserver);
if (!SharedMemory::createOrOpenMapping(m_users))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_notifications))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_services))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_comboPackages))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_inventoryItems))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_serviceBookings))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_jobCards))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_invoices))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_payments))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_serviceManagementObservers))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_paymentManagementObservers))
{
return false;
}
if (!SharedMemory::createOrOpenMapping(m_inventoryManagementObservers))
{
return false;
}
return true;
}
/*
Function: shutdown
Description: Releases all shared-memory resources owned by the
datastore. Closes every file mapping, unmaps all
mapped views, and releases the datastore mutex.
After this call, the datastore must be initialized
again before use.
Parameter: None
Return type: void
*/
void DataStore::shutdown()
{
SharedMemory::closeMapping(m_users);
SharedMemory::closeMapping(m_notifications);
SharedMemory::closeMapping(m_services);
SharedMemory::closeMapping(m_comboPackages);
SharedMemory::closeMapping(m_inventoryItems);
SharedMemory::closeMapping(m_serviceBookings);
SharedMemory::closeMapping(m_jobCards);
SharedMemory::closeMapping(m_invoices);
SharedMemory::closeMapping(m_payments);
SharedMemory::closeMapping(m_serviceManagementObservers);
SharedMemory::closeMapping(m_paymentManagementObservers);
SharedMemory::closeMapping(m_inventoryManagementObservers);
if (m_globalMutex != NULL)
{
CloseHandle(m_globalMutex);
m_globalMutex = NULL;
}
}
/* /*
Function: getInstance Function: getInstance
@@ -159,370 +26,104 @@ DataStore& DataStore::getInstance()
/* /*
Function: getUsers Function: getUsers
Description: Retrieves all user records from the datastore. Description: Retrieves the internal map of users.
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, TrackedRecord<User>>: Collection of user records - Reference to util::Map<std::string, User*> containing all users.
*/ */
util::Map<std::string, TrackedRecord<User>> DataStore::getUsers() util::Map<std::string, User*>& DataStore::getUsers()
{ {
return util::Map<std::string, TrackedRecord<User>>(); return m_users;
}
/*
Function: getNotifications
Description: Retrieves all notification records from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, TrackedRecord<Notification>>: Collection of notification records
*/
util::Map<std::string, TrackedRecord<Notification>> DataStore::getNotifications()
{
return util::Map<std::string, TrackedRecord<Notification>>();
} }
/* /*
Function: getServices Function: getServices
Description: Retrieves all service records from the datastore. Description: Retrieves the internal map of services.
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, TrackedRecord<Service>>: Collection of service records - Reference to util::Map<std::string, Service*> containing all services.
*/ */
util::Map<std::string, TrackedRecord<Service>> DataStore::getServices() util::Map<std::string, Service*>& DataStore::getServices()
{ {
return util::Map<std::string, TrackedRecord<Service>>(); return m_services;
} }
/* /*
Function: getComboPackages Function: getComboPackages
Description: Retrieves all combo package records from the datastore. Description: Retrieves the internal map of combo packages.
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, TrackedRecord<ComboPackage>>: Collection of combo package records - Reference to util::Map<std::string, ComboPackage*> containing all combo packages.
*/ */
util::Map<std::string, TrackedRecord<ComboPackage>> DataStore::getComboPackages() util::Map<std::string, ComboPackage*>& DataStore::getComboPackages()
{ {
return util::Map<std::string, TrackedRecord<ComboPackage>>(); return m_comboPackages;
}
/*
Function: getInventoryItems
Description: Retrieves all inventory item records from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, TrackedRecord<InventoryItem>>: Collection of inventory item records
*/
util::Map<std::string, TrackedRecord<InventoryItem>> DataStore::getInventoryItems()
{
return util::Map<std::string, TrackedRecord<InventoryItem>>();
} }
/* /*
Function: getServiceBookings Function: getServiceBookings
Description: Retrieves all service booking records from the datastore. Description: Retrieves the internal map of service bookings.
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, TrackedRecord<ServiceBooking>>: Collection of service booking records - Reference to util::Map<std::string, ServiceBooking*> containing all service bookings.
*/ */
util::Map<std::string, TrackedRecord<ServiceBooking>> DataStore::getServiceBookings() util::Map<std::string, ServiceBooking*>& DataStore::getServiceBookings()
{ {
return util::Map<std::string, TrackedRecord<ServiceBooking>>(); return m_serviceBookings;
} }
/* /*
Function: getJobCards Function: getJobCards
Description: Retrieves all job card records from the datastore. Description: Retrieves the internal map of job cards.
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, TrackedRecord<JobCard>>: Collection of job card records - Reference to util::Map<std::string, JobCard*> containing all job cards.
*/ */
util::Map<std::string, TrackedRecord<JobCard>> DataStore::getJobCards() util::Map<std::string, JobCard*>& DataStore::getJobCards()
{ {
return util::Map<std::string, TrackedRecord<JobCard>>(); return m_jobCards;
}
/*
Function: getInventoryItems
Description: Retrieves the internal map of inventory items.
Parameters:
- None
Returns:
- Reference to util::Map<std::string, InventoryItem*> containing all inventory items.
*/
util::Map<std::string, InventoryItem*>& DataStore::getInventoryItems()
{
return m_inventoryItems;
} }
/* /*
Function: getInvoices Function: getInvoices
Description: Retrieves all invoice records from the datastore. Description: Retrieves the internal map of invoices.
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, TrackedRecord<Invoice>>: Collection of invoice records - Reference to util::Map<std::string, Invoice*> containing all invoices.
*/ */
util::Map<std::string, TrackedRecord<Invoice>> DataStore::getInvoices() util::Map<std::string, Invoice*>& DataStore::getInvoices()
{ {
return util::Map<std::string, TrackedRecord<Invoice>>(); return m_invoices;
} }
/* /*
Function: getPayments Function: getPayments
Description: Retrieves all payment records from the datastore. Description: Retrieves the internal map of payments.
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, TrackedRecord<Payment>>: Collection of payment records - Reference to util::Map<std::string, Payment*> containing all payments.
*/ */
util::Map<std::string, TrackedRecord<Payment>> DataStore::getPayments() util::Map<std::string, Payment*>& DataStore::getPayments()
{ {
return util::Map<std::string, TrackedRecord<Payment>>(); return m_payments;
}
/*
Function: getServiceManagementObservers
Description: Retrieves all service management observer records from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, TrackedRecord<std::string>>: Collection of observer records
*/
util::Map<std::string, TrackedRecord<std::string>> DataStore::getServiceManagementObservers()
{
return util::Map<std::string, TrackedRecord<std::string>>();
}
/*
Function: getPaymentManagementObservers
Description: Retrieves all payment management observer records from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, TrackedRecord<std::string>>: Collection of observer records
*/
util::Map<std::string, TrackedRecord<std::string>> DataStore::getPaymentManagementObservers()
{
return util::Map<std::string, TrackedRecord<std::string>>();
}
/*
Function: getInventoryManagementObservers
Description: Retrieves all inventory management observer records from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, TrackedRecord<std::string>>: Collection of observer records
*/
util::Map<std::string, TrackedRecord<std::string>> DataStore::getInventoryManagementObservers()
{
return util::Map<std::string, TrackedRecord<std::string>>();
}
/*
Function: saveUsers
Description: Persists all user records to the datastore.
Parameters:
- users: util::Map<std::string, TrackedRecord<User>>&, collection of user records
Returns:
- None
*/
void DataStore::saveUsers(util::Map<std::string, TrackedRecord<User>>& users)
{
}
/*
Function: saveNotifications
Description: Persists all notification records to the datastore.
Parameters:
- notifications: util::Map<std::string, TrackedRecord<Notification>>&, collection of notification records
Returns:
- None
*/
void DataStore::saveNotifications(util::Map<std::string, TrackedRecord<Notification>>& notifications)
{
}
/*
Function: saveServices
Description: Persists all service records to the datastore.
Parameters:
- services: util::Map<std::string, TrackedRecord<Service>>&, collection of service records
Returns:
- None
*/
void DataStore::saveServices(util::Map<std::string, TrackedRecord<Service>>& services)
{
}
/*
Function: saveComboPackages
Description: Persists all combo package records to the datastore.
Parameters:
- comboPackages: util::Map<std::string, TrackedRecord<ComboPackage>>&, collection of combo package records
Returns:
- None
*/
void DataStore::saveComboPackages(util::Map<std::string, TrackedRecord<ComboPackage>>& comboPackages)
{
}
/*
Function: saveInventoryItems
Description: Persists all inventory item records to the datastore.
Parameters:
- inventoryItems: util::Map<std::string, TrackedRecord<InventoryItem>>&, collection of inventory item records
Returns:
- None
*/
void DataStore::saveInventoryItems(util::Map<std::string, TrackedRecord<InventoryItem>>& inventoryItems)
{
}
/*
Function: saveServiceBookings
Description: Persists all service booking records to the datastore.
Parameters:
- bookings: util::Map<std::string, TrackedRecord<ServiceBooking>>&, collection of service booking records
Returns:
- None
*/
void DataStore::saveServiceBookings(util::Map<std::string, TrackedRecord<ServiceBooking>>& bookings)
{
}
/*
Function: saveJobCards
Description: Persists all job card records to the datastore.
Parameters:
- jobCards: util::Map<std::string, TrackedRecord<JobCard>>&, collection of job card records
Returns:
- None
*/
void DataStore::saveJobCards(util::Map<std::string, TrackedRecord<JobCard>>& jobCards)
{
}
/*
Function: saveInvoices
Description: Persists all invoice records to the datastore.
Parameters:
- invoices: util::Map<std::string, TrackedRecord<Invoice>>&, collection of invoice records
Returns:
- None
*/
void DataStore::saveInvoices(util::Map<std::string, TrackedRecord<Invoice>>& invoices)
{
}
/*
Function: savePayments
Description: Persists all payment records to the datastore.
Parameters:
- payments: util::Map<std::string, TrackedRecord<Payment>>&, collection of payment records
Returns:
- None
*/
void DataStore::savePayments(util::Map<std::string, TrackedRecord<Payment>>& payments)
{
}
/*
Function: saveServiceManagementObservers
Description: Persists all service management observer records to the datastore.
Parameters:
- observers: util::Map<std::string, TrackedRecord<std::string>>&, collection of observer records
Returns:
- None
*/
void DataStore::saveServiceManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& observers)
{
}
/*
Function: savePaymentManagementObservers
Description: Persists all payment management observer records to the datastore.
Parameters:
- observers: util::Map<std::string, TrackedRecord<std::string>>&, collection of observer records
Returns:
- None
*/
void DataStore::savePaymentManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& observers)
{
}
/*
Function: saveInventoryManagementObservers
Description: Persists all inventory management observer records to the datastore.
Parameters:
- observers: util::Map<std::string, TrackedRecord<std::string>>&, collection of observer records
Returns:
- None
*/
void DataStore::saveInventoryManagementObservers(util::Map<std::string, TrackedRecord<std::string>>& 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;
}
/*
Function: lockDataStore
Description: Acquires the datastore mutex, providing
exclusive access to the shared-memory
datastore. This function blocks until
the mutex becomes available or an error
occurs.
Parameter: None
Return type:
bool
- true : Mutex successfully acquired.
- false : Failed to acquire the mutex.
*/
bool DataStore::lockDataStore()
{
if (m_globalMutex == NULL)
{
return false;
}
DWORD result = WaitForSingleObject(m_globalMutex, INFINITE);
return result == WAIT_OBJECT_0;
}
/*
Function: unlockDataStore
Description: Releases the datastore mutex after a
successful call to lockDataStore(),
allowing other processes to access the
shared-memory datastore.
Parameter: None
Return type:
bool
- true : Mutex successfully released.
- false : Failed to release the mutex.
*/
bool DataStore::unlockDataStore()
{
if (m_globalMutex == NULL)
{
return false;
}
return ReleaseMutex(m_globalMutex) != 0;
} }
@@ -6,166 +6,42 @@ Date: 19-May-2026
*/ */
#pragma once #pragma once
#include <windows.h>
#include <string> #include <string>
#include "Map.h" #include "Map.h"
#include "MappingInfo.h"
#include "TrackedRecord.h"
#include "SharedMemory.h"
class User; class User;
class Notification;
class Service; class Service;
class ComboPackage; class ComboPackage;
class InventoryItem;
class ServiceBooking; class ServiceBooking;
class JobCard; class JobCard;
class InventoryItem;
class Invoice; class Invoice;
class Payment; class Payment;
class DataStore class DataStore
{ {
private: private:
DataStore(); util::Map<std::string, User*> m_users;
util::Map<std::string, Service*> m_services;
util::Map<std::string, ComboPackage*> m_comboPackages;
util::Map<std::string, ServiceBooking*> m_serviceBookings;
util::Map<std::string, JobCard*> m_jobCards;
util::Map<std::string, InventoryItem*> m_inventoryItems;
util::Map<std::string, Invoice*> m_invoices;
util::Map<std::string, Payment*> m_payments;
DataStore() {}
public:
static DataStore& getInstance();
DataStore(const DataStore&) = delete; DataStore(const DataStore&) = delete;
DataStore& operator=(const DataStore&) = delete; DataStore& operator=(const DataStore&) = delete;
DataStore(DataStore&&) = delete; DataStore(DataStore&&) = delete;
DataStore& operator=(DataStore&&) = delete; DataStore& operator=(DataStore&&) = delete;
HANDLE m_globalMutex; util::Map<std::string, User*>& getUsers();
MappingInfo m_users; util::Map<std::string, Service*>& getServices();
MappingInfo m_notifications; util::Map<std::string, ComboPackage*>& getComboPackages();
MappingInfo m_services; util::Map<std::string, ServiceBooking*>& getServiceBookings();
MappingInfo m_comboPackages; util::Map<std::string, JobCard*>& getJobCards();
MappingInfo m_inventoryItems; util::Map<std::string, InventoryItem*>& getInventoryItems();
MappingInfo m_serviceBookings; util::Map<std::string, Invoice*>& getInvoices();
MappingInfo m_jobCards; util::Map<std::string, Payment*>& getPayments();
MappingInfo m_invoices;
MappingInfo m_payments;
MappingInfo m_serviceManagementObservers;
MappingInfo m_paymentManagementObservers;
MappingInfo m_inventoryManagementObservers;
public:
static DataStore& getInstance();
bool initialize();
void shutdown();
util::Map<std::string, TrackedRecord<User>> getUsers();
util::Map<std::string, TrackedRecord<Notification>> getNotifications();
util::Map<std::string, TrackedRecord<Service>> getServices();
util::Map<std::string, TrackedRecord<ComboPackage>> getComboPackages();
util::Map<std::string, TrackedRecord<InventoryItem>> getInventoryItems();
util::Map<std::string, TrackedRecord<ServiceBooking>> getServiceBookings();
util::Map<std::string, TrackedRecord<JobCard>> getJobCards();
util::Map<std::string, TrackedRecord<Invoice>> getInvoices();
util::Map<std::string, TrackedRecord<Payment>> getPayments();
util::Map<std::string, TrackedRecord<std::string>> getServiceManagementObservers();
util::Map<std::string, TrackedRecord<std::string>> getPaymentManagementObservers();
util::Map<std::string, TrackedRecord<std::string>> getInventoryManagementObservers();
void saveUsers(util::Map<std::string, TrackedRecord<User>>& users);
void saveNotifications(util::Map<std::string, TrackedRecord<Notification>>& notifications);
void saveServices(util::Map<std::string, TrackedRecord<Service>>& services);
void saveComboPackages(util::Map<std::string, TrackedRecord<ComboPackage>>& comboPackages);
void saveInventoryItems(util::Map<std::string, TrackedRecord<InventoryItem>>& inventoryItems);
void saveServiceBookings(util::Map<std::string, TrackedRecord<ServiceBooking>>& bookings);
void saveJobCards(util::Map<std::string, TrackedRecord<JobCard>>& jobCards);
void saveInvoices(util::Map<std::string, TrackedRecord<Invoice>>& invoices);
void savePayments(util::Map<std::string, TrackedRecord<Payment>>& payments);
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 unlockDataStore();
private:
template<typename TObject, typename TSerialized>
util::Map<std::string, TrackedRecord<TObject>> loadRecords(MappingInfo& mapping);
template<typename TObject, typename TSerialized>
void saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records);
}; };
/*
Function: loadRecords
Description: Loads all serialized records from the specified
shared-memory mapping, deserializes them into
application objects, and returns them as a map
of tracked records. Each loaded record is marked
as CLEAN and assigned its corresponding slot index
within the mapping so that future modifications
can be written back efficiently.
Parameter:
- mapping: Reference to the mapping containing the
serialized records.
Return type:
util::Map<std::string, TrackedRecord<TObject>>
A map containing all loaded records keyed by
their unique identifier.
*/
template<typename TObject, typename TSerialized>
util::Map<std::string, TrackedRecord<TObject>> DataStore::loadRecords(MappingInfo& mapping)
{
util::Map<std::string, TrackedRecord<TObject>> records;
SharedMemory::ensureLatestMapping(mapping);
size_t recordCount = SharedMemory::getRecordCount(mapping);
for (size_t index = 0; index < recordCount; ++index)
{
TSerialized* serialized = static_cast<TSerialized*>(SharedMemory::getRecordAddress(mapping,index));
TObject* object = TObject::deserialize(*serialized);
TrackedRecord<TObject> trackedRecord;
trackedRecord.data = object;
trackedRecord.state = RecordState::CLEAN;
trackedRecord.slotIndex = index;
records.insert(object->getId(), trackedRecord);
}
return records;
}
/*
Function: saveRecords
Description: Persists all modified and newly added records
contained in the provided map to the specified
shared-memory mapping. Modified records overwrite
their existing slots, while new records are
appended to the end of the mapping. Records marked
as CLEAN are ignored. After persistence, all
temporary objects owned by the tracked records are
destroyed to release memory.
Parameter:
- mapping: Reference to the mapping where records are
stored.
- records: Map containing the records to be persisted.
Return type: void
*/
template<typename TObject, typename TSerialized> void DataStore::saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records)
{
SharedMemory::ensureLatestMapping(mapping);
for (int index = 0; index < records.getSize(); ++index)
{
TrackedRecord<TObject>& record = records.getValueAt(index);
if (record.state == RecordState::CLEAN)
{
continue;
}
TSerialized serialized = record.data->serialize();
if (record.state == RecordState::MODIFIED)
{
TSerialized* destination = static_cast<TSerialized*>(SharedMemory::getRecordAddress(mapping, record.slotIndex));
if (destination)
{
*destination = serialized;
}
}
else if (record.state == RecordState::NEW_RECORD)
{
if (!SharedMemory::ensureCapacityForInsert(mapping))
{
continue;
}
size_t recordCount = SharedMemory::getRecordCount(mapping);
TSerialized* destination = static_cast<TSerialized*>(SharedMemory::getRecordAddress(mapping, recordCount));
*destination = serialized;
SharedMemory::setRecordCount(mapping, recordCount + 1);
}
}
for (int index = 0; index < records.getSize(); ++index)
{
delete records.getValueAt(index).data;
records.getValueAt(index).data = nullptr;
}
}
@@ -1,8 +0,0 @@
#pragma once
#include <cstddef>
struct FileHeader
{
size_t recordCount;
size_t capacity;
};
@@ -1,19 +0,0 @@
#pragma once
#include <windows.h>
#include <string>
struct MappingInfo
{
HANDLE fileHandle;
HANDLE mappingHandle;
void* mappedView;
std::string fileName;
size_t recordSize;
size_t mappedCapacity;
MappingInfo()
: fileHandle(NULL),
mappingHandle(NULL),
mappedView(nullptr),
recordSize(0),
mappedCapacity(0) {}
};
@@ -1,8 +0,0 @@
#pragma once
enum class RecordState : int
{
CLEAN,
NEW_RECORD,
MODIFIED
};
@@ -1,97 +0,0 @@
#pragma once
#include "Utility.h"
#include "Enums.h"
#include "Timestamp.h"
struct SerializedUser
{
char id[64];
char username[64];
char password[64];
char name[128];
char phone[32];
char email[128];
util::UserType userType;
util::State status;
};
struct SerializedNotification
{
char id[64];
char recipientUserId[64];
char title[128];
char message[1024];
util::Timestamp createdAt;
util::State state;
};
struct SerializedService
{
char id[64];
char name[128];
char inventoryItemIDs[1024];
double laborCost;
util::State status;
};
struct SerializedComboPackage
{
char id[64];
char packageName[128];
double discountPercentage;
char serviceIDs[1024];
util::State status;
};
struct SerializedInventoryItem
{
char id[64];
char partName[128];
int quantity;
double price;
util::State status;
};
struct SerializedServiceBooking
{
char id[64];
util::ServiceJobStatus status;
char serviceIDs[1024];
char customerId[64];
char vehicleNumber[64];
char vehicleBrand[64];
char vehicleModel[64];
char assignedTechnicianId[64];
double discountPercentage;
};
struct SerializedJobCard
{
char id[64];
char bookingId[64];
char serviceId[64];
char technicianId[64];
util::Timestamp assignedDate;
util::ServiceJobStatus status;
util::Timestamp completionDate;
};
struct SerializedInvoice
{
char id[64];
char bookingId[64];
util::Timestamp invoiceDate;
char partIDs[1024];
double laborCost;
double partsCost;
double discountPercentage;
double totalAmount;
util::Timestamp paymentDate;
util::PaymentMode paymentMethod;
util::PaymentStatus status;
};
struct SerializedObserver
{
char id[64];
};
@@ -1,374 +0,0 @@
#include "SharedMemory.h"
#include "Config.h"
/*
Function: invalidateMapping
Description: Releases all mapping resources and resets the mapping to an invalid state.
Parameters:
- mapping: MappingInfo&, mapping information and handles
Returns:
- None
*/
static void invalidateMapping(MappingInfo& mapping)
{
if (mapping.mappedView != nullptr)
{
UnmapViewOfFile(mapping.mappedView);
mapping.mappedView = nullptr;
}
if (mapping.mappingHandle != NULL)
{
CloseHandle(mapping.mappingHandle);
mapping.mappingHandle = NULL;
}
if (mapping.fileHandle != INVALID_HANDLE_VALUE)
{
CloseHandle(mapping.fileHandle);
mapping.fileHandle = INVALID_HANDLE_VALUE;
}
mapping.mappedCapacity = 0;
}
/*
Function: createOrOpenMapping
Description: Creates or opens a file mapping and maps it into the process address space.
Parameters:
- mapping: MappingInfo&, mapping information and handles
Returns:
- bool: True if the mapping was successfully created/opened, otherwise false
*/
bool SharedMemory::createOrOpenMapping(MappingInfo& mapping)
{
if (mapping.recordSize == 0)
{
return false;
}
mapping.fileHandle =
CreateFileA(
mapping.fileName.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (mapping.fileHandle == INVALID_HANDLE_VALUE)
{
return false;
}
LARGE_INTEGER fileSize;
if (!GetFileSizeEx(mapping.fileHandle, &fileSize))
{
invalidateMapping(mapping);
return false;
}
bool isNewFile = (fileSize.QuadPart == 0);
const size_t initialCapacity = config::file::INITIAL_CAPACITY;
if (isNewFile)
{
LARGE_INTEGER newSize;
newSize.QuadPart = sizeof(FileHeader) + initialCapacity * mapping.recordSize;
if (!SetFilePointerEx(mapping.fileHandle, newSize, NULL, FILE_BEGIN))
{
invalidateMapping(mapping);
return false;
}
if (!SetEndOfFile(mapping.fileHandle))
{
invalidateMapping(mapping);
return false;
}
}
mapping.mappingHandle =
CreateFileMappingA(
mapping.fileHandle,
NULL,
PAGE_READWRITE,
0,
0,
NULL);
if (mapping.mappingHandle == NULL)
{
invalidateMapping(mapping);
return false;
}
mapping.mappedView =
MapViewOfFile(
mapping.mappingHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if (mapping.mappedView == nullptr)
{
invalidateMapping(mapping);
return false;
}
FileHeader* header = getHeader(mapping);
if (header == nullptr)
{
invalidateMapping(mapping);
return false;
}
if (isNewFile)
{
header->recordCount = 0;
header->capacity = initialCapacity;
}
mapping.mappedCapacity = header->capacity;
return true;
}
/*
Function: closeMapping
Description: Unmaps and closes all resources associated with a file mapping.
Parameters:
- mapping: MappingInfo&, mapping to close
Returns:
- None
*/
void SharedMemory::closeMapping(MappingInfo& mapping)
{
invalidateMapping(mapping);
}
/*
Function: getHeader
Description: Returns the file header stored at the beginning of the mapped memory region.
Parameters:
- mapping: MappingInfo&, mapping information and handles
Returns:
- FileHeader*: Pointer to the file header, or nullptr if the mapping is not valid
*/
FileHeader* SharedMemory::getHeader(MappingInfo& mapping)
{
if (mapping.mappedView == nullptr)
{
return nullptr;
}
return reinterpret_cast<FileHeader*>(mapping.mappedView);
}
/*
Function: getRecordAddress
Description: Returns the address of a record at the specified index within the mapped memory region.
Parameters:
- mapping: MappingInfo&, mapping information and handles
- index: size_t, record index
Returns:
- void*: Pointer to the record, or nullptr if the mapping is not valid
*/
void* SharedMemory::getRecordAddress(MappingInfo& mapping, size_t index)
{
if (mapping.mappedView == nullptr)
{
return nullptr;
}
return reinterpret_cast<char*>(mapping.mappedView) + sizeof(FileHeader) + index * mapping.recordSize;
}
/*
Function: getRecordCount
Description: Returns the number of records currently stored in the mapping.
Parameters:
- mapping: MappingInfo&, mapping information and handles
Returns:
- size_t: Number of records in the mapping
*/
size_t SharedMemory::getRecordCount(MappingInfo& mapping)
{
FileHeader* header = getHeader(mapping);
if (header == nullptr)
{
return 0;
}
return header->recordCount;
}
/*
Function: setRecordCount
Description: Updates the number of records stored in the mapping.
Parameters:
- mapping: MappingInfo&, mapping information and handles
- count: size_t, new record count
Returns:
- None
*/
void SharedMemory::setRecordCount(MappingInfo& mapping, size_t count)
{
FileHeader* header = getHeader(mapping);
if (header == nullptr)
{
return;
}
header->recordCount = count;
}
/*
Function: getCapacity
Description: Returns the current capacity of the mapping.
Parameters:
- mapping: MappingInfo&, mapping information and handles
Returns:
- size_t: Maximum number of records that can be stored in the mapping
*/
size_t SharedMemory::getCapacity(MappingInfo& mapping)
{
FileHeader* header = getHeader(mapping);
if (header == nullptr)
{
return 0;
}
return header->capacity;
}
/*
Function: resizeMapping
Description: Resizes the file mapping to the specified capacity.
Parameters:
- mapping: MappingInfo&, mapping information and handles
- newCapacity: size_t, new mapping capacity
Returns:
- bool: True if the resize succeeded, otherwise false
*/
bool SharedMemory::resizeMapping(MappingInfo& mapping, size_t newCapacity)
{
FileHeader* header = getHeader(mapping);
if (header == nullptr)
{
invalidateMapping(mapping);
return false;
}
header->capacity = newCapacity;
if (!FlushViewOfFile(mapping.mappedView, sizeof(FileHeader)))
{
return false;
}
if (!UnmapViewOfFile(mapping.mappedView))
{
return false;
}
mapping.mappedView = nullptr;
CloseHandle(mapping.mappingHandle);
mapping.mappingHandle = NULL;
LARGE_INTEGER newSize;
newSize.QuadPart = sizeof(FileHeader) + newCapacity * mapping.recordSize;
if (!SetFilePointerEx(mapping.fileHandle, newSize, NULL, FILE_BEGIN))
{
invalidateMapping(mapping);
return false;
}
if (!SetEndOfFile(mapping.fileHandle))
{
invalidateMapping(mapping);
return false;
}
mapping.mappingHandle =
CreateFileMappingA(
mapping.fileHandle,
NULL,
PAGE_READWRITE,
0,
0,
NULL);
if (mapping.mappingHandle == NULL)
{
invalidateMapping(mapping);
return false;
}
mapping.mappedView =
MapViewOfFile(
mapping.mappingHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if (mapping.mappedView == nullptr)
{
invalidateMapping(mapping);
return false;
}
mapping.mappedCapacity = newCapacity;
return true;
}
/*
Function: ensureCapacityForInsert
Description: Ensures that the mapping has space for at least one additional record, growing it if necessary.
Parameters:
- mapping: MappingInfo&, mapping information and handles
Returns:
- bool: True if capacity is available, otherwise false
*/
bool SharedMemory::ensureCapacityForInsert(MappingInfo& mapping)
{
size_t recordCount = getRecordCount(mapping);
size_t capacity = getCapacity(mapping);
if (recordCount < capacity)
{
return true;
}
return resizeMapping(mapping, capacity * 2);
}
/*
Function: ensureLatestMapping
Description: Remaps the file if another process has resized it.
Parameters:
- mapping: MappingInfo&, mapping information and handles
Returns:
- bool: True if the mapping is valid and up to date, otherwise false
*/
bool SharedMemory::ensureLatestMapping(MappingInfo& mapping)
{
FileHeader* header = getHeader(mapping);
if (header == nullptr)
{
return false;
}
if (header->capacity == mapping.mappedCapacity)
{
return true;
}
if (!UnmapViewOfFile(mapping.mappedView))
{
invalidateMapping(mapping);
return false;
}
mapping.mappedView = nullptr;
CloseHandle(mapping.mappingHandle);
mapping.mappingHandle = NULL;
mapping.mappingHandle =
CreateFileMappingA(
mapping.fileHandle,
NULL,
PAGE_READWRITE,
0,
0,
NULL);
if (mapping.mappingHandle == NULL)
{
invalidateMapping(mapping);
return false;
}
mapping.mappedView =
MapViewOfFile(
mapping.mappingHandle,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
if (mapping.mappedView == nullptr)
{
invalidateMapping(mapping);
return false;
}
header = getHeader(mapping);
if (header == nullptr)
{
invalidateMapping(mapping);
return false;
}
mapping.mappedCapacity = header->capacity;
return true;
}
@@ -1,18 +0,0 @@
#pragma once
#include <cstddef>
#include "MappingInfo.h"
#include "FileHeader.h"
namespace SharedMemory
{
bool createOrOpenMapping(MappingInfo& mapping);
void closeMapping(MappingInfo& mapping);
bool ensureLatestMapping(MappingInfo& mapping);
bool resizeMapping(MappingInfo& mapping, size_t newCapacity);
FileHeader* getHeader(MappingInfo& mapping);
void* getRecordAddress(MappingInfo& mapping, size_t index);
size_t getRecordCount(MappingInfo& mapping);
void setRecordCount(MappingInfo& mapping, size_t count);
size_t getCapacity(MappingInfo& mapping);
bool ensureCapacityForInsert(MappingInfo& mapping);
};
@@ -1,23 +0,0 @@
#pragma once
#include "RecordState.h"
static const size_t INVALID_SLOT = static_cast<size_t>(-1);
template<typename T>
struct TrackedRecord
{
T* data;
RecordState state;
size_t slotIndex;
TrackedRecord()
: data(nullptr),
state(RecordState::CLEAN),
slotIndex(INVALID_SLOT) {}
TrackedRecord(
T* object,
RecordState recordState,
size_t slot)
: data(object),
state(recordState),
slotIndex(slot) {}
};
@@ -9,7 +9,6 @@ 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"
@@ -271,38 +270,72 @@ static util::Vector<std::string> getServiceIDsAsVector(const std::string& servic
/* /*
Function: serialize Function: serialize
Description: Serializes the ComboPackage object into a SerializedComboPackage record. Description: Serializes the combo package into a CSV-formatted string.
Parameters: Parameters:
- None - None
Returns: Returns:
- SerializedComboPackage: Serialized representation of the combo package - std::string: Serialized combo package record
*/ */
SerializedComboPackage ComboPackage::serialize() const std::string ComboPackage::serialize() const
{ {
SerializedComboPackage serialized = {}; std::ostringstream serializedComboPackage;
strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str()); serializedComboPackage << m_id << ','
strcpy_s(serialized.packageName, sizeof(serialized.packageName), m_packageName.c_str()); << m_packageName << ','
strcpy_s(serialized.serviceIDs, sizeof(serialized.serviceIDs), getServiceIDsAsString(m_serviceIDs).c_str()); << m_discountPercentage << ','
serialized.discountPercentage = m_discountPercentage; << getServiceIDsAsString(m_serviceIDs) << ','
serialized.status = m_status; << util::getStateString(m_status);
return serialized; return serializedComboPackage.str();
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a SerializedComboPackage record into a ComboPackage object. Description: Deserializes a CSV-formatted string into a ComboPackage object.
Parameters: Parameters:
- serializedComboPackage: const SerializedComboPackage&, serialized combo package record - record: const std::string&, 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 SerializedComboPackage& serializedComboPackage) ComboPackage* ComboPackage::deserialize(const std::string& record)
{ {
util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serializedComboPackage.serviceIDs); std::string id, packageName;
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>(
serializedComboPackage.id, id,
serializedComboPackage.packageName, packageName,
serializedComboPackage.discountPercentage, discountPercentage,
serviceIDs, serviceIDs,
serializedComboPackage.status); 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,6 @@ Date: 19-May-2026
#include "Enums.h" #include "Enums.h"
class Service; class Service;
class SerializedComboPackage;
class ComboPackage class ComboPackage
{ {
@@ -39,6 +38,7 @@ 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);
SerializedComboPackage serialize() const; std::string serialize() const;
static ComboPackage* deserialize(const SerializedComboPackage&); static ComboPackage* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -8,7 +8,6 @@ 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"
@@ -207,37 +206,73 @@ void InventoryItem::setState(util::State status)
/* /*
Function: serialize Function: serialize
Description: Serializes the InventoryItem object into a SerializedInventoryItem record. Description: Serializes the inventory item into a CSV-formatted string.
Parameters: Parameters:
- None - None
Returns: Returns:
- SerializedInventoryItem: Serialized representation of the inventory item - std::string: Serialized inventory item record
*/ */
SerializedInventoryItem InventoryItem::serialize() const std::string InventoryItem::serialize() const
{ {
SerializedInventoryItem serialized = {}; std::ostringstream serializedInventoryItem;
strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str()); serializedInventoryItem << m_id << ','
strcpy_s(serialized.partName, sizeof(serialized.partName), m_partName.c_str()); << m_partName << ','
serialized.quantity = m_quantity; << m_quantity << ','
serialized.price = m_price; << m_price << ','
serialized.status = m_status; << util::getStateString(m_status);
return serialized; return serializedInventoryItem.str();
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a SerializedInventoryItem record into an InventoryItem object. Description: Deserializes a CSV-formatted string into an InventoryItem object.
Parameters: Parameters:
- serializedInventoryItem: const SerializedInventoryItem&, serialized inventory item record - record: const std::string&, 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 SerializedInventoryItem& serializedInventoryItem) InventoryItem* InventoryItem::deserialize(const std::string& record)
{ {
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>(
serializedInventoryItem.id, id,
serializedInventoryItem.partName, partName,
serializedInventoryItem.quantity, quantity,
serializedInventoryItem.price, price,
serializedInventoryItem.status); 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,12 +6,11 @@ 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:
@@ -35,6 +34,7 @@ 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);
SerializedInventoryItem serialize() const; std::string serialize() const;
static InventoryItem* deserialize(const SerializedInventoryItem&); static InventoryItem* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -9,7 +9,6 @@ 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"
@@ -474,50 +473,100 @@ static util::Vector<std::string> getPartIDsAsVector(const std::string& partIDsSt
/* /*
Function: serialize Function: serialize
Description: Serializes the Invoice object into a SerializedInvoice record. Description: Serializes the invoice into a CSV-formatted string.
Parameters: Parameters:
- None - None
Returns: Returns:
- SerializedInvoice: Serialized representation of the invoice - std::string: Serialized invoice record
*/ */
SerializedInvoice Invoice::serialize() const std::string Invoice::serialize() const
{ {
SerializedInvoice serialized = {}; std::ostringstream serializedInvoice;
strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str()); serializedInvoice << m_id << ','
strcpy_s(serialized.bookingId, sizeof(serialized.bookingId), m_bookingId.c_str()); << m_bookingId << ','
strcpy_s(serialized.partIDs, sizeof(serialized.partIDs), getPartIDsAsString(m_partIDs).c_str()); << m_invoiceDate.toString() << ','
serialized.invoiceDate = m_invoiceDate; << m_laborCost << ','
serialized.laborCost = m_laborCost; << getPartIDsAsString(m_partIDs) << ','
serialized.partsCost = m_partsCost; << m_partsCost << ','
serialized.discountPercentage = m_discountPercentage; << m_discountPercentage << ','
serialized.totalAmount = m_totalAmount; << m_totalAmount << ','
serialized.paymentDate = m_paymentDate; << m_paymentDate.toString() << ','
serialized.paymentMethod = m_paymentMethod; << util::getPaymentModeString(m_paymentMethod) << ','
serialized.status = m_status; << util::getPaymentStatusString(m_status);
return serialized; return serializedInvoice.str();
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a SerializedInvoice record into an Invoice object. Description: Deserializes a CSV-formatted string into an Invoice object.
Parameters: Parameters:
- serializedInvoice: const SerializedInvoice&, serialized invoice record - record: const std::string&, 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 SerializedInvoice& serializedInvoice) Invoice* Invoice::deserialize(const std::string& record)
{ {
util::Vector<std::string> partIDs = getPartIDsAsVector(serializedInvoice.partIDs); std::string id, bookingId;
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>(
serializedInvoice.id, id,
serializedInvoice.bookingId, bookingId,
serializedInvoice.invoiceDate, invoiceDate,
partIDs, partIDs,
serializedInvoice.laborCost, laborCost,
serializedInvoice.partsCost, partsCost,
serializedInvoice.discountPercentage, discountPercentage,
serializedInvoice.totalAmount, totalAmount,
serializedInvoice.paymentDate, paymentDate,
serializedInvoice.paymentMethod, paymentMethod,
serializedInvoice.status); 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,7 +16,6 @@ Date: 19-May-2026
class ServiceBooking; class ServiceBooking;
class InventoryItem; class InventoryItem;
struct SerializedInvoice;
class Invoice class Invoice
{ {
@@ -88,6 +87,7 @@ 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);
SerializedInvoice serialize() const; std::string serialize() const;
static Invoice* deserialize(const SerializedInvoice&); static Invoice* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -9,7 +9,6 @@ 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"
@@ -352,41 +351,79 @@ void JobCard::setCompletionDate(const util::Timestamp& completionDate)
/* /*
Function: serialize Function: serialize
Description: Serializes the JobCard object into a SerializedJobCard record. Description: Serializes the job card into a CSV-formatted string.
Parameters: Parameters:
- None - None
Returns: Returns:
- SerializedJobCard: Serialized representation of the job card - std::string: Serialized job card record
*/ */
SerializedJobCard JobCard::serialize() const std::string JobCard::serialize() const
{ {
SerializedJobCard serialized = {}; std::ostringstream serializedJobCard;
strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str()); serializedJobCard << m_id << ','
strcpy_s(serialized.bookingId, sizeof(serialized.bookingId), m_bookingId.c_str()); << m_bookingId << ','
strcpy_s(serialized.serviceId, sizeof(serialized.serviceId), m_serviceId.c_str()); << m_serviceId << ','
strcpy_s(serialized.technicianId, sizeof(serialized.technicianId), m_technicianId.c_str()); << m_technicianId << ','
serialized.assignedDate = m_assignedDate; << m_assignedDate.toString() << ','
serialized.status = m_status; << util::getServiceJobStatusString(m_status) << ','
serialized.completionDate = m_completionDate; << m_completionDate.toString();
return serialized; return serializedJobCard.str();
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a SerializedJobCard record into a JobCard object. Description: Deserializes a CSV-formatted string into a JobCard object.
Parameters: Parameters:
- serializedJobCard: const SerializedJobCard&, serialized job card record - record: const std::string&, 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 SerializedJobCard& serializedJobCard) JobCard* JobCard::deserialize(const std::string& record)
{ {
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>(
serializedJobCard.id, id,
serializedJobCard.bookingId, bookingId,
serializedJobCard.serviceId, serviceId,
serializedJobCard.technicianId, technicianId,
serializedJobCard.assignedDate, assignedDate,
serializedJobCard.status, status,
serializedJobCard.completionDate); 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,7 +15,6 @@ Date:19-May-2026
class ServiceBooking; class ServiceBooking;
class Service; class Service;
class User; class User;
struct SerializedJobCard;
class JobCard class JobCard
{ {
@@ -71,6 +70,7 @@ 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);
SerializedJobCard serialize() const; std::string serialize() const;
static JobCard* deserialize(const SerializedJobCard&); static JobCard* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -7,7 +7,6 @@ Date: 19-May-2026
*/ */
#include <sstream> #include <sstream>
#include "SerializedRecords.h"
#include "Notification.h" #include "Notification.h"
#include "StringHelper.h" #include "StringHelper.h"
#include "Factory.h" #include "Factory.h"
@@ -24,7 +23,7 @@ Returns:
*/ */
Notification::Notification() Notification::Notification()
: m_id("NOT" + std::to_string(++m_uid)), : m_id("NOT" + std::to_string(++m_uid)),
m_recipient(nullptr), m_state(util::State::ACTIVE) {} m_recipient(nullptr) {}
/* /*
Function: Notification Function: Notification
@@ -44,8 +43,7 @@ Notification::Notification(const std::string& recipientUserId, User* recipient,
m_recipient(recipient), m_recipient(recipient),
m_title(title), m_title(title),
m_message(message), m_message(message),
m_state(util::State::ACTIVE), m_createdAt(createdAt) {}
m_createdAt(createdAt){}
/* /*
Function: Notification (parameterized constructor with ID) Function: Notification (parameterized constructor with ID)
@@ -60,14 +58,13 @@ Parameters:
Returns: Returns:
- A new Notification object - A new Notification object
*/ */
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)
: m_id(id), : m_id(id),
m_recipientUserId(recipientUserId), m_recipientUserId(recipientUserId),
m_recipient(nullptr), m_recipient(nullptr),
m_title(title), m_title(title),
m_message(message), m_message(message),
m_createdAt(createdAt), m_createdAt(createdAt)
m_state(state)
{ {
int idNumber = util::extractNumber(m_id); int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid) if (idNumber > m_uid)
@@ -222,39 +219,69 @@ void Notification::setCreatedAt(const util::Timestamp& createdAt)
/* /*
Function: serialize Function: serialize
Description: Serializes the Notification object into a SerializedNotification record. Description: Serializes the notification into a CSV-formatted string.
Parameters: Parameters:
- None - None
Returns: Returns:
- SerializedNotification: Serialized representation of the notification - std::string: Serialized notification record
*/ */
SerializedNotification Notification::serialize() const std::string Notification::serialize() const
{ {
SerializedNotification serialized = {}; std::ostringstream serializedNotification;
strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str()); serializedNotification << m_id << ','
strcpy_s(serialized.recipientUserId, sizeof(serialized.recipientUserId), m_recipientUserId.c_str()); << m_recipientUserId << ','
strcpy_s(serialized.title, sizeof(serialized.title), m_title.c_str()); << m_title << ','
strcpy_s(serialized.message, sizeof(serialized.message), m_message.c_str()); << m_message << ','
serialized.createdAt = m_createdAt; << m_createdAt.toString();
serialized.state = m_state; return serializedNotification.str();
return serialized;
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a SerializedNotification record into a Notification object. Description: Deserializes a CSV-formatted string into a Notification object.
Parameters: Parameters:
- serializedNotification: const SerializedNotification&, serialized notification record - record: const std::string&, serialized notification record
Returns: Returns:
- Notification*: Pointer to the deserialized Notification object - Notification*: Pointer to the deserialized Notification object
Throws:
- std::runtime_error if timestamp parsing fails
*/ */
Notification* Notification::deserialize(const SerializedNotification& serializedNotification) Notification* Notification::deserialize(const std::string& record)
{ {
std::string id, recipientUserId, title, message, createdAtTimestampString;
std::istringstream serializedNotification(record);
getline(serializedNotification, id, ',');
getline(serializedNotification, recipientUserId, ',');
getline(serializedNotification, title, ',');
getline(serializedNotification, message, ',');
getline(serializedNotification, createdAtTimestampString, ',');
util::Timestamp createdAtTimestamp;
try
{
createdAtTimestamp = util::Timestamp::fromString(createdAtTimestampString);
}
catch (...)
{
throw std::runtime_error("Invalid createdAt timestamp");
}
return Factory::getObject<Notification>( return Factory::getObject<Notification>(
serializedNotification.id, id,
serializedNotification.recipientUserId, recipientUserId,
serializedNotification.title, title,
serializedNotification.message, message,
serializedNotification.createdAt, createdAtTimestamp
serializedNotification.state); );
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for notification serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,RecipientID,Title,Message,Timestamp")
*/
std::string Notification::getHeaders()
{
return "ID,RecipientID,Title,Message,Timestamp";
} }
@@ -9,10 +9,8 @@ Date: 19-May-2026
#pragma once #pragma once
#include <string> #include <string>
#include "Timestamp.h" #include "Timestamp.h"
#include "Enums.h"
class User; class User;
struct SerializedNotification;
class Notification class Notification
{ {
@@ -24,11 +22,10 @@ private:
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;
public: public:
Notification(); Notification();
Notification(const std::string& recipientUserId, User* recipient, 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 std::string& getId() const; const std::string& getId() const;
const std::string& getRecipientUserId() const; const std::string& getRecipientUserId() const;
User* getRecipient() const; User* getRecipient() const;
@@ -41,8 +38,7 @@ public:
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(); std::string serialize() const;
void setState(util::State state); static Notification* deserialize(const std::string&);
SerializedNotification serialize() const; static std::string getHeaders();
static Notification* deserialize(const SerializedNotification&);
}; };
@@ -8,7 +8,6 @@ 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"
@@ -267,38 +266,72 @@ static util::Vector<std::string> getInventoryItemIDsAsVector(const std::string&
/* /*
Function: serialize Function: serialize
Description: Serializes the Service object into a SerializedService record. Description: Serializes the service into a CSV-formatted string.
Parameters: Parameters:
- None - None
Returns: Returns:
- SerializedService: Serialized representation of the service - std::string: Serialized service record
*/ */
SerializedService Service::serialize() const std::string Service::serialize() const
{ {
SerializedService serialized = {}; std::ostringstream serializedService;
strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str()); serializedService << m_id << ','
strcpy_s(serialized.name, sizeof(serialized.name), m_name.c_str()); << m_name << ','
strcpy_s(serialized.inventoryItemIDs, sizeof(serialized.inventoryItemIDs), getInventoryItemIDsAsString(m_requiredInventoryItemIDs).c_str()); << getInventoryItemIDsAsString(m_requiredInventoryItemIDs) << ','
serialized.laborCost = m_laborCost; << m_laborCost << ','
serialized.status = m_status; << util::getStateString(m_status);
return serialized; return serializedService.str();
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a SerializedService record into a Service object. Description: Deserializes a CSV-formatted string into a Service object.
Parameters: Parameters:
- serializedService: const SerializedService&, serialized service record - record: const std::string&, 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 SerializedService& serializedService) Service* Service::deserialize(const std::string& record)
{ {
util::Vector<std::string> inventoryItemIDs = getInventoryItemIDsAsVector(serializedService.inventoryItemIDs); std::string id, name;
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>(
serializedService.id, id,
serializedService.name, name,
inventoryItemIDs, inventoryItemIDs,
serializedService.laborCost, laborCost,
serializedService.status); 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";
} }
@@ -14,7 +14,6 @@ Date: 19-May-2026
#include "Enums.h" #include "Enums.h"
class InventoryItem; class InventoryItem;
struct SerializedService;
class Service class Service
{ {
@@ -41,6 +40,7 @@ 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);
SerializedService serialize() const; std::string serialize() const;
static Service* deserialize(const SerializedService&); static Service* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -8,7 +8,6 @@ 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"
@@ -438,46 +437,84 @@ static util::Vector<std::string> getServiceIDsAsVector(const std::string& servic
/* /*
Function: serialize Function: serialize
Description: Serializes the ServiceBooking object into a SerializedServiceBooking record. Description: Serializes the service booking into a CSV-formatted string.
Parameters: Parameters:
- None - None
Returns: Returns:
- SerializedServiceBooking: Serialized representation of the service booking - std::string: Serialized booking record
*/ */
SerializedServiceBooking ServiceBooking::serialize() const std::string ServiceBooking::serialize() const
{ {
SerializedServiceBooking serialized = {}; std::ostringstream serializedBooking;
strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str()); serializedBooking << m_id << ','
strcpy_s(serialized.serviceIDs, sizeof(serialized.serviceIDs), getServiceIDsAsString(m_serviceIDs).c_str()); << util::getServiceJobStatusString(m_status) << ','
strcpy_s(serialized.customerId, sizeof(serialized.customerId), m_customerId.c_str()); << getServiceIDsAsString(m_serviceIDs) << ','
strcpy_s(serialized.vehicleNumber, sizeof(serialized.vehicleNumber), m_vehicleNumber.c_str()); << m_customerId << ','
strcpy_s(serialized.vehicleBrand, sizeof(serialized.vehicleBrand), m_vehicleBrand.c_str()); << m_vehicleNumber << ','
strcpy_s(serialized.vehicleModel, sizeof(serialized.vehicleModel), m_vehicleModel.c_str()); << m_vehicleBrand << ','
strcpy_s(serialized.assignedTechnicianId, sizeof(serialized.assignedTechnicianId), m_assignedTechnicianId.c_str()); << m_vehicleModel << ','
serialized.status = m_status; << m_assignedTechnicianId << ','
serialized.discountPercentage = m_discountPercentage; << m_discountPercentage << ',';
return serialized; return serializedBooking.str();
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a SerializedServiceBooking record into a ServiceBooking object. Description: Deserializes a CSV-formatted string into a ServiceBooking object.
Parameters: Parameters:
- serializedServiceBooking: const SerializedServiceBooking&, serialized service booking record - record: const std::string&, serialized 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 SerializedServiceBooking& serializedServiceBooking) ServiceBooking* ServiceBooking::deserialize(const std::string& record)
{ {
util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serializedServiceBooking.serviceIDs); std::string id, customerId, vehicleNumber, vehicleBrand, vehicleModel, assignedTechnicianId;
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>(
serializedServiceBooking.id, id,
serializedServiceBooking.status, status,
serviceIDs, serviceIDs,
serializedServiceBooking.customerId, customerId,
serializedServiceBooking.vehicleNumber, vehicleNumber,
serializedServiceBooking.vehicleBrand, vehicleBrand,
serializedServiceBooking.vehicleModel, vehicleModel,
serializedServiceBooking.assignedTechnicianId, assignedTechnicianId,
serializedServiceBooking.discountPercentage); 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";
} }
@@ -14,7 +14,6 @@ Date:19-May-2026
class Service; class Service;
class User; class User;
struct SerializedServiceBooking;
class ServiceBooking class ServiceBooking
{ {
@@ -79,6 +78,7 @@ 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);
SerializedServiceBooking serialize() const; std::string serialize() const;
static ServiceBooking* deserialize(const SerializedServiceBooking&); static ServiceBooking* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -8,7 +8,6 @@ Date: 19-May-2026
*/ */
#include <sstream> #include <sstream>
#include "SerializedRecords.h"
#include "User.h" #include "User.h"
#include "Notification.h" #include "Notification.h"
#include "Enums.h" #include "Enums.h"
@@ -325,43 +324,68 @@ void User::setState(util::State status)
/* /*
Function: serialize Function: serialize
Description: Serializes the User object into a SerializedUser record. Description: Serializes the user into a CSV-formatted string.
Parameters: Parameters:
- None - None
Returns: Returns:
- SerializedUser: Serialized representation of the user - std::string: Serialized user record
*/ */
SerializedUser User::serialize() const std::string User::serialize() const
{ {
SerializedUser serialized = {}; std::ostringstream serializedUser;
strcpy_s(serialized.id, sizeof(serialized.id), m_id.c_str()); serializedUser << m_id << ','
strcpy_s(serialized.username, sizeof(serialized.username), m_userName.c_str()); << m_userName << ','
strcpy_s(serialized.password, sizeof(serialized.password), m_password.c_str()); << m_password << ','
strcpy_s(serialized.name, sizeof(serialized.name), m_name.c_str()); << m_name << ','
strcpy_s(serialized.phone, sizeof(serialized.phone), m_phone.c_str()); << m_phone << ','
strcpy_s(serialized.email, sizeof(serialized.email), m_email.c_str()); << m_email << ','
serialized.userType = m_type; << util::getUserTypeString(m_type) << ','
serialized.status = m_status; << util::getStateString(m_status);
return serialized; return serializedUser.str();
} }
/* /*
Function: deserialize Function: deserialize
Description: Deserializes a SerializedUser record into a User object. Description: Deserializes a CSV-formatted string into a User object.
Parameters: Parameters:
- serializedUser: const SerializedUser&, serialized user record - record: const std::string&, serialized user record
Returns: Returns:
- User*: Pointer to the deserialized User object - User*: Pointer to the deserialized User object
*/ */
User* User::deserialize(const SerializedUser& serializedUser) User* User::deserialize(const std::string& record)
{ {
return Factory::getObject<User>( std::string id, name, username, phone, password, email;
serializedUser.id, std::string userTypeString, stateString;
serializedUser.username, std::istringstream serializedUser(record);
serializedUser.password, getline(serializedUser, id, ',');
serializedUser.name, getline(serializedUser, username, ',');
serializedUser.phone, getline(serializedUser, password, ',');
serializedUser.email, getline(serializedUser, name, ',');
serializedUser.userType, getline(serializedUser, phone, ',');
serializedUser.status); getline(serializedUser, email, ',');
getline(serializedUser, userTypeString, ',');
getline(serializedUser, stateString);
util::UserType userType = util::getUserType(userTypeString);
util::State status = util::getState(stateString);
return Factory::getObject<User>(id,
username,
password,
name,
phone,
email,
userType,
status);
}
/*
Function: getHeaders
Description: Retrieves the CSV headers for user serialization.
Parameters:
- None
Returns:
- std::string: Header string ("ID,Username,Password,Name,Phone,Email,UserType,UserStatus")
*/
std::string User::getHeaders()
{
return "ID,Username,Password,Name,Phone,Email,UserType,UserStatus";
} }
@@ -14,7 +14,6 @@ Date: 19-May-2026
#include "Enums.h" #include "Enums.h"
class Notification; class Notification;
struct SerializedUser;
class User : public Observer class User : public Observer
{ {
@@ -52,6 +51,7 @@ public:
void addNotification(Notification* notification) override; 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; std::string serialize() const;
static User* deserialize(const SerializedUser& serializedUser); static User* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -28,18 +28,16 @@ namespace config
namespace file namespace file
{ {
const size_t INITIAL_CAPACITY = 100; constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.csv";
constexpr const char* DIRECTORY = "files/"; constexpr const char* USER_FILE = "files/User.csv";
constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.dat"; constexpr const char* NOTIFICATION_FILE = "files/Notification.csv";
constexpr const char* USER_FILE = "files/User.dat"; constexpr const char* SERVICE_FILE = "files/Service.csv";
constexpr const char* NOTIFICATION_FILE = "files/Notification.dat"; constexpr const char* COMBOPACKAGE_FILE = "files/ComboPackage.csv";
constexpr const char* SERVICE_FILE = "files/Service.dat"; constexpr const char* SERVICEBOOKING_FILE = "files/ServiceBooking.csv";
constexpr const char* COMBOPACKAGE_FILE = "files/ComboPackage.dat"; constexpr const char* JOBCARD_FILE = "files/JobCard.csv";
constexpr const char* SERVICEBOOKING_FILE = "files/ServiceBooking.dat"; constexpr const char* INVOICE_FILE = "files/Invoice.csv";
constexpr const char* JOBCARD_FILE = "files/JobCard.dat"; constexpr const char* SERVICEMANAGEMENTOBSERVERS = "files/ServiceManagementObservers.csv";
constexpr const char* INVOICE_FILE = "files/Invoice.dat"; constexpr const char* PAYMENTMANAGEMENTOBSERVERS = "files/PaymentManagementObservers.csv";
constexpr const char* SERVICEMANAGEMENTOBSERVERS = "files/ServiceManagementObservers.dat"; constexpr const char* INVENTORYMANAGEMENTOBSERVERS = "files/InventoryManagementObservers.csv";
constexpr const char* PAYMENTMANAGEMENTOBSERVERS = "files/PaymentManagementObservers.dat";
constexpr const char* INVENTORYMANAGEMENTOBSERVERS = "files/InventoryManagementObservers.dat";
} }
} }
@@ -12,28 +12,28 @@ Date: 19-May-2026
namespace util namespace util
{ {
enum class UserType : int enum class UserType
{ {
ADMIN, ADMIN,
TECHNICIAN, TECHNICIAN,
CUSTOMER CUSTOMER
}; };
enum class PaymentMode : int enum class PaymentMode
{ {
ONLINE, ONLINE,
OFFLINE, OFFLINE,
NOTSET NOTSET
}; };
enum class PaymentStatus : int enum class PaymentStatus
{ {
PENDING, PENDING,
COMPLETED, COMPLETED,
PAID PAID
}; };
enum class ServiceJobStatus : int enum class ServiceJobStatus
{ {
PENDING, PENDING,
STARTED, STARTED,
@@ -42,7 +42,7 @@ namespace util
CANCELLED CANCELLED
}; };
enum class State : int enum class State
{ {
ACTIVE, ACTIVE,
INACTIVE INACTIVE