Compare commits

..

1 Commits

51 changed files with 734 additions and 5724 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,13 +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\DataStoreLockGuard.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>
@@ -6,17 +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 "ComboPackage.h"
#include "Controller.h" #include "Controller.h"
#include "Enums.h" #include "Enums.h"
#include "InventoryItem.h"
#include "Invoice.h"
#include "JobCard.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "User.h" #include "User.h"
#include <stdexcept>
/* /*
Function: login Function: login
@@ -62,7 +55,6 @@ Parameter: const std::string& username - customer
const std::string& phone - customers phone number const std::string& phone - customers phone number
Return type: void Return type: void
*/ */
void Controller::createCustomer(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone) void Controller::createCustomer(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone)
{ {
m_userManagementService.createUser(username, name, password, email, phone, util::UserType::CUSTOMER); m_userManagementService.createUser(username, name, password, email, phone, util::UserType::CUSTOMER);
@@ -79,19 +71,8 @@ const User* Controller::getAuthenticatedUser()
return m_authenticationManagementService.getAuthenticatedUser(); return m_authenticationManagementService.getAuthenticatedUser();
} }
/* void Controller::createTechnician(const std::string& username, const std::string& password, const std::string& email, const std::string& phone)
Function: createTechnician
Description: Creates a new technician account with provided details by
delegating to the user management service.
Parameter: const std::string& username - technician's username
const std::string& password - technician's password
const std::string& email - technician's email address
const std::string& phoneNumber - technician's phone number
Return type: void
*/
void Controller::createTechnician(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phoneNumber)
{ {
m_userManagementService.createUser(username, name, password, email, phoneNumber, util::UserType::TECHNICIAN);
} }
/* /*
@@ -111,45 +92,14 @@ void Controller::updateUserDetails(const std::string& email, const std::string&
m_userManagementService.updateUserDetails(authenticatedUser->getId(), email, phone); m_userManagementService.updateUserDetails(authenticatedUser->getId(), email, phone);
} }
/*
Function: getServices
Description: Retrieves all available services in read-only form.
Parameters:
- None
Returns:
- util::Map<std::string, const Service*> containing all services
*/
util::Map<std::string, const Service*> Controller::getServices() util::Map<std::string, const Service*> Controller::getServices()
{ {
util::Map<std::string, Service*> currentServices = m_serviceManagementService.getServices(); return util::Map<std::string, const Service*>();
util::Map<std::string, const Service*> readOnlyServices;
for (int iterator = 0; iterator < currentServices.getSize(); iterator++)
{
readOnlyServices.insert(currentServices.getValueAt(iterator)->getId(), currentServices.getValueAt(iterator));
}
return readOnlyServices;
} }
/*
Function: getComboPackages
Description: Retrieves all available combo packages from the service
management service and constructs a read-only map.
Parameter: None
Return type: util::Map<std::string, const ComboPackage*>
*/
util::Map<std::string, const ComboPackage*> Controller::getComboPackages() util::Map<std::string, const ComboPackage*> Controller::getComboPackages()
{ {
util::Map<std::string, ComboPackage*> currentAvailableComboPackages = m_serviceManagementService.getComboPackages(); return util::Map<std::string, const ComboPackage*>();
util::Map<std::string, const ComboPackage*> readOnlyComboPackages;
for (int iterator = 0; iterator < currentAvailableComboPackages.getSize(); iterator++)
{
ComboPackage* currentComboPackage = currentAvailableComboPackages.getValueAt(iterator);
if (currentComboPackage)
{
readOnlyComboPackages.insert(currentComboPackage->getId(), currentComboPackage);
}
}
return readOnlyComboPackages;
} }
/* /*
@@ -180,333 +130,84 @@ void Controller::purchaseComboPackage(const std::string& comboPackageID, const s
m_serviceManagementService.purchaseComboPackage(comboPackageID, vehicleNumber, vehicleBrand, vehicleModel); m_serviceManagementService.purchaseComboPackage(comboPackageID, vehicleNumber, vehicleBrand, vehicleModel);
} }
/*
Function: getInventoryItems
Description: Retrieves all inventory items from the inventory management service
and constructs a read-only map for external use.
Parameter: None
Return type: util::Map<std::string, const InventoryItem*>
*/
util::Map<std::string, const InventoryItem*> Controller::getInventoryItems() util::Map<std::string, const InventoryItem*> Controller::getInventoryItems()
{ {
auto inventoryItems = m_inventoryManagementService.getInventoryItems(); return util::Map<std::string, const InventoryItem*>();
util::Map<std::string, const InventoryItem*> readOnlyInventoryItems;
int inventoryItemsMapSize = inventoryItems.getSize();
for (int index = 0; index < inventoryItemsMapSize; index++)
{
readOnlyInventoryItems.insert(inventoryItems.getKeyAt(index), inventoryItems.getValueAt(index));
}
return readOnlyInventoryItems;
} }
/*
Function: getInventoryItem
Description: Retrieves a specific inventory item by its ID from the inventory management service.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: const InventoryItem*
*/
const InventoryItem* Controller::getInventoryItem(const std::string& inventoryItemID) const InventoryItem* Controller::getInventoryItem(const std::string& inventoryItemID)
{ {
return m_inventoryManagementService.getInventoryItem(inventoryItemID); return nullptr;
} }
/*
Function: addInventoryItem
Description: Adds a new inventory item with specified details to the inventory management service.
Parameter: const std::string& partName - name of the part
int quantity - quantity of the part
double price - price of the part
Return type: void
*/
void Controller::addInventoryItem(const std::string& partName, int quantity, double price) void Controller::addInventoryItem(const std::string& partName, int quantity, double price)
{ {
m_inventoryManagementService.addInventoryItem(partName, quantity, price);
} }
/*
Function: removeInventoryItem
Description: Removes an inventory item from the inventory management service by its ID.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: void
*/
void Controller::removeInventoryItem(const std::string& inventoryItemID) void Controller::removeInventoryItem(const std::string& inventoryItemID)
{ {
m_inventoryManagementService.removeInventoryItem(inventoryItemID);
} }
/*
Function: addInventoryItemStock
Description: Adds stock to an existing inventory item in the inventory management service.
Parameter: const std::string& selectedItemId - ID of the inventory item
int quantity - quantity to add
Return type: void
*/
void Controller::addInventoryItemStock(const std::string& selectedItemId, int quantity)
{
m_inventoryManagementService.addInventoryItemStock(selectedItemId, quantity);
}
/*
Function: getServiceBookings
Description: Retrieves all service bookings in read-only form.
Parameters:
- None
Returns:
- util::Map<std::string, const ServiceBooking*> containing service bookings
*/
util::Map<std::string, const ServiceBooking*> Controller::getServiceBookings() util::Map<std::string, const ServiceBooking*> Controller::getServiceBookings()
{ {
auto serviceBookings = m_serviceManagementService.getServiceBookings(); return util::Map<std::string, const ServiceBooking*>();
util::Map<std::string, const ServiceBooking*> readOnlyServiceBookings;
for (int iterator = 0; iterator < serviceBookings.getSize(); iterator++)
{
readOnlyServiceBookings.insert(serviceBookings.getKeyAt(iterator), serviceBookings.getValueAt(iterator));
}
return readOnlyServiceBookings;
} }
/*
Function: getServiceBookingsByUser
Description: Retrieves all service bookings for a specific user.
Parameters:
- userID: std::string, the user ID
Returns:
- util::Map<std::string, const ServiceBooking*> containing bookings for the user
*/
util::Map<std::string, const ServiceBooking*> Controller::getServiceBookingsByUser(const std::string userID) util::Map<std::string, const ServiceBooking*> Controller::getServiceBookingsByUser(const std::string userID)
{ {
util::Map<std::string, const ServiceBooking*> readOnlyServiceBookingsByUserMap; return util::Map<std::string, const ServiceBooking*>();
util::Map<std::string, ServiceBooking*> currentServiceBookingsByUser = m_serviceManagementService.getServiceBookings(userID);
for (int iterator = 0; iterator < currentServiceBookingsByUser.getSize(); iterator++)
{
readOnlyServiceBookingsByUserMap.insert(currentServiceBookingsByUser.getValueAt(iterator)->getId(), currentServiceBookingsByUser.getValueAt(iterator));
}
return readOnlyServiceBookingsByUserMap;
} }
/*
Function: getUsers
Description: Retrieves all users from the user management service and
constructs a read-only map.
Parameter: None
Return type: util::Map<std::string, const User*>
*/
util::Map<std::string, const User*> Controller::getUsers() util::Map<std::string, const User*> Controller::getUsers()
{ {
auto listOfUsers = m_userManagementService.getUsers(); return util::Map<std::string, const User*>();
util::Map<std::string, const User*> readOnlyUserList;
for (int iterator = 0; iterator < listOfUsers.getSize(); iterator++)
{
readOnlyUserList.insert(listOfUsers.getKeyAt(iterator), listOfUsers.getValueAt(iterator));
}
return readOnlyUserList;
} }
/*
Function: getUsers
Description: Retrieves users filtered by user type.
Parameters:
- userType: util::UserType, type of user (CUSTOMER, TECHNICIAN, ADMIN)
Returns:
- util::Map<std::string, const User*> containing users of the specified type
*/
util::Map<std::string, const User*> Controller::getUsers(util::UserType userType) util::Map<std::string, const User*> Controller::getUsers(util::UserType userType)
{ {
auto userMap = m_userManagementService.getUsers(userType); return util::Map<std::string, const User*>();
util::Map<std::string, const User*> readOnlyUserMap;
for (int iterator = 0; iterator < userMap.getSize(); iterator++)
{
readOnlyUserMap.insert(userMap.getKeyAt(iterator), userMap.getValueAt(iterator));
}
return readOnlyUserMap;
} }
/*
Function: createJobCard
Description: Creates a job card for a service booking assigned to a technician.
Parameters:
- bookingID: std::string, ID of the service booking
- technicianID: std::string, ID of the technician
- serviceID: std::string, ID of the service
Returns:
- void
*/
void Controller::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID) void Controller::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID)
{ {
m_serviceManagementService.createJobCard(bookingID, technicianID, serviceID);
} }
/*
Function: createService
Description: Creates a new service with associated inventory items and labor cost.
Parameters:
- name: std::string, name of the service
- inventoryItemIDs: Vector of inventory item IDs
- laborCost: double, labor cost
Returns:
- void
*/
void Controller::createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost) void Controller::createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost)
{ {
m_serviceManagementService.createService(name, inventoryItemIDs, laborCost);
} }
/*
Function: removeService
Description: Removes a service from the system by ID.
Parameters:
- serviceID: std::string, ID of the service
Returns:
- void
*/
void Controller::removeService(const std::string& serviceID) void Controller::removeService(const std::string& serviceID)
{ {
m_serviceManagementService.removeService(serviceID);
} }
/*
Function: getJobCardsByUser
Description: Retrieves job cards assigned to the authenticated technician.
Parameters:
- None
Returns:
- util::Map<std::string, const JobCard*> containing job cards
*/
util::Map<std::string, const JobCard*> Controller::getJobCardsByUser() util::Map<std::string, const JobCard*> Controller::getJobCardsByUser()
{ {
const User* currentUser = getAuthenticatedUser(); return util::Map<std::string, const JobCard*>();
auto jobCardsAssignedToTechnician = m_serviceManagementService.getJobCards(currentUser->getId());
util::Map<std::string, const JobCard*> readOnlyJobCardMap;
for (int iterator = 0; iterator < jobCardsAssignedToTechnician.getSize(); iterator++)
{
JobCard* currentJobCard = jobCardsAssignedToTechnician.getValueAt(iterator);
readOnlyJobCardMap.insert(currentJobCard->getId(), currentJobCard);
}
return readOnlyJobCardMap;
} }
/* void Controller::completeJob(const std::string& jobID)
Function: completeJob
Description: Marks a job card as completed.
Parameters:
- jobID: std::string, ID of the job card
Returns:
- void
*/
void Controller::updateJobStatus(const std::string& jobID)
{ {
m_serviceManagementService.updateJobStatus(jobID);
} }
/*
Function: removeUser
Description: Removes a user by ID. Cancels associated service bookings
and technician jobs before removing the user from the system.
Parameter: const std::string& userID - ID of the user to remove
Return type: void
*/
void Controller::removeUser(const std::string& userID) void Controller::removeUser(const std::string& userID)
{ {
User* user = m_userManagementService.getUser(userID);
if (!user)
{
throw std::runtime_error("Error: User not Found.\n");
}
m_userManagementService.removeUser(userID);
} }
/*
Function: createComboPackage
Description: Creates a new combo package with specified services and discount
percentage by delegating to the service management service.
Parameter: const std::string& name - name of the combo package
const util::Vector<std::string>& serviceIDs - list of service IDs
double discountPercentage - discount percentage for the package
Return type: void
*/
void Controller::createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage) void Controller::createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage)
{ {
m_serviceManagementService.createComboPackage(name, serviceIDs, discountPercentage);
} }
/*
Function: removeComboPackage
Description: Removes a combo package by ID by delegating to the service
management service.
Parameter: const std::string& comboPackageID - ID of the combo package
Return type: void
*/
void Controller::removeComboPackage(const std::string& comboPackageID) void Controller::removeComboPackage(const std::string& comboPackageID)
{ {
m_serviceManagementService.removeComboPackage(comboPackageID);
} }
/*
Function: getInvoicesByUser
Description: Retrieves all invoices associated with the currently authenticated user.
Converts them into a read-only map before returning.
Parameters:
- None
Returns:
- util::Map<std::string, const Invoice*> containing the users invoices
*/
util::Map<std::string, const Invoice*> Controller::getInvoicesByUser() util::Map<std::string, const Invoice*> Controller::getInvoicesByUser()
{ {
User* currentUser = m_authenticationManagementService.getAuthenticatedUser(); return util::Map<std::string, const Invoice*>();
util::Map<std::string, Invoice*> currentUserInvoices = m_paymentManagementService.getInvoices(currentUser->getId());
util::Map<std::string, const Invoice*> userInvoicesReadOnly;
for (int iterator = 0; iterator < currentUserInvoices.getSize(); iterator++)
{
Invoice* currentInvoice = currentUserInvoices.getValueAt(iterator);
userInvoicesReadOnly.insert(currentInvoice->getId(), currentInvoice);
}
return userInvoicesReadOnly;
} }
/*
Function: getAllInvoices
Description: Retrieves all invoices from the PaymentManagementService and returns them as a read-only map.
Parameters:
- none
Returns:
- util::Map<std::string, const Invoice*>: Map of invoice IDs to invoice objects
*/
util::Map<std::string, const Invoice*> Controller::getAllInvoices()
{
auto invoices = m_paymentManagementService.getAllInvoices();
util::Map<std::string, const Invoice*> readOnlyInvoice;
for (int iterator = 0; iterator < invoices.getSize(); iterator++)
{
readOnlyInvoice.insert(invoices.getKeyAt(iterator), invoices.getValueAt(iterator));
}
return readOnlyInvoice;
}
/*
Function: confirmPayment
Description: Delegates payment confirmation for a given invoice ID to the PaymentManagementService.
Parameters:
- invoiceID: std::string, ID of the invoice to confirm
Returns:
- void
*/
void Controller::confirmPayment(const std::string& invoiceID)
{
m_paymentManagementService.confirmPayment(invoiceID);
}
/*
Function: completePayment
Description: Completes payment for a specific invoice using the given payment mode.
Parameters:
- invoiceID: std::string, ID of the invoice to be paid
- paymentMode: util::PaymentMode, mode of payment (e.g., ONLINE, OFFLINE)
Returns:
- void
*/
void Controller::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode) void Controller::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode)
{ {
m_paymentManagementService.completePayment(invoiceID, paymentMode);
} }
/* /*
@@ -588,37 +289,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();
}
@@ -1,12 +1,11 @@
/* /*
File: Controller.h File: Controller.h
Description: Header file declaring the Controller class, which manages Description: Header file declaring the Controller class, which coordinates
user authentication, inventory, services, bookings, job cards, authentication, user management, service management, inventory,
invoices, and notifications in the system. and notifications across the Vehicle Service System.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "AuthenticationManagementService.h" #include "AuthenticationManagementService.h"
@@ -16,6 +15,10 @@ Date:19-May-2026
#include "PaymentManagementService.h" #include "PaymentManagementService.h"
#include "ServiceManagementService.h" #include "ServiceManagementService.h"
#include "UserManagementService.h" #include "UserManagementService.h"
#include "InventoryManagementService.h"
#include "UserManagementService.h"
#include "ServiceManagementService.h"
#include "PaymentManagementService.h"
class Service; class Service;
class ComboPackage; class ComboPackage;
@@ -29,9 +32,9 @@ class Notification;
class Controller class Controller
{ {
private: private:
AuthenticationManagementService m_authenticationManagementService; AuthenticationManagementService m_authenticationManagementService;
UserManagementService m_userManagementService; UserManagementService m_userManagementService;
ServiceManagementService m_serviceManagementService; ServiceManagementService m_serviceManagementService;
InventoryManagementService m_inventoryManagementService; InventoryManagementService m_inventoryManagementService;
PaymentManagementService m_paymentManagementService; PaymentManagementService m_paymentManagementService;
public: public:
@@ -40,7 +43,7 @@ public:
void changePassword(const std::string& newPassword); void changePassword(const std::string& newPassword);
void createCustomer(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone); void createCustomer(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone);
const User* getAuthenticatedUser(); const User* getAuthenticatedUser();
void createTechnician(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone); void createTechnician(const std::string& username, const std::string& password, const std::string& email, const std::string& phone);
void updateUserDetails(const std::string& email, const std::string& phone); void updateUserDetails(const std::string& email, const std::string& phone);
util::Map<std::string, const Service*> getServices(); util::Map<std::string, const Service*> getServices();
util::Map<std::string, const ComboPackage*> getComboPackages(); util::Map<std::string, const ComboPackage*> getComboPackages();
@@ -49,7 +52,6 @@ public:
util::Map<std::string, const InventoryItem*> getInventoryItems(); util::Map<std::string, const InventoryItem*> getInventoryItems();
const InventoryItem* getInventoryItem(const std::string& inventoryItemID); const InventoryItem* getInventoryItem(const std::string& inventoryItemID);
void addInventoryItem(const std::string& partName, int quantity, double price); void addInventoryItem(const std::string& partName, int quantity, double price);
void addInventoryItemStock(const std::string& selectedItemId, int quantity);
void removeInventoryItem(const std::string& inventoryItemID); void removeInventoryItem(const std::string& inventoryItemID);
util::Map<std::string, const ServiceBooking*> getServiceBookings(); util::Map<std::string, const ServiceBooking*> getServiceBookings();
util::Map<std::string, const ServiceBooking*> getServiceBookingsByUser(const std::string userID); util::Map<std::string, const ServiceBooking*> getServiceBookingsByUser(const std::string userID);
@@ -59,17 +61,16 @@ public:
void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost); void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID); void removeService(const std::string& serviceID);
util::Map<std::string, const JobCard*> getJobCardsByUser(); util::Map<std::string, const JobCard*> getJobCardsByUser();
void updateJobStatus(const std::string& jobID); void completeJob(const std::string& jobID);
void removeUser(const std::string& userID); void removeUser(const std::string& userID);
void createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage); void createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage);
void removeComboPackage(const std::string& comboPackageID); void removeComboPackage(const std::string& comboPackageID);
util::Map<std::string, const Invoice*> getInvoicesByUser(); util::Map<std::string, const Invoice*> getInvoicesByUser();
util::Map<std::string, const Invoice*> getAllInvoices();
void confirmPayment(const std::string& invoiceID);
void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode); void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode);
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();
}; };
@@ -9,200 +9,6 @@ Date: 19-May-2026
*/ */
#include "DataStore.h" #include "DataStore.h"
#include "Config.h"
#include "SerializedRecords.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() :
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
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;
}
if (!lockDataStore())
{
CloseHandle(m_globalMutex);
m_globalMutex = NULL;
return false;
}
bool success = true;
do
{
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))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_notifications))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_services))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_comboPackages))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_inventoryItems))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_serviceBookings))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_jobCards))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_invoices))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_payments))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_serviceManagementObservers))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_paymentManagementObservers))
{
success = false;
break;
}
if (!SharedMemory::createOrOpenMapping(m_inventoryManagementObservers))
{
success = false;
break;
}
} while (false);
unlockDataStore();
if (!success)
{
shutdown();
}
return success;
}
/*
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
@@ -220,367 +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()
{ {
auto users = loadRecords<User, SerializedUser>(m_users); return m_users;
refreshCache(m_userCache, users);
auto& notifications = getNotifications();
int numberOfNotifications = m_notificationCache.getSize();
for (int index = 0; index < numberOfNotifications; index++)
{
Notification* notification = notifications.getValueAt(index).data;
const std::string& recipientUserId = notification->getRecipientUserId();
int userIndex = m_userCache.find(recipientUserId);
if (userIndex == -1)
{
throw std::runtime_error("Invalid recipient user ID");
}
User* user = m_userCache.getValueAt(userIndex).data;
user->addNotification(notification);
}
return m_userCache;
}
/*
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()
{
auto notifications = loadRecords<Notification, SerializedNotification>(m_notifications);
refreshCache(m_notificationCache, notifications);
return m_notificationCache;
} }
/* /*
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 m_serviceCache; 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 m_comboPackageCache; 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 m_inventoryItemCache;
} }
/* /*
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 m_serviceBookingCache; 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 m_jobCardCache; 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 m_invoiceCache; return m_invoices;
} }
/* /*
Function: getServiceManagementObservers Function: getPayments
Description: Retrieves all service management observer records from the datastore. Description: Retrieves the internal map of payments.
Parameters: Parameters:
- None - None
Returns: Returns:
- util::Map<std::string, User*>: Collection of observer records - Reference to util::Map<std::string, Payment*> containing all payments.
*/ */
util::Map<std::string, User*> DataStore::getServiceManagementObservers() util::Map<std::string, Payment*>& DataStore::getPayments()
{ {
return util::Map<std::string, User*>(); return m_payments;
} }
/*
Function: getPaymentManagementObservers
Description: Retrieves all payment management observer records from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, User*>: Collection of observer records
*/
util::Map<std::string, User*> DataStore::getPaymentManagementObservers()
{
return util::Map<std::string, User*>();
}
/*
Function: getInventoryManagementObservers
Description: Retrieves all inventory management observer records from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, User*>: Collection of observer records
*/
util::Map<std::string, User*> DataStore::getInventoryManagementObservers()
{
return util::Map<std::string, User*>();
}
/*
Function: saveUsers
Description: Persists all user records to the datastore.
Parameters:
- None
Returns:
- None
*/
void DataStore::saveUsers()
{
saveRecords<User, SerializedUser>(m_users, m_userCache);
saveNotifications();
}
/*
Function: saveNotifications
Description: Persists all notification records to the datastore.
Parameters:
- None
Returns:
- None
*/
void DataStore::saveNotifications()
{
saveRecords<Notification, SerializedNotification>(m_notifications, m_notificationCache);
}
/*
Function: saveServices
Description: Persists all service records to the datastore.
Parameters:
- None
Returns:
- None
*/
void DataStore::saveServices()
{
}
/*
Function: saveComboPackages
Description: Persists all combo package records to the datastore.
Parameters:
- None
Returns:
- None
*/
void DataStore::saveComboPackages()
{
}
/*
Function: saveInventoryItems
Description: Persists all inventory item records to the datastore.
Parameters:
- None
Returns:
- None
*/
void DataStore::saveInventoryItems()
{
}
/*
Function: saveServiceBookings
Description: Persists all service booking records to the datastore.
Parameters:
- None
Returns:
- None
*/
void DataStore::saveServiceBookings()
{
}
/*
Function: saveJobCards
Description: Persists all job card records to the datastore.
Parameters:
- None
Returns:
- None
*/
void DataStore::saveJobCards()
{
}
/*
Function: saveInvoices
Description: Persists all invoice records to the datastore.
Parameters:
- None
Returns:
- None
*/
void DataStore::saveInvoices()
{
}
/*
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, User*>& observers)
{
}
/*
Function: savePaymentManagementObservers
Description: Persists all payment management observer records to the datastore.
Parameters:
- observers: util::Map<std::string, User*>&, collection of observer records
Returns:
- None
*/
void DataStore::savePaymentManagementObservers(util::Map<std::string, User*>& observers)
{
}
/*
Function: saveInventoryManagementObservers
Description: Persists all inventory management observer records to the datastore.
Parameters:
- observers: util::Map<std::string, User*>&, collection of observer records
Returns:
- None
*/
void DataStore::saveInventoryManagementObservers(util::Map<std::string, User*>& 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,232 +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 DataStore class DataStore
{ {
private: private:
DataStore(); util::Map<std::string, User*> m_users;
~DataStore(); 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;
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:
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, User*> getServiceManagementObservers();
util::Map<std::string, User*> getPaymentManagementObservers();
util::Map<std::string, User*> getInventoryManagementObservers();
void saveUsers();
void saveNotifications();
void saveServices();
void saveComboPackages();
void saveInventoryItems();
void saveServiceBookings();
void saveJobCards();
void saveInvoices();
void saveServiceManagementObservers(util::Map<std::string, User*>& observers);
void savePaymentManagementObservers(util::Map<std::string, User*>& observers);
void saveInventoryManagementObservers(util::Map<std::string, User*>& 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);
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);
};
/*
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.
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);
record.slotIndex = recordCount;
}
record.state = RecordState::CLEAN;
}
}
/*
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;
cache.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);
if (cache.find(id) == -1)
{
delete oldCache.getValueAt(index).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;
};
@@ -1,17 +0,0 @@
/*
File: FileHeader.h
Description: Defines the FileHeader structure used to store
metadata for binary record files, including
record count and capacity.
Author: Trenser
Created: 10-June-2026
*/
#pragma once
#include <cstddef>
struct FileHeader
{
size_t recordCount;
size_t capacity;
};
@@ -1,29 +0,0 @@
/*
File: MappingInfo.h
Description: Defines the MappingInfo structure used for
managing Windows file mapping operations.
Stores handles, mapped view pointer,
file metadata, and capacity information.
Author: Trenser
Created: 10-June-2026
*/
#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,17 +0,0 @@
/*
File: RecordState.h
Description: Defines the RecordState enumeration used to
represent the state of a record in storage.
States include CLEAN, NEW_RECORD, and MODIFIED.
Author: Trenser
Created: 10-June-2026
*/
#pragma once
enum class RecordState : int
{
CLEAN,
NEW_RECORD,
MODIFIED
};
@@ -1,109 +0,0 @@
/*
File: SerializedRecords.h
Description: Defines serialized structures for persistent storage
and retrieval of system entities including User,
Notification, Service, ComboPackage, InventoryItem,
ServiceBooking, JobCard, Invoice, and Observer.
These structures use fixed-size character arrays
and primitive types for binary serialization.
Author: Trenser
Created: 10-June-2026
*/
#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,386 +0,0 @@
/*
File: SharedMemory.cpp
Description: Implements shared memory utilities for managing
Windows file mapping operations. Provides functions
to create, open, resize, and close mappings, as well
as access headers, records, and ensure synchronization
across processes.
Author: Trenser
Created: 11-June-2026
*/
#include "SharedMemory.h"
#include "Windows.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,29 +0,0 @@
/*
File: SharedMemory.h
Description: Declares functions for managing Windows file
mapping and shared memory operations. Provides
utilities for creating, resizing, and closing
mappings, as well as accessing headers and
record data.
Author: Trenser
Created: 10-June-2026
*/
#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,33 +0,0 @@
/*
File: TrackedRecord.h
Description: Defines the TrackedRecord template structure used
to manage objects with associated record state and
slot index. Supports tracking of CLEAN, NEW_RECORD,
and MODIFIED states for persistence and synchronization.
Author: Trenser
Created: 10-June-2026
*/
#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) {}
};
@@ -0,0 +1 @@
Place files here.
@@ -58,8 +58,8 @@ Invoice::Invoice(
const std::string& bookingId, const std::string& bookingId,
ServiceBooking* booking, ServiceBooking* booking,
const util::Timestamp& invoiceDate, const util::Timestamp& invoiceDate,
double laborCost, double laborCost, const util::Map<std::string,
const util::Map<std::string, InventoryItem*>& parts, InventoryItem*>& parts,
double partsCost, double partsCost,
double discountPercentage, double discountPercentage,
double totalAmount, double totalAmount,
@@ -87,6 +87,7 @@ Invoice::Invoice(
m_partIDs.push_back(partPointers[index]->getId()); m_partIDs.push_back(partPointers[index]->getId());
} }
} }
Invoice::Invoice( Invoice::Invoice(
const std::string& id, const std::string& id,
const std::string& bookingId, const std::string& bookingId,
@@ -40,8 +40,8 @@ public:
const std::string& bookingId, const std::string& bookingId,
ServiceBooking* booking, ServiceBooking* booking,
const util::Timestamp& invoiceDate, const util::Timestamp& invoiceDate,
double laborCost, double laborCost, const util::Map<std::string,
const util::Map<std::string,InventoryItem*>& parts, InventoryItem*>& parts,
double partsCost, double partsCost,
double discountPercentage, double discountPercentage,
double totalAmount, double totalAmount,
@@ -1,10 +1,10 @@
/* /*
File: JobCard.cpp File: JobCard.cpp
Description: Implementation file containing the method definitions of the Description: Implements the JobCard class which represents a technicians job assignment in the Vehicle Service Management System.
JobCard class, including constructors, getters, and setters Provides constructors, accessors, and mutators for job details such as ID, booking, service, technician,
for job card attributes. assigned date, completion date, and job status.
Author: Trenser Author: Trenser
Date:19-May-2026 Date: 19-May-2026
*/ */
#include <sstream> #include <sstream>
@@ -18,10 +18,12 @@ int JobCard::m_uid = 0;
/* /*
Function: JobCard Function: JobCard
Description: Default constructor that initializes a new job card with Description: Default constructor that initializes a new job card with a unique ID,
a unique ID and default values. null booking, null service, null technician, and default job status.
Parameter: None Parameters:
Return type: Constructor - None
Returns:
- A new JobCard object.
*/ */
JobCard::JobCard() JobCard::JobCard()
: m_id("JC" + std::to_string(++m_uid)), : m_id("JC" + std::to_string(++m_uid)),
@@ -1,16 +1,15 @@
/* /*
File: JobCard.h File: JobCard.h
Description: Header file declaring the JobCard class, which represents Description: Declares the JobCard class which represents a technicians job assignment in the Vehicle Service Management System.
a service job card containing booking, service, technician, Each job card includes booking details, associated service, technician information, assigned and completion dates, and job status.
and status details.
Author: Trenser Author: Trenser
Date:19-May-2026 Date: 19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "Enums.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "Enums.h"
class ServiceBooking; class ServiceBooking;
class Service; class Service;
@@ -30,6 +29,7 @@ private:
util::Timestamp m_assignedDate; util::Timestamp m_assignedDate;
util::ServiceJobStatus m_status; util::ServiceJobStatus m_status;
util::Timestamp m_completionDate; util::Timestamp m_completionDate;
public: public:
JobCard(); JobCard();
JobCard(const std::string& bookingId, JobCard(const std::string& bookingId,
@@ -24,10 +24,9 @@ Parameters: None
Returns: A new ServiceBooking object. Returns: A new ServiceBooking object.
*/ */
ServiceBooking::ServiceBooking() ServiceBooking::ServiceBooking()
: m_id("SBK" + std::to_string(++m_uid)), : m_id("SRV" + std::to_string(++m_uid)),
m_customer(nullptr), m_customer(nullptr),
m_assignedTechnician(nullptr), m_assignedTechnician(nullptr),
m_status(util::ServiceJobStatus::PENDING),
m_discountPercentage(0.0) {} m_discountPercentage(0.0) {}
/* /*
@@ -42,6 +41,8 @@ Parameters:
- vehicleNumber: Vehicle registration number. - vehicleNumber: Vehicle registration number.
- vehicleBrand: Brand of the vehicle. - vehicleBrand: Brand of the vehicle.
- vehicleModel: Model of the vehicle. - vehicleModel: Model of the vehicle.
- assignedTechnicianId: ID of the assigned technician.
- assignedTechnician: Name of the assigned technician.
- discountPercentage: Discount applied to the booking. - discountPercentage: Discount applied to the booking.
Returns: Returns:
- A new ServiceBooking object. - A new ServiceBooking object.
@@ -57,7 +58,7 @@ ServiceBooking::ServiceBooking(
const std::string& vehicleModel, const std::string& vehicleModel,
double discountPercentage double discountPercentage
) )
: m_id("SBK" + std::to_string(++m_uid)), : m_id("SRV" + std::to_string(++m_uid)),
m_status(status), m_status(status),
m_services(services), m_services(services),
m_customerId(customerId), m_customerId(customerId),
@@ -160,12 +161,6 @@ const util::Vector<std::string>& ServiceBooking::getServiceIDs() const
return m_serviceIDs; return m_serviceIDs;
} }
/*
Function: getServices
Description: Retrieves the services associated with the booking.
Parameter: None
Return type: const util::Map<std::string, Service*>&
*/
/* /*
Function: getServices Function: getServices
Description: Retrieves the services associated with the booking. Description: Retrieves the services associated with the booking.
@@ -42,6 +42,8 @@ public:
const std::string& vehicleNumber, const std::string& vehicleNumber,
const std::string& vehicleBrand, const std::string& vehicleBrand,
const std::string& vehicleModel, const std::string& vehicleModel,
const std::string& assignedTechnicianId,
User* assignedTechnician,
double discountPercentage double discountPercentage
); );
ServiceBooking( ServiceBooking(
@@ -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"
@@ -29,8 +28,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 +51,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)
@@ -327,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();
}; };
@@ -1,12 +1,11 @@
/* /*
File: AuthenticationManagementService.cpp File: AuthenticationManagementService.cpp
Description: Implementation file containing the method definitions of the Description: Implementation file containing the method definitions of the
AuthenticationManagementService class, including logout and AuthenticationManagementService class, including login, logout,
password change logic. password change, and retrieval of the authenticated user.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <stdexcept> #include <stdexcept>
#include "AuthenticationManagementService.h" #include "AuthenticationManagementService.h"
#include "User.h" #include "User.h"
@@ -6,7 +6,6 @@ Description: Header file declaring the AuthenticationManagementService class, wh
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "DataStore.h" #include "DataStore.h"
@@ -7,7 +7,6 @@ Description: Implements the InventoryManagementService class, which manages inve
Author: Trenser Author: Trenser
Date: 22-May-2026 Date: 22-May-2026
*/ */
#include <stdexcept> #include <stdexcept>
#include "Config.h" #include "Config.h"
#include "Enums.h" #include "Enums.h"
@@ -20,49 +19,75 @@ Date: 22-May-2026
#include "Utility.h" #include "Utility.h"
#include "Vector.h" #include "Vector.h"
util::Map<std::string, User*> InventoryManagementService::m_observers{}; util::Map<std::string, User*> InventoryManagementService::m_observers{};
/* void InventoryManagementService::attach(User* user)
Function: sendLowStockAlertsToAdmins (static helper) {
Description: Sends low stock alert notifications to all admin users for a given inventory item. if (user)
Parameters: {
- inventoryManagementService: InventoryManagementService&, service used to send notifications const std::string& userID = user->getId();
- inventoryItem: const InventoryItem*, pointer to the low-stock inventory item if (m_observers.find(userID) == -1)
- adminUsers: const util::Vector<User*>&, list of admin users to notify {
Returns: m_observers[userID] = user;
- None }
*/ }
}
void InventoryManagementService::detach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) != -1)
{
m_observers.remove(userID);
}
}
}
void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{
if (user)
{
if (m_observers.find(user->getId()) != -1)
{
Notification* notification =
Factory::getObject<Notification>(
user->getId(),
user,
"InventoryManagementService: " + title,
message,
util::Timestamp()
);
if (notification)
{
user->addNotification(notification);
}
else
{
throw std::runtime_error("Failed to create notification");
}
}
}
}
static void sendLowStockAlertsToAdmins(InventoryManagementService& inventoryManagementService, const InventoryItem* inventoryItem, const util::Vector<User*>& adminUsers) static void sendLowStockAlertsToAdmins(InventoryManagementService& inventoryManagementService, const InventoryItem* inventoryItem, const util::Vector<User*>& adminUsers)
{ {
int adminUsersSize = adminUsers.getSize(); int adminUsersSize = adminUsers.getSize();
for (int index = 0; index < adminUsersSize; index++) for (int index = 0; index < adminUsersSize; index++)
{ {
std::string title = "Low Stock Alert";
std::string message = "The inventory item with ID " + inventoryItem->getId() + " has very low quantity in the inventory";
inventoryManagementService.sendNotification( inventoryManagementService.sendNotification(
adminUsers[index], adminUsers[index],
title, "Low Stock Alert",
message "The inventory item with ID " + inventoryItem->getId() +
); " has very low quantity in the inventory"
);
} }
} }
/*
Function: sendLowStockAlerts
Description: Sends alerts to user for inventory items with low stock
Parameters:
- None
Returns:
- None
*/
void InventoryManagementService::sendLowStockAlerts() void InventoryManagementService::sendLowStockAlerts()
{ {
auto& inventoryItems = m_dataStore.getInventoryItems(); auto& inventoryItems = m_dataStore.getInventoryItems();
if (inventoryItems.isEmpty())
{
return;
}
int inventoryItemsSize = inventoryItems.getSize(); int inventoryItemsSize = inventoryItems.getSize();
auto& usersMap = m_dataStore.getUsers(); auto& usersMap = m_dataStore.getUsers();
int usersMapSize = usersMap.getSize(); int usersMapSize = usersMap.getSize();
@@ -80,7 +105,7 @@ void InventoryManagementService::sendLowStockAlerts()
{ {
throw std::runtime_error("The system has no admins present!"); throw std::runtime_error("The system has no admins present!");
} }
for (int index = 0; index < inventoryItemsSize; index++) for (int index = 0; index <= inventoryItemsSize; index++)
{ {
InventoryItem* inventoryItem = inventoryItems.getValueAt(index); InventoryItem* inventoryItem = inventoryItems.getValueAt(index);
if (inventoryItem && inventoryItem->getQuantity() < config::threshold::INVENTORY_LOW_STOCK_THRESHOLD) if (inventoryItem && inventoryItem->getQuantity() < config::threshold::INVENTORY_LOW_STOCK_THRESHOLD)
@@ -90,6 +115,7 @@ void InventoryManagementService::sendLowStockAlerts()
} }
} }
/* /*
Function: getObserverIDs Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the Description: Retrieves the IDs of all observers currently attached to the
@@ -177,165 +203,4 @@ Returns:
void InventoryManagementService::saveObservers() void InventoryManagementService::saveObservers()
{ {
util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this); util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this);
} }
/*
Function: addInventoryItem
Description: Creates a new inventory item using the Factory and inserts it
into the DataStore.
Parameter: const std::string& partName - name of the part
int quantity - initial quantity of the part
double price - price of the part
Return type: void
*/
void InventoryManagementService::addInventoryItem(const std::string& partName, int quantity, double price)
{
InventoryItem* newItem = Factory::getObject<InventoryItem>(partName, quantity, price);
m_dataStore.getInventoryItems().insert(newItem->getId(), newItem);
}
/*
Function: addInventoryItemStock
Description: Increases the stock quantity of an existing inventory item.
Parameter: const std::string& selectedItemId - ID of the inventory item
int quantity - quantity to add
Return type: void
*/
void InventoryManagementService::addInventoryItemStock(const std::string& selectedItemId, int quantity)
{
int index = m_dataStore.getInventoryItems().find(selectedItemId);
if (index != -1)
{
InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index);
if (item != nullptr)
{
int totalQuantity = item->getQuantity() + quantity;
item->setQuantity(totalQuantity);
}
}
}
/*
Function: getInventoryItems
Description: Retrieves all inventory items stored in the DataStore.
Parameter: None
Return type: util::Map<std::string, InventoryItem*>
*/
util::Map<std::string, InventoryItem*> InventoryManagementService::getInventoryItems()
{
return m_dataStore.getInventoryItems();
}
/*
Function: removeInventoryItem
Description: Marks an inventory item as inactive instead of deleting it.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: void
*/
void InventoryManagementService::removeInventoryItem(const std::string& inventoryItemID)
{
int index = m_dataStore.getInventoryItems().find(inventoryItemID);
if (index != -1)
{
InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index);
if (item != nullptr)
{
item->setState(util::State::INACTIVE);
}
}
}
/*
Function: getInventoryItem
Description: Retrieves a specific inventory item by its ID from the DataStore.
Parameter: const std::string& inventoryItemID - ID of the inventory item
Return type: InventoryItem*
*/
InventoryItem* InventoryManagementService::getInventoryItem(const std::string& inventoryItemID)
{
int index = m_dataStore.getInventoryItems().find(inventoryItemID);
if (index != -1)
{
return m_dataStore.getInventoryItems().getValueAt(index);
}
return nullptr;
}
/*
Function: attach
Description: Adds a user to the observer list for receiving inventory notifications.
Parameters:
- user: User*, pointer to the user to be attached as an observer
Returns:
- None
*/
void InventoryManagementService::attach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) == -1)
{
m_observers[userID] = user;
}
}
}
/*
Function: detach
Description: Removes a user from the observer list so they no longer receive inventory notifications.
Parameters:
- user: User*, pointer to the user to be detached from the observer list
Returns:
- None
*/
void InventoryManagementService::detach(User* user)
{
if (user)
{
const std::string& userID = user->getId();
if (m_observers.find(userID) != -1)
{
m_observers.remove(userID);
}
}
}
/*
Function: sendNotification
Description: Sends a notification to a user if they are subscribed as an observer.
Parameters:
- user: User*, pointer to the user receiving the notification
- title: std::string, title of the notification
- message: std::string, body/content of the notification
Returns:
- None
Throws:
- std::runtime_error if notification creation fails
*/
void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
{
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");
}
}
}
}
@@ -1,10 +1,9 @@
/* /*
File: InventoryManagementService.h File: InventoryManagementService.h
Description: Header file declaring the InventoryManagementService class, Description: Declares the InventoryManagementService class which manages inventory operations in the Vehicle Service Management System.
which manages inventory items, stock updates, and notifications Provides functionality to retrieve, add, and remove inventory items, send low stock alerts, and handle notifications using the Observer pattern.
related to low stock alerts. Inherits from NotificationManagementService.
Author: Trenser Author: Trenser
Date:19-May-2026 Date: 19-May-2026
*/ */
#pragma once #pragma once
@@ -28,7 +27,6 @@ public:
InventoryItem* getInventoryItem(const std::string& inventoryItemID); InventoryItem* getInventoryItem(const std::string& inventoryItemID);
void addInventoryItem(const std::string& partName, int quantity, double price); void addInventoryItem(const std::string& partName, int quantity, double price);
void removeInventoryItem(const std::string& inventoryItemID); void removeInventoryItem(const std::string& inventoryItemID);
void addInventoryItemStock(const std::string& selectedItemId, int quantity);
void sendLowStockAlerts(); void sendLowStockAlerts();
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;
@@ -12,16 +12,14 @@ Date: 20-May-2026
#include "Enums.h" #include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h" #include "FileManager.h"
#include "InventoryItem.h"
#include "Invoice.h" #include "Invoice.h"
#include "JobCard.h"
#include "PaymentManagementService.h" #include "PaymentManagementService.h"
#include "Service.h"
#include "ServiceBooking.h" #include "ServiceBooking.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "User.h" #include "User.h"
#include "Utility.h" #include "Utility.h"
util::Map<std::string, User*> PaymentManagementService::m_observers{}; util::Map<std::string, User*> PaymentManagementService::m_observers{};
/* /*
@@ -86,7 +84,7 @@ void PaymentManagementService::sendNotification(User* user, const std::string& t
Factory::getObject<Notification>( Factory::getObject<Notification>(
user->getId(), user->getId(),
user, user,
title, "PaymentManagementService: " + title,
message, message,
util::Timestamp() util::Timestamp()
); );
@@ -130,9 +128,9 @@ void PaymentManagementService::sendPaymentReminders()
User* customer = serviceBooking->getCustomer(); User* customer = serviceBooking->getCustomer();
if (customer) if (customer)
{ {
std::string title = "Payment Reminder"; sendNotification(customer,
std::string message = "Your payment for Invoice ID " + invoice->getId() + " is still pending. Please complete the payment."; "Payment Reminder",
sendNotification(customer, title, message); "Your payment for Invoice ID " + invoice->getId() + " is still pending.Please complete the payment." + invoice->getId());
} }
} }
} }
@@ -255,177 +253,4 @@ Returns:
void PaymentManagementService::saveObservers() void PaymentManagementService::saveObservers()
{ {
util::saveObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this); util::saveObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this);
}
/*
Function: createInventoryItemsMap (static helper)
Description: Builds a map of inventory items required for a given service and adds them to the bookings inventory map.
Parameters:
- completeInventoryItemMapOfBooking: util::Map<std::string, InventoryItem*>&, map to store inventory items for the booking
- currentService: const Service*, pointer to the current service
Returns:
- void
*/
static void createInventoryItemsMap(util::Map<std::string, InventoryItem*>& completeInventoryItemMapOfBooking, const Service* currentService)
{
auto& currentRequiredInventoryItems = currentService->getRequiredInventoryItems();
for (int iterator = 0; iterator < currentRequiredInventoryItems.getSize(); iterator++)
{
auto& currentRequiredInventoryItem = currentRequiredInventoryItems.getValueAt(iterator);
completeInventoryItemMapOfBooking.insert(currentRequiredInventoryItem->getId(), currentRequiredInventoryItem);
}
}
/*
Function: generateInvoice
Description: Generates an invoice for a completed service booking.
Validates that all job cards are completed, calculates labor and parts cost, applies discount,
and stores the invoice in the datastore.
Parameters:
- booking: ServiceBooking*, pointer to the service booking
Returns:
- void
Throws:
- std::runtime_error if booking is null or job cards are incomplete
*/
void PaymentManagementService::generateInvoice(ServiceBooking* booking)
{
if (!booking)
{
throw std::runtime_error("Invoice generation failed: booking is null.");
}
double totalLaborCost = 0, totalPartsCost = 0, totalServiceCost = 0;
double discountPercentage = booking->getDiscountPercentage();
std::string bookingID = booking->getId();
util::Map<std::string, Service*> servicesInTheBookedService = booking->getServices();
util::Map<std::string, InventoryItem*> completeInventoryItemMapOfBooking;
util::Map<std::string, JobCard*> currentJobCards = m_dataStore.getJobCards();
for (int iterator = 0; iterator < currentJobCards.getSize(); iterator++)
{
JobCard* currentJobCard = currentJobCards.getValueAt(iterator);
util::ServiceJobStatus currentJobCardStatus = currentJobCard->getStatus();
if (currentJobCard->getBookingId() == bookingID && currentJobCardStatus != util::ServiceJobStatus::CANCELLED && currentJobCardStatus != util::ServiceJobStatus::COMPLETED)
{
throw std::runtime_error("Invoice generation failed: Not all job cards are completed for booking '" + bookingID + "'.");
}
}
for (int iterator = 0; iterator < servicesInTheBookedService.getSize(); iterator++)
{
Service* currentService = servicesInTheBookedService.getValueAt(iterator);
if (currentService)
{
createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService);
totalLaborCost += currentService->getLaborCost();
totalPartsCost += util::calculatePartsCost(currentService);
}
}
totalServiceCost = totalLaborCost + totalPartsCost;
totalServiceCost -= (totalServiceCost * (discountPercentage / 100));
Invoice* invoice = Factory::getObject<Invoice>(bookingID, booking, util::Timestamp(), totalLaborCost, completeInventoryItemMapOfBooking, totalPartsCost, discountPercentage, totalServiceCost, util::Timestamp(), util::PaymentMode::NOTSET, util::PaymentStatus::PENDING);
util::Map<std::string, Invoice*>& currentInvoices = m_dataStore.getInvoices();
currentInvoices.insert(invoice->getId(), invoice);
}
/*
Function: getInvoices
Description: Retrieves all invoices associated with a specific customer.
Parameters:
- customerID: std::string, ID of the customer
Returns:
- util::Map<std::string, Invoice*> containing the customers invoices
*/
util::Map<std::string, Invoice*> PaymentManagementService::getInvoices(const std::string& customerID)
{
util::Map<std::string, Invoice*>& currentInvoices = m_dataStore.getInvoices();
util::Map<std::string, Invoice*> currentUserInvoices;
for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
{
Invoice* currentInvoice = currentInvoices.getValueAt(iterator);
if (currentInvoice->getBooking()->getCustomerId() == customerID)
{
currentUserInvoices.insert(currentInvoice->getId(), currentInvoice);
}
}
return currentUserInvoices;
}
/*
Function: completePayment
Description: Completes payment for a specific invoice. Updates payment method, date, and status,
then sends a notification to the customer.
Parameters:
- invoiceID: std::string, ID of the invoice
- paymentMode: util::PaymentMode, mode of payment (e.g., ONLINE, OFFLINE)
Returns:
- void
Throws:
- std::runtime_error if the invoice ID is invalid
*/
void PaymentManagementService::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode)
{
auto& currentInvoices = m_dataStore.getInvoices();
int invoiceIndex = currentInvoices.find(invoiceID);
if (invoiceIndex != -1)
{
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
if (invoice && invoice->getStatus() != util::PaymentStatus::PAID)
{
User* currentUser = invoice->getBooking()->getCustomer();
invoice->setPaymentMethod(paymentMode);
invoice->setPaymentDate(util::Timestamp());
invoice->setStatus(util::PaymentStatus::PAID);
std::string title, message;
title = "Payment successful";
message = "Payment successful for Invoice ID " + invoiceID;
sendNotification(currentUser, title, message);
}
}
else
{
throw std::runtime_error("Payment failed: invalid invoice ID.");
}
}
/*
Function: getAllInvoice
Description: Provides access to all invoices stored in the data store.
Parameters:
- none
Returns:
- util::Map<std::string, Invoice*>&: Map of invoice IDs to invoice objects
*/
util::Map<std::string, Invoice*>& PaymentManagementService::getAllInvoices()
{
return m_dataStore.getInvoices();
}
/*
Function: confirmPayment
Description: Confirms payment for a specific invoice. Updates payment date and status,
then sends a notification to the customer.
Parameters:
- invoiceID: std::string, ID of the invoice to confirm
Returns:
- void
Throws:
- std::runtime_error if the invoice ID is invalid
*/
void PaymentManagementService::confirmPayment(const std::string& invoiceID)
{
auto& currentInvoices = m_dataStore.getInvoices();
int invoiceIndex = currentInvoices.find(invoiceID);
if (invoiceIndex == -1)
{
throw std::runtime_error("Payment confirmation failed: invalid invoice ID.");
}
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
if (!invoice || invoice->getStatus() != util::PaymentStatus::PAID)
{
throw std::runtime_error("Payment confirmation failed: invoice is not awaiting confirmation.");
}
User* currentUser = invoice->getBooking()->getCustomer();
invoice->setStatus(util::PaymentStatus::COMPLETED);
std::string title = "Payment Confirmed";
std::string message = "Payment Confirmed for Invoice ID " + invoiceID;
sendNotification(currentUser, title, message);
} }
@@ -28,8 +28,6 @@ public:
void generateInvoice(ServiceBooking* booking); void generateInvoice(ServiceBooking* booking);
util::Map<std::string, Invoice*> getInvoices(const std::string& customerID); util::Map<std::string, Invoice*> getInvoices(const std::string& customerID);
void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode); void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode);
util::Map<std::string, Invoice*>& getAllInvoices();
void confirmPayment(const std::string& invoiceID);
void sendPaymentReminders(); void sendPaymentReminders();
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;
@@ -11,20 +11,14 @@ Date:19-May-2026
#include "AuthenticationManagementService.h" #include "AuthenticationManagementService.h"
#include "ComboPackage.h" #include "ComboPackage.h"
#include "Config.h" #include "Config.h"
#include "DataStore.h"
#include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h" #include "FileManager.h"
#include "InventoryItem.h"
#include "JobCard.h" #include "JobCard.h"
#include "NotificationManagementService.h"
#include "PaymentManagementService.h"
#include "Service.h" #include "Service.h"
#include "ServiceBooking.h" #include "ServiceBooking.h"
#include "ServiceManagementService.h" #include "ServiceManagementService.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "User.h" #include "User.h"
#include "UserManagementService.h"
#include "Utility.h" #include "Utility.h"
/* /*
@@ -60,15 +54,15 @@ void ServiceManagementService::purchaseService(const util::Vector<std::string>&
Service* service = servicesMap.getValueAt(serviceIndex); Service* service = servicesMap.getValueAt(serviceIndex);
selectedServices[service->getId()] = service; selectedServices[service->getId()] = service;
} }
ServiceBooking* serviceBooking = Factory::getObject<ServiceBooking>(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, 0); ServiceBooking* serviceBooking = Factory::getObject<ServiceBooking>(util::ServiceJobStatus::STARTED, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, 0);
if (serviceBooking == nullptr) if (serviceBooking == nullptr)
{ {
throw std::runtime_error("Failed to create service booking"); throw std::runtime_error("Failed to create service booking");
} }
serviceBookingMap[serviceBooking->getId()] = serviceBooking; serviceBookingMap[serviceBooking->getId()] = serviceBooking;
std::string title = "Service Booking succeeded"; sendNotification(authenticatedUser,
std::string message = "Your service booking has been successfully placed with ID " + serviceBooking->getId(); "Service Booking succeeded",
sendNotification(authenticatedUser, title, message); "Your service booking has been successfully placed with ID " + serviceBooking->getId());
} }
/* /*
@@ -99,15 +93,15 @@ void ServiceManagementService::purchaseComboPackage(const std::string& comboPack
} }
const ComboPackage* comboPackage = comboPackagesMap[comboPackageID]; const ComboPackage* comboPackage = comboPackagesMap[comboPackageID];
util::Map<std::string, Service*> selectedServices = comboPackage->getServices(); util::Map<std::string, Service*> selectedServices = comboPackage->getServices();
ServiceBooking* serviceBooking = Factory::getObject<ServiceBooking>(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, comboPackage->getDiscountPercentage()); ServiceBooking* serviceBooking = Factory::getObject<ServiceBooking>(util::ServiceJobStatus::STARTED, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, comboPackage->getDiscountPercentage());
if (serviceBooking == nullptr) if (serviceBooking == nullptr)
{ {
throw std::runtime_error("Failed to create combo package service booking"); throw std::runtime_error("Failed to create combo package service booking");
} }
serviceBookingMap[serviceBooking->getId()] = serviceBooking; serviceBookingMap[serviceBooking->getId()] = serviceBooking;
std::string title = "Combo Package Service Booking succeeded"; sendNotification(authenticatedUser,
std::string message = "Your service booking for the combo package has been successfully placed with ID " + serviceBooking->getId(); "Combo Package Service Booking succeeded",
sendNotification(authenticatedUser, title, message); "Your service booking for the combo package has been successfully placed with ID " + serviceBooking->getId());
} }
util::Map<std::string, User*> ServiceManagementService::m_observers{}; util::Map<std::string, User*> ServiceManagementService::m_observers{};
@@ -174,7 +168,7 @@ void ServiceManagementService::sendNotification(User* user, const std::string& t
Factory::getObject<Notification>( Factory::getObject<Notification>(
user->getId(), user->getId(),
user, user,
title, "ServiceManagementService: " + title,
message, message,
util::Timestamp() util::Timestamp()
); );
@@ -505,654 +499,4 @@ Returns:
void ServiceManagementService::saveObservers() void ServiceManagementService::saveObservers()
{ {
util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this); util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this);
}
/*
Function: restoreInventory
Description: Restores inventory quantities for all required items in the services associated
with a given booking. Each item's quantity is incremented by a fixed value.
Parameter: ServiceBooking* booking - Pointer to the booking whose inventory items need to be restored
Return type: void
*/
static void restoreInventory(ServiceBooking* booking)
{
const int INCREMENT_VALUE = 1;
if (!booking)
{
return;
}
const auto& services = booking->getServices();
for (int serviceIterator = 0; serviceIterator < services.getSize(); ++serviceIterator)
{
Service* service = services.getValueAt(serviceIterator);
if (!service)
{
continue;
}
const auto& items = service->getRequiredInventoryItems();
for (int InventoryIterator = 0; InventoryIterator < items.getSize(); ++InventoryIterator)
{
InventoryItem* item = items.getValueAt(InventoryIterator);
if (item)
{
item->setQuantity(item->getQuantity() + INCREMENT_VALUE);
}
}
}
}
/*
Function: processBookingCancellation
Description: Handles cancellation or reassignment of a service booking based on user type.
Cancels associated job cards, updates booking status, clears technician assignments,
restores inventory, and sends appropriate notifications.
Parameters:
ServiceBooking* booking - The booking to cancel or reset
util::Map<std::string, JobCard*>& jobs - Collection of job cards to update
ServiceManagementService& currentService - Service layer for notifications
util::UserType userType - Type of user initiating cancellation (CUSTOMER or TECHNICIAN)
Return type: void
*/
static void processBookingCancellation(ServiceBooking* booking,
util::Map<std::string, JobCard*>& jobs,
ServiceManagementService& currentService,
util::UserType userType)
{
if (!booking)
{
return;
}
for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator)
{
JobCard* jobCard = jobs.getValueAt(jobIterator);
if (!jobCard || jobCard->getBookingId() != booking->getId() || jobCard->getStatus() == util::ServiceJobStatus::CANCELLED)
{
continue;
}
jobCard->setStatus(util::ServiceJobStatus::CANCELLED);
if (userType == util::UserType::CUSTOMER)
{
if (User* technician = booking->getAssignedTechnician())
{
const std::string jobTitle = "Job Cancelled";
const std::string jobMessage = "Your job card has been cancelled and the inventory has been restocked.";
currentService.sendNotification(technician, jobTitle, jobMessage);
}
}
}
if (userType == util::UserType::CUSTOMER)
{
booking->setStatus(util::ServiceJobStatus::CANCELLED);
if (User* technician = booking->getAssignedTechnician())
{
const std::string title = "Customer Service Cancelled";
const std::string message = "Your assigned job card has been cancelled and the inventory has been restocked.";
currentService.sendNotification(technician, title, message);
}
}
else if (userType == util::UserType::TECHNICIAN)
{
booking->setStatus(util::ServiceJobStatus::PENDING);
if (User* customer = booking->getCustomer())
{
const std::string title = "Technician Unavailable";
const std::string message = "Your booking has been reset to pending and we will reassign a new technician shortly.";
currentService.sendNotification(customer, title, message);
}
}
booking->setAssignedTechnician(nullptr);
booking->setAssignedTechnicianId("");
restoreInventory(booking);
}
/*
Function: cancelCustomerServiceBookings
Description: Cancels all service bookings associated with a given customer or technician.
Updates booking status, resets customer/technician assignments, sends notifications,
and restocks inventory items.
Parameter: const std::string& userID - ID of the customer or technician
Return type: void
*/
void ServiceManagementService::cancelCustomerServiceBookings(const std::string& customerID)
{
auto& users = m_dataStore.getUsers();
int userIndex = users.find(customerID);
if (userIndex == -1)
{
throw std::runtime_error("User not found: " + customerID);
}
User* customer = users.getValueAt(userIndex);
if (!customer)
{
throw std::runtime_error("User not found: " + customerID);
}
auto& bookings = m_dataStore.getServiceBookings();
auto& jobs = m_dataStore.getJobCards();
for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++)
{
ServiceBooking* booking = bookings.getValueAt(iteratorOne);
if (!booking)
{
continue;
}
if (booking->getCustomerId() != customerID)
{
continue;
}
if (booking->getStatus() != util::ServiceJobStatus::PENDING &&
booking->getStatus() != util::ServiceJobStatus::STARTED &&
booking->getStatus() != util::ServiceJobStatus::IN_PROGRESS)
{
continue;
}
processBookingCancellation(booking, jobs, *this, util::UserType::CUSTOMER);
}
}
/*
Function: cancelTechnicianJobs
Description: Cancels all jobs assigned to a technician. Updates job status, sends notifications,
and restocks inventory items used in the service.
Parameter: const std::string& technicianID - ID of the technician
Return type: void
*/
void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID)
{
auto& users = m_dataStore.getUsers();
int userIndex = users.find(technicianID);
if (userIndex == -1)
{
throw std::runtime_error("User not found: " + technicianID);
}
User* technician = users.getValueAt(userIndex);
if (!technician)
{
throw std::runtime_error("User not found: " + technicianID);
}
auto& bookings = m_dataStore.getServiceBookings();
auto& jobs = m_dataStore.getJobCards();
for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++)
{
ServiceBooking* booking = bookings.getValueAt(iteratorOne);
if (!booking)
{
continue;
}
std::string technicianId = booking->getAssignedTechnicianId();
if (technicianId != technicianID)
{
continue;
}
if (booking->getStatus() != util::ServiceJobStatus::PENDING &&
booking->getStatus() != util::ServiceJobStatus::STARTED &&
booking->getStatus() != util::ServiceJobStatus::IN_PROGRESS)
{
continue;
}
User* customer = booking->getCustomer();
if (!customer)
{
continue;
}
processBookingCancellation(booking, jobs, *this, util::UserType::TECHNICIAN);
}
}
/*
Function: createComboPackage
Description: Creates a new combo package with two services and a discount percentage.
Validates service IDs, ensures uniqueness, and inserts the new package into the DataStore.
Parameter: const std::string& packageName - name of the combo package
const util::Vector<std::string>& serviceIDsInNewCombo - list of service IDs
double discountPercentage - discount percentage for the package
Return type: void
*/
void ServiceManagementService::createComboPackage(const std::string& packageName, const util::Vector<std::string>& serviceIDsInNewCombo, double discountPercentage)
{
if (packageName.empty())
{
throw std::invalid_argument("The Combo Package Name cannot be empty.\n");
}
if (serviceIDsInNewCombo.getSize() < 2 || serviceIDsInNewCombo.getSize() > 2)
{
throw std::invalid_argument("Combo package must contain only two services.");
}
if (discountPercentage < 0.0 || discountPercentage > 100.0)
{
throw std::invalid_argument("Discount percentage must be between 0 and 100.");
}
auto& servicesMap = m_dataStore.getServices();
for (int index = 0; index < serviceIDsInNewCombo.getSize(); index++)
{
const std::string serviceid = serviceIDsInNewCombo[index];
if (servicesMap.find(serviceid) == -1)
{
throw std::runtime_error("Service ID not found: " + serviceid);
}
}
auto& comboPackageMap = m_dataStore.getComboPackages();
for (int iterator = 0; iterator < comboPackageMap.getSize(); iterator++)
{
ComboPackage* existingCombos = comboPackageMap.getValueAt(iterator);
const util::Map<std::string, Service*>& servicesInsideExistingCombos = existingCombos->getServices();
if (servicesInsideExistingCombos.getSize() == serviceIDsInNewCombo.getSize())
{
bool isIdentical = true;
for (int serviceIterator = 0; serviceIterator < serviceIDsInNewCombo.getSize(); serviceIterator++)
{
const std::string& id = serviceIDsInNewCombo[serviceIterator];
if (servicesInsideExistingCombos.find(id) == -1)
{
isIdentical = false;
break;
}
}
if (isIdentical)
{
throw std::runtime_error("A combo package with the same services already exists.");
}
}
}
util::Map<std::string, Service*> selectedServices;
for (int iteratorOne = 0; iteratorOne < serviceIDsInNewCombo.getSize(); iteratorOne++)
{
const std::string& serviceId = serviceIDsInNewCombo[iteratorOne];
int serviceIndex = servicesMap.find(serviceId);
if (serviceIndex == -1)
{
throw std::runtime_error("Service ID not found: " + serviceId);
}
selectedServices.insert(serviceId, servicesMap.getValueAt(serviceIndex));
}
ComboPackage* newComboPackage = Factory::getObject<ComboPackage>(packageName, discountPercentage, selectedServices);
comboPackageMap.insert(newComboPackage->getId(), newComboPackage);
}
/*
Function: getComboPackages
Description: Retrieves all combo packages stored in the DataStore.
Parameter: None
Return type: util::Map<std::string, ComboPackage*>
*/
util::Map<std::string, ComboPackage*> ServiceManagementService::getComboPackages()
{
return m_dataStore.getComboPackages();
}
/*
Function: removeComboPackage
Description: Removes a combo package by marking it inactive. Throws an exception if the package ID is not found.
Parameter: const std::string& comboPackageID - ID of the combo package
Return type: void
*/
void ServiceManagementService::removeComboPackage(const std::string& comboPackageID)
{
bool removed = false;
util::Map<std::string, ComboPackage*>& currentComboPackages = m_dataStore.getComboPackages();
for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++)
{
ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator);
if (currentComboPackage && currentComboPackage->getId() == comboPackageID)
{
currentComboPackage->setState(util::State::INACTIVE);
removed = true;
break;
}
}
if (!removed)
{
throw std::runtime_error("Combo package with ID '" + comboPackageID + "' not found.");
}
}
/*
Function: getServiceBookings
Description: Retrieves all service bookings from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, ServiceBooking*> containing all service bookings
*/
util::Map<std::string, ServiceBooking*> ServiceManagementService::getServiceBookings()
{
return m_dataStore.getServiceBookings();
}
/*
Function: getServiceBooking
Description: Retrieves a specific service booking by its ID.
Parameters:
- serviceID: std::string, ID of the service booking
Returns:
- ServiceBooking*: Pointer to the service booking, or nullptr if not found
*/
ServiceBooking* ServiceManagementService::getServiceBooking(const std::string& serviceID)
{
auto currentServiceBookings = getServiceBookings();
for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++)
{
if (currentServiceBookings.getValueAt(iterator)->getId() == serviceID)
{
return currentServiceBookings.getValueAt(iterator);
}
}
return nullptr;
}
/*
Function: createJobCard
Description: Creates a job card for a given service booking, service, and technician.
Validates booking, service, technician, and inventory availability before creation.
Parameters:
- bookingID: std::string, ID of the service booking
- technicianID: std::string, ID of the technician
- serviceID: std::string, ID of the service
Returns:
- void
Throws:
- std::runtime_error if booking, service, technician, or inventory validation fails
*/
void ServiceManagementService::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID)
{
UserManagementService m_userManagementService;
ServiceBooking* currentBooking = getServiceBooking(bookingID);
auto& currentJobCards = m_dataStore.getJobCards();
if (currentBooking == nullptr)
{
throw std::runtime_error("Service Booking not available");
}
auto& currentServices = currentBooking->getServices();
if (currentServices.find(serviceID) == -1)
{
throw std::runtime_error("Invalid service Id");
}
Service* currentService = currentServices.getValueAt(currentServices.find(serviceID));
User* selectedTechnician = m_userManagementService.getUser(technicianID);
if (selectedTechnician == nullptr)
{
throw std::runtime_error("Technician not available");
}
auto& inventoryItems = currentService->getRequiredInventoryItems();
for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++)
{
InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator);
if (currentInventoryItem && currentInventoryItem->getQuantity() == 0)
{
std::string errorMessage = "Failed to create job card, " + currentInventoryItem->getPartName() + " is out of stock.";
throw std::runtime_error(errorMessage);
}
}
for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++)
{
InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator);
if (currentInventoryItem)
{
int currentStockQuantity = currentInventoryItem->getQuantity();
currentInventoryItem->setQuantity(currentStockQuantity - 1);
}
}
currentBooking->setAssignedTechnician(selectedTechnician);
currentBooking->setAssignedTechnicianId(selectedTechnician->getId());
if (currentBooking->getStatus() == util::ServiceJobStatus::PENDING)
{
currentBooking->setStatus(util::ServiceJobStatus::STARTED);
}
std::string title = "Job card created";
std::string message = "Job card created for the service and you are assigned for that.";
JobCard* jobCard = Factory::getObject<JobCard>(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::Timestamp(), util::ServiceJobStatus::STARTED, util::Timestamp());
if (jobCard)
{
currentJobCards.insert(jobCard->getId(), jobCard);
sendNotification(selectedTechnician, title, message);
}
else
{
throw std::runtime_error("Failed to create job card.");
}
title = "Technician assigned";
message = "A technician has been assigned to your Service Booking with ID " + bookingID;
sendNotification(currentBooking->getCustomer(), title, message);
}
/*
Function: createService
Description: Creates a new service with associated inventory items and labor cost.
Validates inventory items before creation.
Parameters:
- name: std::string, name of the service
- inventoryItemIDs: util::Vector<std::string>, IDs of required inventory items
- laborCost: double, labor cost for the service
Returns:
- void
Throws:
- std::runtime_error if inventory items are not found or service creation fails
*/
void ServiceManagementService::createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost)
{
util::Map<std::string, InventoryItem*> currentServiceInventoryItems;
auto inventoryItems = m_dataStore.getInventoryItems();
for (int iteratorOne =0; iteratorOne < inventoryItemIDs.getSize(); iteratorOne++)
{
std::string currentItemID = inventoryItemIDs[iteratorOne];
bool itemFound = false;
for (int iteratorTwo = 0; iteratorTwo < inventoryItems.getSize(); iteratorTwo++)
{
InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iteratorTwo);
if (currentInventoryItem && currentInventoryItem->getId() == currentItemID)
{
itemFound = true;
currentServiceInventoryItems.insert(currentInventoryItem->getId(), currentInventoryItem);
break;
}
}
if (!itemFound)
{
throw std::runtime_error("Inventory item with ID '" + currentItemID + "' not found.");
}
}
Service* newService = Factory::getObject<Service>(name, currentServiceInventoryItems, laborCost);
if (newService == nullptr)
{
throw std::runtime_error("Unable to create new service.");
}
util::Map<std::string, Service*>& currentServices = m_dataStore.getServices();
if (currentServices.find(newService->getId()) != -1)
{
throw std::runtime_error("Service with this ID Already exists.");
}
currentServices.insert(newService->getId(), newService);
}
/*
Function: getServices
Description: Retrieves all services from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, Service*> containing all services
*/
util::Map<std::string, Service*> ServiceManagementService::getServices()
{
return m_dataStore.getServices();
}
/*
Function: removeService
Description: Marks a service as inactive by its ID.
Parameters:
- serviceID: std::string, ID of the service
Returns:
- void
Throws:
- std::runtime_error if the service is not found
*/
void ServiceManagementService::removeService(const std::string& serviceID)
{
util::Map<std::string, Service*>& currentServices = m_dataStore.getServices();
util::Map<std::string, ComboPackage*>& currentComboPackages = m_dataStore.getComboPackages();
if (currentServices.find(serviceID) != -1)
{
currentServices.getValueAt(currentServices.find(serviceID))->setState(util::State::INACTIVE);
for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++)
{
ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator);
if (currentComboPackage && currentComboPackage->getState() == util::State::ACTIVE)
{
util::Map<std::string, Service*> currentServices = currentComboPackage->getServices();
for (int iterator = 0; iterator < currentServices.getSize(); iterator++)
{
auto currentService = currentServices.getValueAt(iterator);
if (currentService->getId() == serviceID)
{
currentComboPackage->setState(util::State::INACTIVE);
break;
}
}
}
}
}
else
{
throw std::runtime_error("Service not found.");
}
}
/*
Function: getServiceBookings (overloaded)
Description: Retrieves all service bookings for a specific customer.
Parameters:
- customerID: std::string, ID of the customer
Returns:
- util::Map<std::string, ServiceBooking*> containing bookings for the customer
*/
util::Map<std::string, ServiceBooking*> ServiceManagementService::getServiceBookings(const std::string& customerID)
{
util::Map<std::string, ServiceBooking*> currentServiceBookings = getServiceBookings();
util::Map<std::string, ServiceBooking*> currentUserServiceBookings;
if (currentServiceBookings.getSize() != 0)
{
for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++)
{
auto currentServiceBooking = currentServiceBookings.getValueAt(iterator);
if (currentServiceBooking->getCustomerId() == customerID)
{
currentUserServiceBookings.insert(currentServiceBooking->getId(), currentServiceBooking);
}
}
}
return currentUserServiceBookings;
}
/*
Function: getJobCards
Description: Retrieves all job cards assigned to a specific technician.
Parameters:
- technicianID: std::string, ID of the technician
Returns:
- util::Map<std::string, JobCard*> containing job cards assigned to the technician
*/
util::Map<std::string, JobCard*> ServiceManagementService::getJobCards(const std::string& technicianID)
{
util::Map<std::string, JobCard*> jobCards = m_dataStore.getJobCards();
util::Map<std::string, JobCard*> technicianJobCards;
for (int iterator = 0; iterator < jobCards.getSize(); iterator++)
{
JobCard* currentJobCard = jobCards.getValueAt(iterator);
if (currentJobCard->getTechnicianId() == technicianID)
{
technicianJobCards.insert(currentJobCard->getId(), currentJobCard);
}
}
return technicianJobCards;
}
/*
Function: hasCompletedAllJobs (static helper)
Description: Checks if all job cards for a given service booking are completed.
Parameters:
- bookingId: std::string, ID of the service booking
- currentAssignedJobs: util::Map<std::string, JobCard*>&, map of assigned job cards
Returns:
- bool: True if all job cards are completed, False otherwise
*/
static bool hasCompletedAllJobs(std::string bookingId, util::Map<std::string, JobCard*>& currentAssignedJobs)
{
for (int iterator = 0; iterator < currentAssignedJobs.getSize(); iterator++)
{
JobCard* currentJob = currentAssignedJobs.getValueAt(iterator);
if (currentJob->getBookingId() == bookingId)
{
if (currentJob->getStatus() != util::ServiceJobStatus::COMPLETED && currentJob->getStatus() != util::ServiceJobStatus::CANCELLED)
{
return false;
}
}
}
return true;
}
/*
Function: updateJobStatus
Description:
Updates the status of a job card assigned to the currently authenticated technician.
- If the job is STARTED, it moves to IN_PROGRESS.
- If the job is IN_PROGRESS, it moves to COMPLETED.
When all jobs in a service booking are completed, the booking status is updated,
an invoice is generated, and a notification is sent to the customer.
Parameters:
- jobID: const std::string&, unique identifier of the job card to update.
Returns:
- void
*/
void ServiceManagementService::updateJobStatus(const std::string& jobID)
{
AuthenticationManagementService authenticationManagementService;
PaymentManagementService paymentManagementService;
bool jobStatusUpdated = false, serviceBookingCompleted;
JobCard* currentJob;
User* currentTechnician = authenticationManagementService.getAuthenticatedUser();
if (currentTechnician == nullptr)
{
throw std::runtime_error("Unable to fetch current technician.");
}
util::Map<std::string, JobCard*> currentAssignedJobs = getJobCards(currentTechnician->getId());
if (currentAssignedJobs.getSize() == 0)
{
throw std::runtime_error("No job cards assigned to the technician.");
}
if (currentAssignedJobs.find(jobID) != -1)
{
currentJob = currentAssignedJobs.getValueAt(currentAssignedJobs.find(jobID));
if (currentJob == nullptr)
{
throw std::runtime_error("Unable to fetch current job.");
}
if (currentJob->getStatus() == util::ServiceJobStatus::STARTED)
{
currentJob->setStatus(util::ServiceJobStatus::IN_PROGRESS);
jobStatusUpdated = true;
}
else if (currentJob->getStatus() == util::ServiceJobStatus::IN_PROGRESS)
{
currentJob->setStatus(util::ServiceJobStatus::COMPLETED);
jobStatusUpdated = true;
serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs);
if (serviceBookingCompleted)
{
currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED);
paymentManagementService.generateInvoice(currentJob->getBooking());
std::string title = "Service Booking completed. Invoice Generated.";
std::string message = "Services completed for the booking and invoice generated.";
sendNotification(currentJob->getBooking()->getCustomer(), title, message);
}
}
}
else
{
throw std::runtime_error("Failed to update job status. Job may already be completed.");
}
if (!jobStatusUpdated)
{
throw std::runtime_error("Failed to update job status. Job may already be completed.");
}
} }
@@ -6,7 +6,6 @@ Description: Header file declaring the ServiceManagementService class, which man
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"
@@ -32,15 +31,14 @@ public:
void purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel); void purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel);
util::Map<std::string, ServiceBooking*> getServiceBookings(); util::Map<std::string, ServiceBooking*> getServiceBookings();
util::Map<std::string, ServiceBooking*> getServiceBookings(const std::string& customerID); util::Map<std::string, ServiceBooking*> getServiceBookings(const std::string& customerID);
ServiceBooking* getServiceBooking(const std::string& serviceID);
void createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID); void createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID);
void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost); void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID); void removeService(const std::string& serviceID);
util::Map<std::string, JobCard*> getJobCards(const std::string& technicianID); util::Map<std::string, JobCard*> getJobCards(const std::string& technicianID);
void updateJobStatus(const std::string& jobID); void completeJob(const std::string& jobID);
void cancelCustomerServiceBookings(const std::string& customerID); void cancelCustomerServiceBookings(const std::string& customerID);
void cancelTechnicianJobs(const std::string& technicianID); void cancelTechnicianJobs(const std::string& technicianID);
void createComboPackage(const std::string& packageName, const util::Vector<std::string>& serviceIDs, double discountPercentage); void createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage);
void removeComboPackage(const std::string& comboPackageID); void removeComboPackage(const std::string& comboPackageID);
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;
@@ -6,7 +6,6 @@ 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 "Config.h" #include "Config.h"
#include "Enums.h" #include "Enums.h"
@@ -19,10 +18,7 @@ Date:19-May-2026
#include "User.h" #include "User.h"
#include "UserManagementService.h" #include "UserManagementService.h"
#include "Vector.h" #include "Vector.h"
#include "Validator.h"
#include "Utility.h"
#include "TrackedRecord.h"
#include "DataStoreLockGuard.h"
/* /*
Function: ensureAdminExists Function: ensureAdminExists
@@ -34,13 +30,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;
@@ -77,30 +72,25 @@ 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(); int index = usersMap.findIf(
auto usersMap = util::getObjects(trackedUsersMap); [&](const std::string&, User* user)
if (util::isUsernameDuplicate(username, usersMap)) {
return user->getUserName() == username;
}
);
if (index != -1)
{ {
throw std::runtime_error("Username already exists"); throw std::runtime_error("Username already exists");
} }
if (util::isEmailDuplicate(email, usersMap))
{
throw std::runtime_error("Email already exists");
}
if (util::isPhoneDuplicate(phone, usersMap))
{
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();
} }
/* /*
@@ -114,39 +104,15 @@ 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!");
}
User* user = trackedUsersMap.getValueAt(index).data;
bool isModified = false;
if (email != user->getEmail())
{
if (util::isEmailDuplicate(email, usersMap))
{
throw std::runtime_error("Email already exists!\n");
}
user->setEmail(email);
isModified = true;
}
if (phone != user->getPhone())
{
if (util::isPhoneDuplicate(phone, usersMap))
{
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* user = usersMap.getValueAt(index);
user->setEmail(email);
user->setPhone(phone);
} }
/* /*
@@ -161,13 +127,12 @@ 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& notifications = user->getNotifications(); auto& notifications = user->getNotifications();
@@ -187,136 +152,95 @@ 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");
} }
User* user = trackedUsersMap.getValueAt(userIndex).data; User* user = usersMap[userID];
auto& notifications = user->getNotifications(); auto& notifications = user->getNotifications();
if (notifications.find(notificationID) == -1) 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");
} }
int notificationIndex = trackedNotificationsMap.find(notificationID); notifications.remove(notificationID);
if (notificationIndex == -1)
{
throw std::runtime_error("No notification found with given NotificationID");
}
notifications[notificationID]->setState(util::State::INACTIVE);
trackedNotificationsMap.getValueAt(notificationIndex).state = RecordState::MODIFIED;
m_dataStore.saveNotifications();
} }
/* /*
Function: getUsers Function: loadUsers
Description: Retrieves all users stored in the DataStore. Description: Loads users and notifications from persistent storage into the datastore.
Parameter: None Validates that each notifications recipient exists and attaches the
Return type: util::Map<std::string, User*> notification to the corresponding user.
*/
util::Map<std::string, User*> UserManagementService::getUsers()
{
DataStoreLockGuard lock(m_dataStore);
auto users = util::getObjects(m_dataStore.getUsers());
return users;
}
/*
Function: getUser
Description: Retrieves a specific user by ID from the DataStore.
Parameter: const std::string& userID - ID of the user
Return type: User*
*/
User* UserManagementService::getUser(const std::string& userID)
{
DataStoreLockGuard lock(m_dataStore);
auto& trackedUsersMap = m_dataStore.getUsers();
int index = trackedUsersMap.find(userID);
if (index != -1)
{
return trackedUsersMap.getValueAt(index).data;
}
return nullptr;
}
/*
Function: removeUser
Description: Marks a user as inactive in the DataStore instead of deleting them.
Parameter: const std::string& userID - ID of the user to remove
Return type: void
*/
void UserManagementService::removeUser(const std::string& userID)
{
InventoryManagementService inventoryManagementService;
PaymentManagementService paymentManagementService;
ServiceManagementService serviceManagementService;
DataStoreLockGuard lock(m_dataStore);
auto& trackedUsersMap = m_dataStore.getUsers();
int index = trackedUsersMap.find(userID);
if (index != -1)
{
User* user = trackedUsersMap.getValueAt(index).data;
if (user != nullptr)
{
if (user->getUserType() == util::UserType::CUSTOMER)
{
serviceManagementService.cancelCustomerServiceBookings(userID);
}
if (user->getUserType() == util::UserType::TECHNICIAN)
{
serviceManagementService.cancelTechnicianJobs(userID);
}
inventoryManagementService.detach(user);
paymentManagementService.detach(user);
serviceManagementService.detach(user);
user->setState(util::State::INACTIVE);
trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED;
m_dataStore.saveUsers();
}
}
}
/*
Function: getUsers
Description: Retrieves all active users of the specified type from
the DataStore.
Parameters: Parameters:
- type: The user type to filter by - None
(ADMIN, CUSTOMER, or TECHNICIAN).
Returns: Returns:
- util::Map<std::string, User*>: - void
Collection of active users matching the specified type, Throws:
keyed by user ID. - std::runtime_error if a notification recipient user ID is invalid
*/ */
util::Map<std::string, User*> UserManagementService::getUsers(util::UserType type) void UserManagementService::loadUsers()
{ {
DataStoreLockGuard lock(m_dataStore); util::FileManager<User> userFileManager(config::file::USER_FILE);
auto& trackedUsersMap = m_dataStore.getUsers(); util::FileManager<Notification> notificationFileManager(config::file::NOTIFICATION_FILE);
util::Map<std::string, User*> currentUsers = util::getObjects(trackedUsersMap); auto& users = m_dataStore.getUsers();
util::Map<std::string, User*> filteredUsersMap; auto usersMap = userFileManager.load();
for (int index = 0; index < currentUsers.getSize(); index++) auto notificationsMap = notificationFileManager.load();
{ int numberOfUsers = usersMap.getSize();
User* currentUser = currentUsers.getValueAt(index); int numberOfNotifications = notificationsMap.getSize();
if (currentUser && currentUser->getState() == util::State::ACTIVE && currentUser->getUserType() == type) for (int index = 0; index < numberOfUsers; index++)
{ {
filteredUsersMap.insert(currentUser->getId(), currentUser); users[usersMap.getKeyAt(index)] = usersMap.getValueAt(index);
} }
} for (int index = 0; index < numberOfNotifications; index++)
return filteredUsersMap; {
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);
} }
@@ -6,7 +6,6 @@ Description: Header file declaring the UserManagementService class, which manage
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"
@@ -31,4 +30,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();
}; };
@@ -15,7 +15,7 @@ namespace config
{ {
constexpr const char* DEFAULT_ADMIN_USERNAME = "admin"; constexpr const char* DEFAULT_ADMIN_USERNAME = "admin";
constexpr const char* DEFAULT_ADMIN_NAME = "admin"; constexpr const char* DEFAULT_ADMIN_NAME = "admin";
constexpr const char* DEFAULT_ADMIN_PASSWORD = "admin"; constexpr const char* DEFAULT_ADMIN_PASSWORD = "";
constexpr const char* DEFAULT_ADMIN_EMAIL = "admin@vss"; constexpr const char* DEFAULT_ADMIN_EMAIL = "admin@vss";
constexpr const char* DEFAULT_ADMIN_PHONE = "0000000000"; constexpr const char* DEFAULT_ADMIN_PHONE = "0000000000";
} }
@@ -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,37 +12,32 @@ 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
}; };
enum class PaymentStatus : int enum class PaymentStatus
{ {
PENDING, PENDING,
COMPLETED, COMPLETED
PAID
}; };
enum class ServiceJobStatus : int enum class ServiceJobStatus
{ {
PENDING,
STARTED, STARTED,
COMPLETED, COMPLETED
IN_PROGRESS,
CANCELLED
}; };
enum class State : int enum class State
{ {
ACTIVE, ACTIVE,
INACTIVE INACTIVE
@@ -113,8 +108,6 @@ namespace util
return "ONLINE"; return "ONLINE";
case PaymentMode::OFFLINE: case PaymentMode::OFFLINE:
return "OFFLINE"; return "OFFLINE";
case PaymentMode::NOTSET:
return "NOTSET";
} }
throw std::invalid_argument("Invalid PaymentMode"); throw std::invalid_argument("Invalid PaymentMode");
} }
@@ -139,10 +132,6 @@ namespace util
{ {
return PaymentMode::OFFLINE; return PaymentMode::OFFLINE;
} }
if (value == "NOTSET")
{
return PaymentMode::NOTSET;
}
throw std::invalid_argument("Invalid PaymentMode string"); throw std::invalid_argument("Invalid PaymentMode string");
} }
@@ -162,8 +151,6 @@ namespace util
return "PENDING"; return "PENDING";
case PaymentStatus::COMPLETED: case PaymentStatus::COMPLETED:
return "COMPLETED"; return "COMPLETED";
case PaymentStatus::PAID:
return "PAID";
} }
throw std::invalid_argument("Invalid PaymentStatus"); throw std::invalid_argument("Invalid PaymentStatus");
} }
@@ -205,16 +192,10 @@ namespace util
{ {
switch (status) switch (status)
{ {
case ServiceJobStatus::PENDING:
return "PENDING";
case ServiceJobStatus::STARTED: case ServiceJobStatus::STARTED:
return "STARTED"; return "STARTED";
case ServiceJobStatus::COMPLETED: case ServiceJobStatus::COMPLETED:
return "COMPLETED"; return "COMPLETED";
case ServiceJobStatus::CANCELLED:
return "CANCELLED";
case ServiceJobStatus::IN_PROGRESS:
return "IN_PROGRESS";
} }
throw std::invalid_argument("Invalid ServiceJobStatus"); throw std::invalid_argument("Invalid ServiceJobStatus");
} }
@@ -239,18 +220,6 @@ namespace util
{ {
return ServiceJobStatus::COMPLETED; return ServiceJobStatus::COMPLETED;
} }
if (value == "PENDING")
{
return ServiceJobStatus::PENDING;
}
if (value == "CANCELLED")
{
return ServiceJobStatus::CANCELLED;
}
if (value == "IN_PROGRESS")
{
return ServiceJobStatus::IN_PROGRESS;
}
throw std::invalid_argument("Invalid ServiceJobStatus string"); throw std::invalid_argument("Invalid ServiceJobStatus string");
} }
@@ -296,4 +265,4 @@ namespace util
} }
throw std::invalid_argument("Invalid State string"); throw std::invalid_argument("Invalid State string");
} }
} }
@@ -11,39 +11,10 @@ Date: 22-May-2026
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include <direct.h>
#include "Vector.h" #include "Vector.h"
namespace util namespace util
{ {
/*
Function: ensureDirectoryExists
Description: Creates all missing directories present in the given file path.
Iteratively parses the path and creates each directory level
using _mkdir() before file operations are performed.
Parameters:
- filePath: const std::string&, relative or absolute file path
Returns:
- void
Throws:
- None (_mkdir failures are intentionally ignored if directory already exists)
*/
inline void ensureDirectoryExists(const std::string& filePath)
{
size_t position = 0;
while ((position = filePath.find('/', position)) != std::string::npos)
{
std::string directory = filePath.substr(0, position);
if (!directory.empty())
{
(void)_mkdir(directory.c_str());
}
position++;
}
}
/* /*
Function: loadRecords Function: loadRecords
Description: Loads records from a given file path into a vector of strings. Description: Loads records from a given file path into a vector of strings.
@@ -61,7 +32,6 @@ namespace util
std::ifstream file(filePath); std::ifstream file(filePath);
if (!file.is_open()) if (!file.is_open())
{ {
ensureDirectoryExists(filePath);
std::ofstream newFile(filePath); std::ofstream newFile(filePath);
newFile.close(); newFile.close();
file.open(filePath); file.open(filePath);
@@ -106,4 +76,4 @@ namespace util
file << records[index] << '\n'; file << records[index] << '\n';
} }
} }
} }
@@ -11,11 +11,9 @@ Date: 22-May-2026
#pragma once #pragma once
#include <stdexcept> #include <stdexcept>
#include <string>
#include <fstream> #include <fstream>
#include "Vector.h" #include "Vector.h"
#include "Map.h" #include "Map.h"
#include "FileHelper.h"
namespace util namespace util
{ {
@@ -52,7 +50,6 @@ namespace util
std::ifstream file(m_filePath); std::ifstream file(m_filePath);
if (!file.is_open()) if (!file.is_open())
{ {
ensureDirectoryExists(m_filePath);
std::ofstream newFile(m_filePath); std::ofstream newFile(m_filePath);
newFile.close(); newFile.close();
file.open(m_filePath); file.open(m_filePath);
@@ -10,7 +10,6 @@
#include <limits> #include <limits>
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
#include <conio.h>
namespace util namespace util
{ {
@@ -55,48 +54,6 @@ namespace util
value = cleanedValue; value = cleanedValue;
} }
/*
* Function: readPassword
* Description: Reads a password from console without echoing characters;
* displays '*' for each character typed, handles backspace,
* and cleans commas from the result.
* Parameters:
* value - reference to a string where the password will be stored
* Returns:
* void - no return value
*/
inline void readPassword(std::string& value)
{
value.clear();
char currentCharacter;
while ((currentCharacter = _getch()) != '\r')
{
if (currentCharacter == '\b')
{
if (!value.empty())
{
value.pop_back();
std::cout << "\b \b";
}
}
else
{
value += currentCharacter;
std::cout << '*';
}
}
std::cout << std::endl;
std::string cleanedValue;
for (int iterator = 0; iterator < value.length(); iterator++)
{
if (value[iterator] != ',')
{
cleanedValue += value[iterator];
}
}
value = cleanedValue;
}
/* /*
* Function: pressEnter * Function: pressEnter
* Description: Pauses execution until the user presses Enter. * Description: Pauses execution until the user presses Enter.
@@ -105,7 +62,6 @@ namespace util
*/ */
inline void pressEnter() inline void pressEnter()
{ {
std::cout << std::endl;
system("pause"); system("pause");
} }
} }
@@ -21,28 +21,4 @@ namespace util
{ {
std::cout << "\x1B[2J\x1B[H" << std::flush; std::cout << "\x1B[2J\x1B[H" << std::flush;
} }
/*
Function: truncateString
Description:
Truncates a string if its length exceeds the given maximum length.
The truncated string ends with "..." to indicate omitted characters.
Parameters:
- text: const std::string&, input string to truncate
- maxLength: size_t, maximum allowed length of the returned string
Returns:
- std::string: Original string if within limit, otherwise truncated string with "..."
*/
inline std::string truncateString(const std::string& text, size_t maxLength)
{
if (text.length() <= maxLength)
{
return text;
}
if (maxLength <= 3)
{
return std::string(maxLength, '.');
}
return text.substr(0, maxLength - 3) + "...";
}
} }
@@ -1,12 +1,12 @@
/* /*
File: Utility.h File: Utility.h
Description: Header file declaring utility functions used across the system Description: Header file declaring utility functions used across the system,
including cost calculation for services and combo packages.
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include "ComboPackage.h"
#include "DataStore.h" #include "DataStore.h"
#include "FileHelper.h" #include "FileHelper.h"
#include "InventoryItem.h" #include "InventoryItem.h"
@@ -25,154 +25,77 @@ namespace util
inline double calculatePartsCost(const Service* service) inline double calculatePartsCost(const Service* service)
{ {
double cost = 0; double cost = 0;
auto& requiredInventoryItems = service->getRequiredInventoryItems(); auto& requiredInventoryItems = service->getRequiredInventoryItems();
int requiredInventoryItemsSize = requiredInventoryItems.getSize(); int requiredInventoryItemsSize = requiredInventoryItems.getSize();
for (int index = 0; index < requiredInventoryItemsSize; index++) for (int index = 0; index < requiredInventoryItemsSize; index++)
{
cost += requiredInventoryItems.getValueAt(index)->getPrice();
}
return cost;
}
/*
Function: calculateComboServiceEstimatedCost
Description: Calculates the estimated total cost of a combo package by summing
the labor and parts costs of all services included in the package.
Parameter: const ComboPackage* comboPackage - pointer to the combo package object
Return type: double - estimated total cost of the combo package
*/
inline double calculateComboServiceEstimatedCost(const ComboPackage* comboPackage)
{
double cost = 0;
auto& services = comboPackage->getServices();
int servicesSize = services.getSize();
for (int index = 0; index < servicesSize; index++)
{
const Service* service = services.getValueAt(index);
cost += calculatePartsCost(service) + service->getLaborCost();
}
return cost;
}
/*
Function: loadObservers
Description: Loads observer IDs from a file and attaches the corresponding users
to the notification management service. Validates that each observer ID
exists in the datastore before attaching.
Parameters:
- filePath: const std::string&, path to the file containing observer IDs
- service: NotificationManagementService*, pointer to the notification service
- dataStore: DataStore&, reference to the datastore containing users
Returns:
- void
Throws:
- std::runtime_error if an observer ID is invalid (not found in datastore)
*/
inline void loadObservers(const std::string& filePath, NotificationManagementService* service, DataStore& dataStore)
{
auto observerIDs = util::loadRecords(filePath);
auto& users = dataStore.getUsers();
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"); cost += requiredInventoryItems.getValueAt(index)->getPrice();
}
service->attach(users.getValueAt(userIndex));
} }
return cost;
} }
/* /*
Function: saveObservers Function: calculateComboServiceEstimatedCost
Description: Saves the current observer IDs from the notification management service Description: Calculates the estimated total cost of a combo package by summing
to a file for persistence. the labor and parts costs of all services included in the package.
Parameters: Parameter: const ComboPackage* comboPackage - pointer to the combo package object
- filePath: const std::string&, path to the file where observer IDs will be saved Return type: double - estimated total cost of the combo package
- service: NotificationManagementService*, pointer to the notification service
Returns:
- void
*/ */
inline void saveObservers(const std::string& filePath, NotificationManagementService* service) inline double calculateComboServiceEstimatedCost(const ComboPackage* comboPackage)
{
double cost = 0;
auto& services = comboPackage->getServices();
int servicesSize = services.getSize();
for (int index = 0; index < servicesSize; index++)
{ {
auto observerIDs = service->getObserverIDs(); const Service* service = services.getValueAt(index);
util::saveRecords(filePath, observerIDs); cost += calculatePartsCost(service) + service->getLaborCost();
} }
return cost;
template<typename TObject>
Map<std::string, TObject*> getObjects(const Map<std::string, TrackedRecord<TObject>>& trackedRecords);
template<typename TObject>
Map<std::string, const TObject*> getConstObjects(const Map<std::string, TrackedRecord<TObject>>& trackedRecords);
template<typename TObject>
TrackedRecord<TObject> createNewRecord(TObject* object);
} }
/* /*
Function: getObjects Function: loadObservers
Description: Extracts the object pointers from a tracked-record Description: Loads observer IDs from a file and attaches the corresponding users
collection and returns them as a map keyed by the to the notification management service. Validates that each observer ID
same identifiers. exists in the datastore before attaching.
Parameters: Parameters:
- trackedRecords: Collection of tracked records. - filePath: const std::string&, path to the file containing observer IDs
- service: NotificationManagementService*, pointer to the notification service
- dataStore: DataStore&, reference to the datastore containing users
Returns: Returns:
- Map<std::string, TObject*>: Collection of object pointers. - void
Throws:
- std::runtime_error if an observer ID is invalid (not found in datastore)
*/ */
template<typename TObject> inline void loadObservers(const std::string& filePath, NotificationManagementService* service, DataStore& dataStore)
util::Map<std::string, TObject*> util::getObjects(const util::Map<std::string, TrackedRecord<TObject>>& trackedRecords)
{ {
util::Map<std::string, TObject*> objects; auto observerIDs = util::loadRecords(filePath);
for (int index = 0; index < trackedRecords.getSize(); ++index) auto& users = dataStore.getUsers();
for (int index = 0; index < observerIDs.getSize(); index++)
{ {
const std::string& key = trackedRecords.getKeyAt(index); const std::string& observerID = observerIDs[index];
TObject* object = trackedRecords.getValueAt(index).data; int userIndex = users.find(observerID);
objects.insert(key, object); 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:
- trackedRecords: Collection of tracked records. - filePath: const std::string&, path to the file where observer IDs will be saved
- service: NotificationManagementService*, pointer to the notification service
Returns: Returns:
- Map<std::string, const TObject*>: - void
Collection of read-only object pointers.
*/ */
template<typename TObject> inline void saveObservers(const std::string& filePath, NotificationManagementService* service)
util::Map<std::string, const TObject*> util::getConstObjects(
const util::Map<std::string, TrackedRecord<TObject>>& trackedRecords)
{ {
util::Map<std::string, const TObject*> objects; auto observerIDs = service->getObserverIDs();
for (int index = 0; index < trackedRecords.getSize(); ++index) util::saveRecords(filePath, observerIDs);
{
const std::string& key = trackedRecords.getKeyAt(index);
const TObject* object = trackedRecords.getValueAt(index).data;
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;
}
@@ -106,68 +106,4 @@ bool util::isPasswordValid(const std::string& password)
} }
return hasUpper && hasLower && hasDigit && hasSpecial; return hasUpper && hasLower && hasDigit && hasSpecial;
}
/*
* Function: isUsernameDuplicate
* Description: Checks if the given username already exists among active users.
* Parameters:
* username - string containing the username to validate
* usersMap - map of user objects keyed by identifier
* Returns:
* bool - true if the username is already in use by an active user, false otherwise
*/
bool util::isUsernameDuplicate(const std::string& username, const util::Map<std::string, User*>& usersMap)
{
int index = usersMap.findIf(
[&](const std::string&, User* user)
{
return (user->getUserName() == username);
}
);
return index != -1;
}
/*
* Function: isPhoneDuplicate
* Description: Checks if the given phone number already exists among active users.
* Parameters:
* phone - string containing the phone number to validate
* usersMap - map of user objects keyed by identifier
* Returns:
* bool - true if the phone number is already in use by an active user, false otherwise
* Notes:
* - Only considers users with state util::State::ACTIVE
*/
bool util::isPhoneDuplicate(const std::string& phone, const util::Map<std::string, User*>& usersMap)
{
int index = usersMap.findIf(
[&](const std::string&, User* user)
{
return (user->getPhone() == phone && user->getState() == util::State::ACTIVE);
}
);
return index != -1;
}
/*
* Function: isEmailDuplicate
* Description: Checks if the given email address already exists among active users.
* Parameters:
* email - string containing the email address to validate
* usersMap - map of user objects keyed by identifier
* Returns:
* bool - true if the email address is already in use by an active user, false otherwise
* Notes:
* - Only considers users with state util::State::ACTIVE
*/
bool util::isEmailDuplicate(const std::string& email, const util::Map<std::string, User*>& usersMap)
{
int index = usersMap.findIf(
[&](const std::string&, User* user)
{
return (user->getEmail() == email && user->getState() == util::State::ACTIVE);
}
);
return index != -1;
} }
@@ -9,15 +9,10 @@
#include<string> #include<string>
#include<algorithm> #include<algorithm>
#include<cctype> #include<cctype>
#include "Map.h"
#include "User.h"
namespace util namespace util
{ {
bool isPhoneNumberValid(const std::string&); bool isPhoneNumberValid(const std::string&);
bool isEmailValid(const std::string&); bool isEmailValid(const std::string&);
bool isPasswordValid(const std::string&); bool isPasswordValid(const std::string&);
bool isUsernameDuplicate(const std::string&, const util::Map<std::string, User*>&);
bool isPhoneDuplicate(const std::string&, const util::Map<std::string, User*>&);
bool isEmailDuplicate(const std::string&, const util::Map<std::string, User*>&);
} }
@@ -8,740 +8,100 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#include <iomanip>
#include <iostream>
#include "AdminMenu.h" #include "AdminMenu.h"
#include "Enums.h"
#include "InputHelper.h" #include "InputHelper.h"
#include "InventoryItem.h"
#include "MenuHelper.h"
#include "OutputHelper.h" #include "OutputHelper.h"
#include "Service.h" #include "MenuHelper.h"
#include "ServiceBooking.h"
#include "User.h"
#include "Utility.h"
#include "Validator.h"
/* /*
Function: showMenu Function: showMenu
Description: Displays the admin menu and handles user input until logout is selected. Description: Displays the admin menu in a loop until the user chooses to logout.
Parameter: None Handles exceptions and ensures smooth user interaction.
Return type: void Parameters:
- None
Returns:
- void
*/ */
void AdminMenu::showMenu() void AdminMenu::showMenu()
{ {
while (true) bool isMenuActive = true;
{ while (isMenuActive)
try {
{ try
int choice; {
util::clear(); int choice;
std::cout << "Admin Menu" util::clear();
<< "\n1. View Stock Levels" std::cout << "" << std::endl;
<< "\n2. Add Inventory Item" util::read(choice);
<< "\n3. Remove Inventory Item" if (!handleOperation(choice))
<< "\n4. Check Stock Availability" {
<< "\n5. Assign Job to Technician" isMenuActive = false;
<< "\n6. Display Users" }
<< "\n7. Add Technician" }
<< "\n8. Remove Customer/Technician" catch (const std::exception& e)
<< "\n9. Display Services" {
<< "\n10. Create Service" std::cout << "Exception: " << e.what() << std::endl;
<< "\n11. Remove Service" util::pressEnter();
<< "\n12. Display Combo Packages" }
<< "\n13. Create Combo Package" }
<< "\n14. Remove Combo Package"
<< "\n15. View Notifications"
<< "\n16. Change Password"
<< "\n17. Confirm Payment"
<< "\n18. Logout"
<< "\nEnter a choice: ";
util::read(choice);
if (!handleOperation(choice))
{
break;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
}
}
} }
/*
Function: handleOperation
Description: Executes the corresponding admin operation based on the selected menu choice.
Parameter: int choice - selected menu option
Return type: bool - true if menu continues, false if logout
*/
bool AdminMenu::handleOperation(int choice) bool AdminMenu::handleOperation(int choice)
{ {
switch (choice) return false;
{
case 1:
viewStockLevels();
break;
case 2:
addInventoryItem();
break;
case 3:
removeInventoryItem();
break;
case 4:
checkStockAvailability();
break;
case 5:
assignJob();
break;
case 6:
displayUsers();
break;
case 7:
addTechnician();
break;
case 8:
removeUser();
break;
case 9:
displayServices();
break;
case 10:
createService();
break;
case 11:
removeService();
break;
case 12:
displayComboPackages();
break;
case 13:
createComboPackages();
break;
case 14:
removeComboPackage();
break;
case 15:
viewNotifications();
break;
case 16:
changePassword();
break;
case 17:
confirmPayment();
break;
case 18:
logout();
return false;
default:
std::cout << "Enter a valid choice!" << std::endl;
util::pressEnter();
}
return true;
} }
/*
Function: logout
Description: Logs out the currently authenticated admin user.
Parameter: None
Return type: void
*/
void AdminMenu::logout() void AdminMenu::logout()
{ {
m_controller.logout();
} }
/*
Function: changePassword
Description: Allows the admin to change their password after validation.
Parameter: None
Return type: void
*/
void AdminMenu::changePassword() void AdminMenu::changePassword()
{ {
changePasswordHelper(m_controller);
} }
/*
Function: viewStockLevels
Description: Displays all active inventory items with their details
including ID, part name, quantity, and price.
Parameter: None
Return type: void
*/
void AdminMenu::viewStockLevels() void AdminMenu::viewStockLevels()
{ {
util::clear();
auto inventoryItems = m_controller.getInventoryItems();
bool hasActiveItems = false;
std::cout << "View Stock Levels" << std::endl;
if (inventoryItems.isEmpty())
{
std::cout << "No items found in Inventory.\n";
util::pressEnter();
return;
}
for (int index = 0; index < inventoryItems.getSize(); index++)
{
const InventoryItem* item = inventoryItems.getValueAt(index);
if (item->getState() == util::State::ACTIVE)
{
hasActiveItems = true;
break;
}
}
if (!hasActiveItems)
{
std::cout << "No active Inventory Item found.\n";
util::pressEnter();
return;
}
std::cout << std::left << std::setw(15) << "Item ID"
<< std::setw(25) << "Part Name"
<< std::setw(15) << "Quantity"
<< std::setw(15) << "Price"
<< std::endl;
for (int iterator = 0; iterator < inventoryItems.getSize(); ++iterator)
{
const InventoryItem* item = inventoryItems.getValueAt(iterator);
if (item != nullptr)
{
if (item->getState() != util::State::INACTIVE)
{
std::cout << std::left << std::setw(15) << item->getId()
<< std::setw(25) << item->getPartName()
<< std::setw(15) << item->getQuantity()
<< std::setw(15) << item->getPrice()
<< std::endl;
}
}
}
std::cout << "\n";
util::pressEnter();
} }
/*
Function: addInventoryItem
Description: Allows the admin to either add a new inventory item
or increase the quantity of an existing item.
Parameter: None
Return type: void
*/
void AdminMenu::addInventoryItem() void AdminMenu::addInventoryItem()
{ {
util::clear();
int choice, quantity;
double price;
std::string partName;
std::cout << "Add Inventory Item\n";
std::cout << "1. Add new item \n2. Restock Item\n\nEnter your choice : ";
util::read(choice);
switch (choice)
{
case 1:
{
util::clear();
std::cout << "Enter Item Details\n";
std::cout << "Part Name : ";
util::read(partName);
std::cout << "Quantity : ";
util::read(quantity);
std::cout << "Price : ";
util::read(price);
m_controller.addInventoryItem(partName, quantity, price);
std::cout << "\nNew Item " << partName << " added to the Inventory.\n\n";
break;
}
case 2:
{
util::clear();
std::cout << "Select Item to Restock\n";
auto inventoryItems = m_controller.getInventoryItems();
addQuantityToItem(inventoryItems, m_controller);
break;
}
default:
{
std::cout << "\nEnter a valid choice.\n\n";
}
}
util::pressEnter();
} }
/*
Function: removeInventoryItem
Description: Removes an active inventory item by marking it inactive
after user selection.
Parameter: None
Return type: void
*/
void AdminMenu::removeInventoryItem() void AdminMenu::removeInventoryItem()
{ {
util::clear();
std::cout << "Remove Inventory Item\n";
auto inventoryItems = m_controller.getInventoryItems();
auto activeItems = filterActiveItems(inventoryItems);
int activeItemsSize = activeItems.getSize();
if (activeItemsSize == 0)
{
std::cout << "No items available in Inventory." << std::endl;
util::pressEnter();
return;
}
displayInventoryWithItems(activeItems);
int itemIndex;
std::cout << "Enter the index of the item to remove: ";
util::read(itemIndex);
if (itemIndex < 1 || itemIndex > activeItemsSize)
{
std::cout << "Invalid index selected." << std::endl;
util::pressEnter();
return;
}
const InventoryItem* selectedItem = activeItems.getValueAt(itemIndex - 1);
if (selectedItem != nullptr)
{
if(selectedItem->getState() != util::State::INACTIVE)
{
std::string selectedItemId = selectedItem->getId();
m_controller.removeInventoryItem(selectedItemId);
std::cout << "Item " << selectedItem->getPartName() << " removed successfully." << std::endl;
}
}
util::pressEnter();
} }
/*
Function: checkStockAvailability
Description: Checks if a specific inventory item is available
and displays its details if active.
Parameter: None
Return type: void
*/
void AdminMenu::checkStockAvailability() void AdminMenu::checkStockAvailability()
{ {
util::clear();
std::string itemId;
std::cout << "Check Stock Availability \n";
std::cout << "Enter the Item ID : ";
util::read(itemId);
util::clear();
const InventoryItem* selectedItem = m_controller.getInventoryItem(itemId);
if (selectedItem != nullptr)
{
if (selectedItem->getState() != util::State::INACTIVE)
{
std::cout << "Item Details\n";
std::cout << "---------------------------------------------\n";
std::cout << "Item ID : " << selectedItem->getId() << "\n";
std::cout << "Part Name : " << selectedItem->getPartName() << "\n";
std::cout << "Quantity : " << selectedItem->getQuantity() << "\n";
}
}
else
{
std::cout << "Item not Found" << std::endl;
}
util::pressEnter();
} }
/*
Function: assignJob
Description: Allows the admin to assign pending service bookings to available technicians.
Creates job cards for selected services.
Parameters:
- None
Returns:
- void
*/
void AdminMenu::assignJob() void AdminMenu::assignJob()
{ {
util::clear();
std::cout << "Assign Job to Technician\n";
std::string selectedService;
bool hasPendingService = false;
auto currentBookings = m_controller.getServiceBookings();
auto pendingServiceBookings = filterActiveServiceBookings(currentBookings);
auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN);
int bookingsSize = pendingServiceBookings.getSize();
util::Map<int, const ServiceBooking*> serviceBookingsMap;
util::Map<int, const User*> currentAvailableTechniciansMap;
if (listServiceBookings(pendingServiceBookings, bookingsSize, serviceBookingsMap))
{
const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap);
if (selectedService)
{
if (availableTechnicians.getSize() != 0)
{
listAvailableTechnicians(availableTechnicians, availableTechnicians.getSize(), currentAvailableTechniciansMap);
const User* selectedTechnician = selectTechnician(currentAvailableTechniciansMap);
if (selectedTechnician)
{
auto& servicesInBooking = selectedService->getServices();
for (int iterator = 0; iterator < servicesInBooking.getSize(); iterator++)
{
m_controller.createJobCard(selectedService->getId(), selectedTechnician->getId(), servicesInBooking.getValueAt(iterator)->getId());
}
std::cout << "Job card created for each service and technician successfully assigned.\n\n";
}
}
else
{
std::cout << "No technicians are currently available.\n\n";
}
}
}
else
{
std::cout << "No pending service bookings available.\n\n";
}
util::pressEnter();
} }
/*
Function: displayServices()
Description: Display all active services
Parameters:
- None
Returns:
- void
*/
void AdminMenu::displayServices()
{
util::clear();
std::cout << "List of all Services\n";
util::Map<std::string, const Service*> currentServices = m_controller.getServices();
util::Map<std::string, const Service*> currentActiveServices = filterActiveServices(currentServices);
displayAllServices(currentActiveServices);
util::pressEnter();
}
/*
Function: createService
Description: Allows the admin to create a new service by selecting inventory items and specifying labor cost.
Parameters:
- None
Returns:
- void
*/
void AdminMenu::createService() void AdminMenu::createService()
{ {
util::clear();
std::cout << "Create Service\n";
std::string serviceName;
double labourCost;
std::cout << "Enter the service name: ";
util::read(serviceName);
util::Map<std::string, const InventoryItem*> currentInventoryItems = m_controller.getInventoryItems();
util::Map<std::string, const InventoryItem*> activeInventoryItems = filterActiveItems(currentInventoryItems);
util::Vector<std::string> selectedInventoryItems;
selectInventoryItems(activeInventoryItems,selectedInventoryItems);
if (selectedInventoryItems.isEmpty())
{
util::pressEnter();
return;
}
std::cout << "\nEnter the labour cost: ";
util::read(labourCost);
m_controller.createService(serviceName, selectedInventoryItems, labourCost);
std::cout << "\nService created sucessfully.\n\n";
util::pressEnter();
} }
/*
Function: removeService
Description: Allows the admin to remove an existing service by selecting from available services.
Parameters:
- None
Returns:
- void
*/
void AdminMenu::removeService() void AdminMenu::removeService()
{ {
util::clear();
std::cout << "Remove Service\n";
std::string selectedServiceID;
util::Map<std::string, const Service*> currentServices = m_controller.getServices();
util::Map<std::string, const Service*> currentActiveServices = filterActiveServices(currentServices);
selectedServiceID = selectServicesToRemove(currentActiveServices);
if (selectedServiceID != "")
{
m_controller.removeService(selectedServiceID);
std::cout << "Service removed successfully.\n\n";
}
else
{
std::cout << "Failed to remove service.\n\n";
}
util::pressEnter();
} }
/*
Function: displayUsers
Description: Displays all users.
Parameter: None
Return type: void
*/
void AdminMenu::displayUsers()
{
util::clear();
auto listOfUsers = m_controller.getUsers();
auto listOfActiveUsers = filterActiveUsers(listOfUsers);
int activeUserCount = listOfActiveUsers.getSize();
std::cout << "List of all Users\n";
if (activeUserCount < 1)
{
std::cout << "No Active users." << std::endl;
util::pressEnter();
return;
}
displayAllUsers(listOfActiveUsers);
util::pressEnter();
}
/*
Function: confirmPayment
Description: Confirms payment for a selected invoice. Validates invoice status, updates payment date,
sets status to COMPLETED, and sends a notification to the customer.
Parameters:
- invoiceID: std::string, ID of the invoice to confirm
Returns:
- void
*/
void AdminMenu::confirmPayment()
{
util::clear();
std::cout << "Confirm Payment\n";
auto invoiceList = m_controller.getAllInvoices();
if (invoiceList.isEmpty())
{
std::cout << "No pending invoices available for confirmation.";
util::pressEnter();
return;
}
bool hasConfirmableInvoice = false;
for (int index = 0; index < invoiceList.getSize(); ++index)
{
const Invoice* invoice = invoiceList.getValueAt(index);
if (invoice && invoice->getStatus() == util::PaymentStatus::PAID)
{
hasConfirmableInvoice = true;
break;
}
}
if (!hasConfirmableInvoice)
{
std::cout << "No invoices awaiting confirmation.\n";
util::pressEnter();
return;
}
std::string selectedID = selectInvoiceFromUserForPayment(invoiceList, util::PaymentStatus::PAID);
if (selectedID == "")
{
std::cout << "Payment failed.\n";
util::pressEnter();
return;
}
m_controller.confirmPayment(selectedID);
std::cout << "Payment Confirmed successfully.\n";
util::pressEnter();
}
/*
Function: addTechnician
Description: Adds a new technician after validating username, password, email, and phone number.
Parameter: None
Return type: void
*/
void AdminMenu::addTechnician() void AdminMenu::addTechnician()
{ {
util::clear();
std::string username, name, password, email, phoneNumber;
std::cout << "Add Technician\n";
std::cout << "Enter Technician Username: ";
util::read(username);
std::cout << "Enter Technician Name: ";
util::read(name);
std::cout << "Enter Technician Password: ";
util::read(password);
if(!util::isPasswordValid(password))
{
std::cout << "\nError: Password is invalid!\n\n";
util::pressEnter();
return;
}
std::cout << "Enter Technician Email: ";
util::read(email);
if(!util::isEmailValid(email))
{
std::cout << "\nError: Email is invalid!\n\n";
util::pressEnter();
return;
}
std::cout << "Enter Technician Phone: ";
util::read(phoneNumber);
if(!util::isPhoneNumberValid(phoneNumber))
{
std::cout << "\nError: Phone Number is invalid!\n\n";
util::pressEnter();
return;
}
m_controller.createTechnician(username, name, password, email, phoneNumber);
std::cout << "\nTechnician Added Successfully.\n\n";
util::pressEnter();
} }
/*
Function: removeUser
Description: Removes a selected active user (customer or technician) from the system.
Parameter: None
Return type: void
*/
void AdminMenu::removeUser() void AdminMenu::removeUser()
{ {
util::clear();
int indexChoice;
auto listOfUsers = m_controller.getUsers();
auto listOfActiveUsers = filterActiveUsers(listOfUsers);
int activeUserCount = listOfActiveUsers.getSize();
std::cout << "Remove User \n";
if (activeUserCount < 1)
{
std::cout << "No Active users." << std::endl;
util::pressEnter();
return;
}
displayAllUsers(listOfActiveUsers);
std::cout << "Enter the index of the user to delete : ";
util::read(indexChoice);
if (indexChoice < 1 || indexChoice > activeUserCount)
{
std::cout << "Error invalid index.\n" << std::endl;
util::pressEnter();
return;
}
const User* userToRemove = listOfActiveUsers.getValueAt(indexChoice - 1);
if (userToRemove != nullptr)
{
std::string userIdToRemove = userToRemove->getId();
m_controller.removeUser(userIdToRemove);
std::cout << userToRemove->getUserName() << " removed Successfully.\n";
}
util::pressEnter();
} }
/*
Function: displayComboPackages()
Description: Display all active combo packages
Parameters:
- None
Returns:
- void
*/
void AdminMenu::displayComboPackages()
{
util::clear();
std::cout << "List of all Combo Packages\n";
util::Map<std::string, const ComboPackage*> currentComboPackages = m_controller.getComboPackages();
util::Map<std::string, const ComboPackage*> currentActiveComboPackages = filterComboPackages(currentComboPackages);
displayAllComboPackages(currentActiveComboPackages);
util::pressEnter();
}
/*
Function: createComboPackages
Description: Creates a new combo package by selecting two active services and applying a discount.
Parameter: None
Return type: void
*/
void AdminMenu::createComboPackages() void AdminMenu::createComboPackages()
{ {
util::clear();
std::cout << "Create Combo Packages\n";
auto serviceList = m_controller.getServices();
auto activeServices = filterActiveServices(serviceList);
int currentActiveServicesCount = activeServices.getSize();
const int NUMBER_OF_SERVICE_PER_PACKAGE = 2;
util::Vector<std::string> selectedServiceID;
for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++)
{
const Service* chosenService = nullptr;
while (true)
{
chosenService = selectServiceFromServices(activeServices);
if (!chosenService)
{
std::cout << "Failed to create combo package!\n\n";
util::pressEnter();
return;
}
bool alreadyChosen = false;
for (int iteratorOne = 0; iteratorOne < selectedServiceID.getSize(); iteratorOne++)
{
if (selectedServiceID[iteratorOne] == chosenService->getId())
{
alreadyChosen = true;
break;
}
}
if (alreadyChosen)
{
if (currentActiveServicesCount < 2)
{
break;
}
std::cout << "Service already selected. Please choose a different one." << std::endl;
continue;
}
selectedServiceID.push_back(chosenService->getId());
break;
}
if (currentActiveServicesCount < 2)
{
std::cout << "All the available services selected\n\n";
break;
}
}
std::string packageName;
double discountPercentage;
std::cout << "Enter combo package name: ";
util::read(packageName);
std::cout << "Enter discount percentage: ";
util::read(discountPercentage);
if (discountPercentage < 0.0 || discountPercentage > 100.0)
{
std::cout << "Error: Discount percentage must be between 0 and 100." << std::endl;
util::pressEnter();
return;
}
m_controller.createComboPackage(packageName, selectedServiceID, discountPercentage);
std::cout << "Combo package '" << packageName << "' created successfully." << std::endl;
util::pressEnter();
} }
/*
Function: removeComboPackage
Description: Removes a selected combo package from the system.
Parameter: None
Return type: void
*/
void AdminMenu::removeComboPackage() void AdminMenu::removeComboPackage()
{ {
util::clear();
std::cout << "Remove Combo Package\n";
util::Map<std::string, const ComboPackage*> currentComboPackages = m_controller.getComboPackages();
std::string selectedComboPackageID = selectComboPackage(currentComboPackages);
if (!selectedComboPackageID.empty())
{
m_controller.removeComboPackage(selectedComboPackageID);
std::cout << "Combo Package removed successfully.\n\n";
}
else
{
std::cout << "Combo package removal failed.\n\n";
}
util::pressEnter();
} }
/* /*
@@ -1,10 +1,10 @@
/* /*
File: AdminMenu.h File: AdminMenu.h
Description: Header file declaring the AdminMenu class, which provides Description: Declares the AdminMenu class which provides the administrative console menu in the Vehicle Service Management System.
administrative operations such as inventory management, Supports operations such as inventory management, job assignment, service creation/removal, technician management,
user management, service configuration, and notifications. combo package handling, notification viewing, and account management functions like logout and password change.
Author: Trenser Author: Trenser
Date:19-May-2026 Date: 19-May-2026
*/ */
#pragma once #pragma once
@@ -24,14 +24,10 @@ public:
void removeInventoryItem(); void removeInventoryItem();
void checkStockAvailability(); void checkStockAvailability();
void assignJob(); void assignJob();
void displayServices();
void createService(); void createService();
void removeService(); void removeService();
void displayUsers();
void confirmPayment();
void addTechnician(); void addTechnician();
void removeUser(); void removeUser();
void displayComboPackages();
void createComboPackages(); void createComboPackages();
void removeComboPackage(); void removeComboPackage();
void viewNotifications(); void viewNotifications();
@@ -6,21 +6,16 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <iomanip> #include <iomanip>
#include "ComboPackage.h" #include "ComboPackage.h"
#include "CustomerMenu.h" #include "CustomerMenu.h"
#include "MenuHelper.h"
#include "Enums.h"
#include "InputHelper.h" #include "InputHelper.h"
#include "OutputHelper.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "Invoice.h"
#include "Map.h" #include "Map.h"
#include "MenuHelper.h"
#include "OutputHelper.h"
#include "Service.h" #include "Service.h"
#include "ServiceBooking.h" #include "Utility.h"
#include "Timestamp.h"
#include "User.h"
#include "Validator.h" #include "Validator.h"
#include "Vector.h" #include "Vector.h"
@@ -130,7 +125,19 @@ Return type: void
*/ */
void CustomerMenu::changePassword() void CustomerMenu::changePassword()
{ {
changePasswordHelper(m_controller); std::string newPassword;
util::clear();
std::cout << "Enter new password: ";
util::read(newPassword);
m_controller.changePassword(newPassword);
if (!util::isPasswordValid(newPassword))
{
std::cout << "Error: Password is not strong enough!";
util::pressEnter();
return;
}
std::cout << "Password changed successfully";
util::pressEnter();
} }
/* /*
@@ -143,12 +150,11 @@ void CustomerMenu::updateDetails()
{ {
std::string email, phone; std::string email, phone;
util::clear(); util::clear();
std::cout << "Update Details\n";
std::cout << "Enter new email: "; std::cout << "Enter new email: ";
util::read(email); util::read(email);
if (!util::isEmailValid(email)) if (!util::isEmailValid(email))
{ {
std::cout << "Error: Email is invalid!\n"; std::cout << "Error: Email is invalid!";
util::pressEnter(); util::pressEnter();
return; return;
} }
@@ -156,15 +162,64 @@ void CustomerMenu::updateDetails()
util::read(phone); util::read(phone);
if (!util::isPhoneNumberValid(phone)) if (!util::isPhoneNumberValid(phone))
{ {
std::cout << "Error: Phone number is invalid!\n"; std::cout << "Error: Phone number is invalid!";
util::pressEnter(); util::pressEnter();
return; return;
} }
m_controller.updateUserDetails(email, phone); m_controller.updateUserDetails(email, phone);
std::cout << "Profile details updated successfully\n"; std::cout << "Profile details updated successfully";
util::pressEnter(); util::pressEnter();
} }
/*
Function: selectServiceFromServices
Description: Displays active services and allows the customer to select one by index.
Parameter: const util::Map<std::string, const Service*>& services - list of services
Return type: const Service* - selected service
*/
static const Service* selectServiceFromServices(const util::Map<std::string, const Service*>& services)
{
util::Map<int, const Service*> activeServicesMap;
int currentIndex = 1;
int userInputIndex;
std::cout << std::left
<< std::setw(10) << "Index"
<< std::setw(15) << "Service ID"
<< std::setw(25) << "Service Name"
<< std::setw(15) << "Estimated Cost"
<< std::endl;
for (int index = 0; index < services.getSize(); index++)
{
const Service* currentService = services.getValueAt(index);
if (currentService->getState() != util::State::ACTIVE)
{
continue;
}
activeServicesMap.insert(currentIndex, currentService);
double partsCost = calculatePartsCost(currentService);
std::cout << std::left
<< std::setw(10) << currentIndex
<< std::setw(15) << currentService->getId()
<< std::setw(25) << currentService->getName()
<< std::setw(15) << (currentService->getLaborCost() + partsCost)
<< std::endl;
currentIndex++;
}
if (activeServicesMap.getSize() == 0)
{
std::cout << "No active services available." << std::endl;
return nullptr;
}
std::cout << "Enter service index: ";
util::read(userInputIndex);
if (activeServicesMap.find(userInputIndex) == -1)
{
std::cout << "Invalid service index." << std::endl;
return nullptr;
}
return activeServicesMap[userInputIndex];
}
/* /*
Function: selectService Function: selectService
Description: Allows the customer to select a service, provide vehicle details, Description: Allows the customer to select a service, provide vehicle details,
@@ -175,16 +230,9 @@ Return type: void
void CustomerMenu::selectService() void CustomerMenu::selectService()
{ {
std::string vehicleNumber, vehicleBrand, vehicleModel; std::string vehicleNumber, vehicleBrand, vehicleModel;
util::clear();
std::cout << "Select a Service\n";
auto services = m_controller.getServices(); auto services = m_controller.getServices();
if (services.isEmpty())
{
std::cout << "No services available!";
util::pressEnter();
return;
}
util::Vector<std::string> selectedServices; util::Vector<std::string> selectedServices;
util::clear();
const Service* selectedService = selectServiceFromServices(services); const Service* selectedService = selectServiceFromServices(services);
if (selectedService == nullptr) if (selectedService == nullptr)
{ {
@@ -194,7 +242,6 @@ void CustomerMenu::selectService()
} }
selectedServices.push_back(selectedService->getId()); selectedServices.push_back(selectedService->getId());
util::clear(); util::clear();
std::cout << "Enter Vehicle Details\n";
std::cout << "Enter vehicle number: "; std::cout << "Enter vehicle number: ";
util::read(vehicleNumber); util::read(vehicleNumber);
std::cout << "Enter vehicle brand: "; std::cout << "Enter vehicle brand: ";
@@ -206,6 +253,54 @@ void CustomerMenu::selectService()
util::pressEnter(); util::pressEnter();
} }
/*
Function: selectComboPackageFromPackages
Description: Displays active combo packages and allows the customer to select one by index.
Parameter: const util::Map<std::string, const ComboPackage*>& comboPackages - list of combo packages
Return type: const ComboPackage* - selected combo package
*/
static const ComboPackage* selectComboPackageFromPackages(const util::Map<std::string, const ComboPackage*>& comboPackages)
{
util::Map<int, const ComboPackage*> activeComboPackages;
int currentIndex = 1;
int userInputIndex;
std::cout << std::left
<< std::setw(10) << "Index"
<< std::setw(15) << "Combo Package ID"
<< std::setw(15) << "Combo Package Name"
<< std::setw(15) << "Estimate Cost"
<< std::endl;
for (int index = 0; index < comboPackages.getSize(); index++)
{
const ComboPackage* currentComboPackage = comboPackages.getValueAt(index);
if (currentComboPackage->getState() != util::State::ACTIVE)
{
continue;
}
activeComboPackages.insert(currentIndex, currentComboPackage);
std::cout << std::left
<< std::setw(10) << currentIndex
<< std::setw(15) << currentComboPackage->getId()
<< std::setw(25) << currentComboPackage->getPackageName()
<< std::setw(15) << calculateComboServiceEstimatedCost(currentComboPackage)
<< std::endl;
currentIndex++;
}
if (activeComboPackages.getSize() == 0)
{
std::cout << "No active combo packages available." << std::endl;
return nullptr;
}
std::cout << "Enter combo package index: ";
util::read(userInputIndex);
if (activeComboPackages.find(userInputIndex) == -1)
{
std::cout << "Invalid combo package index." << std::endl;
return nullptr;
}
return activeComboPackages[userInputIndex];
}
/* /*
Function: selectComboPackage Function: selectComboPackage
Description: Allows the customer to select a combo package, provide vehicle details, Description: Allows the customer to select a combo package, provide vehicle details,
@@ -216,27 +311,16 @@ Return type: void
void CustomerMenu::selectComboPackage() void CustomerMenu::selectComboPackage()
{ {
std::string vehicleNumber, vehicleBrand, vehicleModel; std::string vehicleNumber, vehicleBrand, vehicleModel;
util::clear();
std::cout << "Select a Combo Package\n";
auto comboPackages = m_controller.getComboPackages(); auto comboPackages = m_controller.getComboPackages();
util::Map<std::string, const ComboPackage*> activeComboPackages = filterComboPackages(comboPackages); util::clear();
if (activeComboPackages.isEmpty()) const ComboPackage* selectedComboPackage = selectComboPackageFromPackages(comboPackages);
{
std::cout << "No combo packages available!\n\n";
util::pressEnter();
return;
}
const ComboPackage* selectedComboPackage = selectComboPackageFromPackages(activeComboPackages);
if (selectedComboPackage == nullptr) if (selectedComboPackage == nullptr)
{ {
std::cout << "Failed to book combo package!\n\n"; std::cout << "Failed to book combo package!";
util::pressEnter(); util::pressEnter();
return; return;
} }
std::cout << "Combo Package selected\n";
util::pressEnter();
util::clear(); util::clear();
std::cout << "Enter the vehicle details\n";
std::cout << "Enter vehicle number: "; std::cout << "Enter vehicle number: ";
util::read(vehicleNumber); util::read(vehicleNumber);
std::cout << "Enter vehicle brand: "; std::cout << "Enter vehicle brand: ";
@@ -244,127 +328,20 @@ void CustomerMenu::selectComboPackage()
std::cout << "Enter vehicle model: "; std::cout << "Enter vehicle model: ";
util::read(vehicleModel); util::read(vehicleModel);
m_controller.purchaseComboPackage(selectedComboPackage->getId(), vehicleNumber, vehicleBrand, vehicleModel); m_controller.purchaseComboPackage(selectedComboPackage->getId(), vehicleNumber, vehicleBrand, vehicleModel);
std::cout << "Combo Package has been booked successfully\n\n"; std::cout << "Combo Package has been booked successfully";
util::pressEnter(); util::pressEnter();
} }
/*
Function: viewServiceHistory
Description: Displays the customers past service bookings in tabular format,
including booking ID, technician, vehicle details, discount percentage, and status.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::viewServiceHistory() void CustomerMenu::viewServiceHistory()
{ {
util::clear();
bool hasServiceHistory = false;
const User* currentUser = m_controller.getAuthenticatedUser();
std::string currentUserID = currentUser->getId();
util::Map<std::string, const ServiceBooking*> serviceBookingsByCurrentUser = m_controller.getServiceBookingsByUser(currentUserID);
std::cout << "View Service History" << std::endl;
if (serviceBookingsByCurrentUser.getSize() != 0)
{
std::cout << std::left
<< std::setw(15) << "Booking ID"
<< std::setw(20) << "Technician"
<< std::setw(20) << "Vehicle Brand"
<< std::setw(20) << "Vehicle Number"
<< std::setw(20) << "Vehicle Model"
<< std::setw(20) << "Discount %"
<< std::setw(20) << "Status"
<< std::endl;
for (int iterator = 0; iterator < serviceBookingsByCurrentUser.getSize(); iterator++)
{
const ServiceBooking* currentBooking = serviceBookingsByCurrentUser.getValueAt(iterator);
std::string technicianName = currentBooking->getAssignedTechnician() == nullptr
? "Not Assigned"
: currentBooking->getAssignedTechnician()->getName();
std::cout << std::left
<< std::setw(15) << currentBooking->getId()
<< std::setw(20) << technicianName
<< std::setw(20) << currentBooking->getVehicleBrand()
<< std::setw(20) << currentBooking->getVehicleNumber()
<< std::setw(20) << currentBooking->getVehicleModel()
<< std::setw(20) << currentBooking->getDiscountPercentage()
<< std::setw(20) << util::getServiceJobStatusString(currentBooking->getStatus())
<< std::endl;
hasServiceHistory = true;
}
}
if (!hasServiceHistory)
{
std::cout << "No history available." << std::endl;
}
util::pressEnter();
} }
/*
Function: completePayments
Description: Allows the customer to complete pending payments for invoices.
Validates invoice selection and payment mode before completing payment.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::completePayments() void CustomerMenu::completePayments()
{ {
util::clear();
std::cout << "Complete Payments\n";
util::Map<std::string, const Invoice*> currentInvoices = m_controller.getInvoicesByUser();
if (currentInvoices.isEmpty())
{
std::cout << "No pending invoices available for payment.\n";
util::pressEnter();
return;
}
bool hasPending = false;
for (int index = 0; index < currentInvoices.getSize(); ++index)
{
const Invoice* invoice = currentInvoices.getValueAt(index);
if (invoice && invoice->getStatus() == util::PaymentStatus::PENDING)
{
hasPending = true;
break;
}
}
if (!hasPending)
{
std::cout << "No pending invoices available for payment.\n";
util::pressEnter();
return;
}
std::string selectedID = selectInvoiceFromUserForPayment(currentInvoices, util::PaymentStatus::PENDING);
if (selectedID == "")
{
std::cout << "Payment failed.\n";
util::pressEnter();
return;
}
util::PaymentMode paymentMode = selectPaymentMode();
m_controller.completePayment(selectedID, paymentMode);
std::cout << "Payment completed successfully.\n";
util::pressEnter();
} }
/*
Function: viewInvoices
Description: Displays invoices associated with the customer by calling displayInvoices.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::viewInvoices() void CustomerMenu::viewInvoices()
{ {
util::clear();
std::cout << "View Invoices\n";
util::Map<std::string, const Invoice*> currentUserInvoices = m_controller.getInvoicesByUser();
displayInvoices(currentUserInvoices);
util::pressEnter();
} }
/* /*
@@ -380,6 +357,38 @@ void CustomerMenu::viewNotifications()
viewAndDeleteNotification(m_controller); viewAndDeleteNotification(m_controller);
} }
/*
Function: getNotificationPreference (static helper)
Description: Helper function to configure notification preferences for a specific service.
Parameters:
- serviceName: Name of the service for which notifications are being configured.
Returns:
- bool: True if notifications are enabled, False if disabled.
*/
static bool getNotificationPreference(const std::string& serviceName)
{
int choice;
while (true)
{
util::clear();
std::cout << " Configure Notification Preferences\n";
std::cout << "\n" << serviceName << " Notifications\n";
std::cout << "1. Enable Notifications\n";
std::cout << "2. Disable Notifications\n";
std::cout << "Enter your choice: ";
util::read(choice);
if (choice == 1)
{
return true;
}
if (choice == 2)
{
return false;
}
std::cout << "\nInvalid choice. Please enter 1 or 2.\n";
util::pressEnter();
}
}
/* /*
Function: configureNotifications Function: configureNotifications
@@ -397,4 +406,4 @@ void CustomerMenu::configureNotifications()
util::clear(); util::clear();
std::cout << "Notification preferences updated successfully.\n"; std::cout << "Notification preferences updated successfully.\n";
util::pressEnter(); util::pressEnter();
} }
@@ -7,7 +7,6 @@ Description: Header file declaring the CustomerMenu class, which provides
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include "Controller.h" #include "Controller.h"
File diff suppressed because it is too large Load Diff
@@ -1,20 +1,16 @@
/* /*
File: TechnicianMenu.cpp File: TechnicianMenu.cpp
Description: Implementation file containing the method definitions of the Description: Implements the TechnicianMenu class which provides the technicians console interface
TechnicianMenu class, including menu handling, job completion, in the Vehicle Service Management System. Handles menu display, user input, and
notification viewing, password management, and logout logic. technician-specific operations such as completing jobs and viewing notifications.
Author: Trenser Author: Trenser
Date:19-May-2026 Date: 19-May-2026
*/ */
#include "Enums.h"
#include "InputHelper.h"
#include "JobCard.h"
#include "MenuHelper.h"
#include "OutputHelper.h"
#include "Service.h"
#include "TechnicianMenu.h" #include "TechnicianMenu.h"
#include "Validator.h" #include "InputHelper.h"
#include "OutputHelper.h"
#include "MenuHelper.h"
/* /*
Function: showMenu Function: showMenu
@@ -27,124 +23,35 @@ Returns:
*/ */
void TechnicianMenu::showMenu() void TechnicianMenu::showMenu()
{ {
while (true) bool isMenuActive = true;
{ while (isMenuActive)
try {
{ try
int choice; {
util::clear(); int choice;
std::cout << "Technician Menu" util::clear();
<< "\n1. Display My Jobs" std::cout << "" << std::endl;
<< "\n2. Update Job Status" util::read(choice);
<< "\n3. View Notifications" if (!handleOperation(choice))
<< "\n4. Change Password" {
<< "\n5. Logout" isMenuActive = false;
<< "\nEnter a choice: "; }
util::read(choice); }
if (!handleOperation(choice)) catch (const std::exception& e)
{ {
break; std::cout << "Exception: " << e.what() << std::endl;
} util::pressEnter();
} }
catch (const std::exception& e) }
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
}
}
} }
/*
Function: handleOperation
Description: Executes the corresponding technician operation based on the selected menu choice.
Parameter: int choice - selected menu option
Return type: bool - true if menu continues, false if logout
*/
bool TechnicianMenu::handleOperation(int choice) bool TechnicianMenu::handleOperation(int choice)
{ {
switch (choice) return false;
{
case 1:
displayJobs();
break;
case 2:
updateJobStatus();
break;
case 3:
viewNotifications();
break;
case 4:
changePassword();
break;
case 5:
logout();
return false;
default:
std::cout << "Enter a valid choice!" << std::endl;
util::pressEnter();
}
return true;
} }
/* void TechnicianMenu::completeJob()
Function: displayJobs
Description: Displays all Jobs assigned to a Technician
Parameters:
- None
Returns:
- void
*/
void TechnicianMenu::displayJobs()
{ {
util::clear();
std::cout << "My Jobs\n";
util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
util::Map<std::string, const JobCard*> jobCards = filterStartedJobCards(assignedJobCards);
displayAllJobs(jobCards);
util::pressEnter();
}
/*
Function: updateJobStatus
Description: Allows the technician to update a selected job card.
Validates selection and updates job status through the controller.
Parameters:
- None
Returns:
- void
*/
void TechnicianMenu::updateJobStatus()
{
util::clear();
std::cout << "Update Job Status\n";
int choice;
std::string selectedJobID;
util::ServiceJobStatus selectedJobStatus = util::ServiceJobStatus::PENDING;
util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
std::cout << "Select the type of job you want to update:\n1.Started\n2.In Progress\nChoice: ";
util::read(choice);
if (choice == 1)
{
selectedJobStatus = util::ServiceJobStatus::STARTED;
}
else if (choice == 2)
{
selectedJobStatus = util::ServiceJobStatus::IN_PROGRESS;
}
else
{
std::cout << "Invalid choice. Please try again.\n";
util::pressEnter();
return;
}
util::Map<std::string, const JobCard*> selectedTypeJobCard = filterJobCards(assignedJobCards, selectedJobStatus);
selectedJobID = selectJobCardToUpdate(selectedTypeJobCard, selectedJobStatus);
if (!selectedJobID.empty())
{
m_controller.updateJobStatus(selectedJobID);
std::cout << "\nJob status updated.\n\n";
}
util::pressEnter();
} }
/* /*
@@ -159,26 +66,3 @@ void TechnicianMenu::viewNotifications()
{ {
viewAndDeleteNotification(m_controller); viewAndDeleteNotification(m_controller);
} }
/*
Function: logout
Description: Logs out the currently authenticated technician user.
Parameter: None
Return type: void
*/
void TechnicianMenu::logout()
{
m_controller.logout();
}
/*
Function: changePassword
Description: Allows the technician to change their password after validation.
Parameter: None
Return type: void
*/
void TechnicianMenu::changePassword()
{
changePasswordHelper(m_controller);
}
@@ -1,10 +1,9 @@
/* /*
File: TechnicianMenu.h File: TechnicianMenu.h
Description: Header file declaring the TechnicianMenu class, which provides Description: Declares the TechnicianMenu class which provides the technician-facing console menu in the Vehicle Service Management System.
technician operations such as job completion, notification viewing, Supports operations such as viewing assigned jobs, completing jobs, and managing notifications.
password management, and logout functionality.
Author: Trenser Author: Trenser
Date:19-May-2026 Date: 19-May-2026
*/ */
#pragma once #pragma once
@@ -17,9 +16,6 @@ private:
bool handleOperation(int choice); bool handleOperation(int choice);
public: public:
void showMenu(); void showMenu();
void displayJobs(); void completeJob();
void updateJobStatus();
void viewNotifications(); void viewNotifications();
void logout(); };
void changePassword();
};
@@ -6,14 +6,11 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include "UserInterface.h"
#include <iostream>
#include <stdexcept>
#include "Enums.h"
#include "InputHelper.h" #include "InputHelper.h"
#include "OutputHelper.h" #include "OutputHelper.h"
#include "Enums.h"
#include "User.h" #include "User.h"
#include "UserInterface.h"
#include "Validator.h" #include "Validator.h"
/* /*
@@ -25,47 +22,29 @@ Return type: void
*/ */
void UserInterface::run() void UserInterface::run()
{ {
try m_controller.loadSystemData();
m_controller.runSystemChecks();
bool isMenuActive = true;
while (isMenuActive)
{ {
if (!m_controller.initialize()) try
{ {
std::cout << "Error: Failed to initialize the system!"; int choice;
return; util::clear();
} std::cout << "Vehicle Service System\n1. Login\n2. Register Customer\n3. Exit\nEnter your Choice: ";
bool isMenuActive = true; util::read(choice);
while (isMenuActive) if (!handleOperation(choice))
{
try
{ {
int choice; isMenuActive = false;
util::clear();
std::cout << "Vehicle Service System\n1. Login\n2. Register Customer\n3. Exit\nEnter your Choice: ";
util::read(choice);
if (!handleOperation(choice))
{
isMenuActive = false;
}
}
catch (const std::exception& e)
{
std::cout << "Exception: " << e.what() << std::endl;
util::pressEnter();
} }
} }
m_controller.shutdown(); catch (const std::exception& e)
} {
catch (const std::invalid_argument& exception) std::cout << "Exception: " << e.what() << std::endl;
{ util::pressEnter();
std::cout << "Exception: Invalid Argument: " << exception.what() << std::endl; }
}
catch (const std::exception& exception)
{
std::cout << "Exception: " << exception.what() << std::endl;
}
catch (...)
{
std::cout << "Unknown error occurred." << std::endl;
} }
m_controller.saveSystemData();
} }
/* /*
@@ -105,15 +84,14 @@ void UserInterface::login()
{ {
std::string username, password; std::string username, password;
util::clear(); util::clear();
std::cout << "Login\n";
std::cout << "Enter username: "; std::cout << "Enter username: ";
util::read(username); util::read(username);
std::cout << "Enter password: "; std::cout << "Enter password: ";
util::readPassword(password); util::read(password);
if (m_controller.login(username, password)) if (m_controller.login(username, password))
{ {
const User* authenticatedUser = m_controller.getAuthenticatedUser(); const User* authenticatedUser = m_controller.getAuthenticatedUser();
if (authenticatedUser && authenticatedUser->getState() != util::State::INACTIVE) if (authenticatedUser != nullptr)
{ {
switch (authenticatedUser->getUserType()) switch (authenticatedUser->getUserType())
{ {
@@ -131,16 +109,10 @@ void UserInterface::login()
break; break;
} }
} }
else if (authenticatedUser && authenticatedUser->getState() == util::State::INACTIVE)
{
std::cout << "\nError: Your account has been disabled. Please contact your Administrator.";
util::pressEnter();
}
} }
else else
{ {
std::cout << "\nError: Invalid Username or Password"; std::cout << "\nError: Invalid Username or Password";
util::pressEnter();
} }
} }
@@ -156,7 +128,6 @@ void UserInterface::registerCustomer()
{ {
std::string username, name, email, phone, password; std::string username, name, email, phone, password;
util::clear(); util::clear();
std::cout << "Register Customer\n";
std::cout << "Enter username: "; std::cout << "Enter username: ";
util::read(username); util::read(username);
std::cout << "Enter name: "; std::cout << "Enter name: ";
@@ -170,7 +141,7 @@ void UserInterface::registerCustomer()
return; return;
} }
std::cout << "Enter password: "; std::cout << "Enter password: ";
util::readPassword(password); util::read(password);
if (!util::isPasswordValid(password)) if (!util::isPasswordValid(password))
{ {
std::cout << "Error: Password is invalid!"; std::cout << "Error: Password is invalid!";
@@ -188,4 +159,4 @@ void UserInterface::registerCustomer()
m_controller.createCustomer(username, name, password, email, phone); m_controller.createCustomer(username, name, password, email, phone);
std::cout << "Registration is successful"; std::cout << "Registration is successful";
util::pressEnter(); util::pressEnter();
} }
@@ -7,7 +7,6 @@ Description: Header file declaring the UserInterface class, which provides
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#pragma once #pragma once
#include "Controller.h" #include "Controller.h"
#include "AdminMenu.h" #include "AdminMenu.h"
@@ -27,4 +26,4 @@ public:
void run(); void run();
void login(); void login();
void registerCustomer(); void registerCustomer();
}; };