Merge branch 'feature-file-management' into feature

This commit is contained in:
2026-05-22 16:25:59 +05:30
41 changed files with 1566 additions and 70 deletions
@@ -173,9 +173,12 @@
<ClInclude Include="services\UserManagementService.h" /> <ClInclude Include="services\UserManagementService.h" />
<ClInclude Include="utilities\Config.h" /> <ClInclude Include="utilities\Config.h" />
<ClInclude Include="utilities\Enums.h" /> <ClInclude Include="utilities\Enums.h" />
<ClInclude Include="utilities\FileHelper.h" />
<ClInclude Include="utilities\FileManager.h" />
<ClInclude Include="utilities\InputHelper.h" /> <ClInclude Include="utilities\InputHelper.h" />
<ClInclude Include="utilities\Map.h" /> <ClInclude Include="utilities\Map.h" />
<ClInclude Include="utilities\OutputHelper.h" /> <ClInclude Include="utilities\OutputHelper.h" />
<ClInclude Include="utilities\StringHelper.h" />
<ClInclude Include="utilities\Timestamp.h" /> <ClInclude Include="utilities\Timestamp.h" />
<ClInclude Include="utilities\Utility.h" /> <ClInclude Include="utilities\Utility.h" />
<ClInclude Include="utilities\Validator.h" /> <ClInclude Include="utilities\Validator.h" />
@@ -242,5 +242,14 @@
<ClInclude Include="utilities\Config.h"> <ClInclude Include="utilities\Config.h">
<Filter>Header Files\Utilities</Filter> <Filter>Header Files\Utilities</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="utilities\FileManager.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="utilities\StringHelper.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
<ClInclude Include="utilities\FileHelper.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -423,6 +423,34 @@ void Controller::configureNotifications(bool paymentNotifications, bool serviceN
} }
} }
void Controller::loadSystemData()
{
m_userManagementService.loadUsers();
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();
}
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 Function: runSystemChecks
Description: Executes system checks including sending low stock alerts Description: Executes system checks including sending low stock alerts
@@ -67,5 +67,7 @@ public:
util::Vector<const Notification*> getNotifications(); util::Vector<const Notification*> getNotifications();
void deleteNotification(const std::string& notificationID); void deleteNotification(const std::string& notificationID);
void configureNotifications(bool paymentNotifications, bool serviceNotifications); void configureNotifications(bool paymentNotifications, bool serviceNotifications);
void loadSystemData();
void saveSystemData();
void runSystemChecks(); void runSystemChecks();
}; };
@@ -8,6 +8,7 @@ Date: 19-May-2026
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
#include "Vector.h"
class User; class User;
class Notification; class Notification;
@@ -0,0 +1 @@
Place files here.
@@ -7,7 +7,12 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#include <sstream>
#include <stdexcept>
#include "ComboPackage.h" #include "ComboPackage.h"
#include "Service.h"
#include "Factory.h"
#include "StringHelper.h"
int ComboPackage::m_uid = 0; int ComboPackage::m_uid = 0;
@@ -41,7 +46,29 @@ ComboPackage::ComboPackage(const std::string& packageName, double discountPercen
m_packageName(packageName), m_packageName(packageName),
m_discountPercentage(discountPercentage), m_discountPercentage(discountPercentage),
m_status(util::State::ACTIVE), m_status(util::State::ACTIVE),
m_services(services) {} m_services(services)
{
int numberOfServices = m_services.getSize();
auto servicePointers = m_services.getValues();
for (int index = 0; index < numberOfServices; index++)
{
m_serviceIDs.push_back(servicePointers[index]->getId());
}
}
ComboPackage::ComboPackage(const std::string& id, const std::string& packageName, double discountPercentage, const util::Vector<std::string>& serviceIDs, util::State status)
: m_id(id),
m_packageName(packageName),
m_discountPercentage(discountPercentage),
m_serviceIDs(serviceIDs),
m_status(status)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/* /*
Function: getId Function: getId
@@ -95,6 +122,11 @@ util::State ComboPackage::getState() const
return m_status; return m_status;
} }
const util::Vector<std::string>& ComboPackage::getServiceIDs() const
{
return m_serviceIDs;
}
/* /*
Function: getServices Function: getServices
Description: Retrieves the map of services included in the combo package. Description: Retrieves the map of services included in the combo package.
@@ -158,6 +190,13 @@ Returns:
void ComboPackage::setServices(const util::Map<std::string, Service*>& services) void ComboPackage::setServices(const util::Map<std::string, Service*>& services)
{ {
m_services = services; m_services = services;
m_serviceIDs.clear();
int numberOfServices = m_services.getSize();
auto servicePointers = m_services.getValues();
for (int index = 0; index < numberOfServices; index++)
{
m_serviceIDs.push_back(servicePointers[index]->getId());
}
} }
/* /*
@@ -172,3 +211,76 @@ void ComboPackage::setState(util::State status)
{ {
m_status = status; m_status = status;
} }
static std::string getServiceIDsAsString(const util::Vector<std::string>& serviceIDs)
{
int numberOfServices = serviceIDs.getSize();
std::string serviceIDsString;
for (int index = 0; index < numberOfServices; index++)
{
serviceIDsString += serviceIDs[index];
if (index < numberOfServices - 1)
{
serviceIDsString += '|';
}
}
return serviceIDsString;
}
static util::Vector<std::string> getServiceIDsAsVector(const std::string& serviceIDsString)
{
util::Vector<std::string> serviceIDs;
std::string serviceID;
std::istringstream serializedServiceIDs(serviceIDsString);
while (getline(serializedServiceIDs, serviceID, '|'))
{
serviceIDs.push_back(serviceID);
}
return serviceIDs;
}
std::string ComboPackage::serialize() const
{
std::ostringstream serializedComboPackage;
serializedComboPackage << m_id << ','
<< m_packageName << ','
<< m_discountPercentage << ','
<< getServiceIDsAsString(m_serviceIDs) << ','
<< util::getStateString(m_status);
return serializedComboPackage.str();
}
ComboPackage* ComboPackage::deserialize(const std::string& record)
{
std::string id, packageName;
std::string discountPercentageString, serviceIDsString, statusString;
double discountPercentage;
std::istringstream serializedComboPackage(record);
getline(serializedComboPackage, id, ',');
getline(serializedComboPackage, packageName, ',');
getline(serializedComboPackage, discountPercentageString, ',');
getline(serializedComboPackage, serviceIDsString, ',');
getline(serializedComboPackage, statusString, ',');
try
{
discountPercentage = std::stod(discountPercentageString);
}
catch (...)
{
throw std::runtime_error("Invalid combo package data");
}
util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serviceIDsString);
util::State status = util::getState(statusString);
return Factory::getObject<ComboPackage>(
id,
packageName,
discountPercentage,
serviceIDs,
status
);
}
std::string ComboPackage::getHeaders()
{
return "ID,PackageName,DiscountPercentage,ServiceIDs,Status";
}
@@ -8,6 +8,7 @@ Date: 19-May-2026
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
#include "Vector.h"
#include "Enums.h" #include "Enums.h"
class Service; class Service;
@@ -19,14 +20,17 @@ private:
std::string m_id; std::string m_id;
std::string m_packageName; std::string m_packageName;
double m_discountPercentage; double m_discountPercentage;
util::Vector<std::string> m_serviceIDs;
util::Map<std::string, Service*> m_services; util::Map<std::string, Service*> m_services;
util::State m_status; util::State m_status;
public: public:
ComboPackage(); ComboPackage();
ComboPackage(const std::string& packageName, double discountPercentage, const util::Map<std::string, Service*>& services); ComboPackage(const std::string& packageName, double discountPercentage, const util::Map<std::string, Service*>& services);
ComboPackage(const std::string& id, const std::string& packageName, double discountPercentage, const util::Vector<std::string>& serviceIDs, util::State status);
const std::string& getId() const; const std::string& getId() const;
const std::string& getPackageName() const; const std::string& getPackageName() const;
double getDiscountPercentage() const; double getDiscountPercentage() const;
const util::Vector<std::string>& getServiceIDs() const;
const util::Map<std::string, Service*>& getServices() const; const util::Map<std::string, Service*>& getServices() const;
util::State getState() const; util::State getState() const;
void setId(const std::string& id); void setId(const std::string& id);
@@ -34,4 +38,7 @@ public:
void setDiscountPercentage(double discountPercentage); void setDiscountPercentage(double discountPercentage);
void setServices(const util::Map<std::string, Service*>& services); void setServices(const util::Map<std::string, Service*>& services);
void setState(util::State status); void setState(util::State status);
std::string serialize() const;
static ComboPackage* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -6,7 +6,11 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#include <sstream>
#include <stdexcept>
#include "InventoryItem.h" #include "InventoryItem.h"
#include "Factory.h"
#include "StringHelper.h"
int InventoryItem::m_uid = 0; int InventoryItem::m_uid = 0;
@@ -43,6 +47,20 @@ InventoryItem::InventoryItem(const std::string& partName, int quantity, double p
m_status(util::State::ACTIVE), m_status(util::State::ACTIVE),
m_price(price) {} m_price(price) {}
InventoryItem::InventoryItem(const std::string& id, const std::string& partName, int quantity, double price, util::State status)
: m_id(id),
m_partName(partName),
m_quantity(quantity),
m_status(status),
m_price(price)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/* /*
Function: getId Function: getId
Description: Retrieves the unique ID of the inventory item. Description: Retrieves the unique ID of the inventory item.
@@ -172,3 +190,50 @@ void InventoryItem::setState(util::State status)
{ {
m_status = status; m_status = status;
} }
std::string InventoryItem::serialize() const
{
std::ostringstream serializedInventoryItem;
serializedInventoryItem << m_id << ','
<< m_partName << ','
<< m_quantity << ','
<< m_price << ','
<< util::getStateString(m_status);
return serializedInventoryItem.str();
}
InventoryItem* InventoryItem::deserialize(const std::string& record)
{
std::string id, partName;
std::string quantityString, priceString, statusString;
int quantity;
double price;
std::istringstream serializedInventoryItem(record);
getline(serializedInventoryItem, id, ',');
getline(serializedInventoryItem, partName, ',');
getline(serializedInventoryItem, quantityString, ',');
getline(serializedInventoryItem, priceString, ',');
getline(serializedInventoryItem, statusString, ',');
try
{
quantity = std::stoi(quantityString);
price = std::stod(priceString);
}
catch (...)
{
throw std::runtime_error("Invalid inventory item data");
}
util::State status = util::getState(statusString);
return Factory::getObject<InventoryItem>(
id,
partName,
quantity,
price,
status
);
}
std::string InventoryItem::getHeaders()
{
return "ID,PartName,Quantity,Price,Status";
}
@@ -23,6 +23,7 @@ private:
public: public:
InventoryItem(); InventoryItem();
InventoryItem(const std::string& partName, int quantity, double price); InventoryItem(const std::string& partName, int quantity, double price);
InventoryItem(const std::string& id, const std::string& partName, int quantity, double price, util::State status);
const std::string& getId() const; const std::string& getId() const;
const std::string& getPartName() const; const std::string& getPartName() const;
int getQuantity() const; int getQuantity() const;
@@ -33,4 +34,7 @@ public:
void setQuantity(int quantity); void setQuantity(int quantity);
void setPrice(double price); void setPrice(double price);
void setState(util::State status); void setState(util::State status);
std::string serialize() const;
static InventoryItem* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -7,7 +7,12 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#include <sstream>
#include <stdexcept>
#include "Invoice.h" #include "Invoice.h"
#include "Factory.h"
#include "InventoryItem.h"
#include "StringHelper.h"
int Invoice::m_uid = 0; int Invoice::m_uid = 0;
@@ -74,14 +79,49 @@ Invoice::Invoice(
m_totalAmount(totalAmount), m_totalAmount(totalAmount),
m_paymentDate(paymentDate), m_paymentDate(paymentDate),
m_paymentMethod(paymentMethod), m_paymentMethod(paymentMethod),
m_status(status) {} m_status(status)
{
int numberOfParts = m_parts.getSize();
auto partPointers = m_parts.getValues();
for (int index = 0; index < numberOfParts; index++)
{
m_partIDs.push_back(partPointers[index]->getId());
}
}
Invoice::Invoice(
const std::string& id,
const std::string& bookingId,
const util::Timestamp& invoiceDate,
const util::Vector<std::string>& partIDs,
double laborCost,
double partsCost,
double discountPercentage,
double totalAmount,
const util::Timestamp& paymentDate,
util::PaymentMode paymentMethod,
util::PaymentStatus status
)
: m_id(id),
m_bookingId(bookingId),
m_booking(nullptr),
m_invoiceDate(invoiceDate),
m_partIDs(partIDs),
m_laborCost(laborCost),
m_partsCost(partsCost),
m_discountPercentage(discountPercentage),
m_totalAmount(totalAmount),
m_paymentDate(paymentDate),
m_paymentMethod(paymentMethod),
m_status(status)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/*
Function: getId
Description: Retrieves the unique ID of the invoice.
Returns:
- const std::string& representing the invoice ID.
*/
const std::string& Invoice::getId() const const std::string& Invoice::getId() const
{ {
return m_id; return m_id;
@@ -131,6 +171,11 @@ double Invoice::getLaborCost() const
return m_laborCost; return m_laborCost;
} }
const util::Vector<std::string>& Invoice::getPartIDs() const
{
return m_partIDs;
}
/* /*
Function: getParts Function: getParts
Description: Retrieves the map of inventory items used in the service. Description: Retrieves the map of inventory items used in the service.
@@ -284,6 +329,13 @@ Returns:
void Invoice::setParts(const util::Map<std::string, InventoryItem*>& parts) void Invoice::setParts(const util::Map<std::string, InventoryItem*>& parts)
{ {
m_parts = parts; m_parts = parts;
m_partIDs.clear();
int numberOfParts = m_parts.getSize();
auto partPointers = m_parts.getValues();
for (int index = 0; index < numberOfParts; index++)
{
m_partIDs.push_back(partPointers[index]->getId());
}
} }
/* /*
@@ -363,3 +415,104 @@ void Invoice::setStatus(util::PaymentStatus status)
{ {
m_status = status; m_status = status;
} }
static std::string getPartIDsAsString(const util::Vector<std::string>& partIDs)
{
int numberOfParts = partIDs.getSize();
std::string partIDsString;
for (int index = 0; index < numberOfParts; index++)
{
partIDsString += partIDs[index];
if (index < numberOfParts - 1)
{
partIDsString += '|';
}
}
return partIDsString;
}
static util::Vector<std::string> getPartIDsAsVector(const std::string& partIDsString)
{
util::Vector<std::string> partIDs;
std::string partID;
std::istringstream serializedPartIDs(partIDsString);
while (getline(serializedPartIDs, partID, '|'))
{
partIDs.push_back(partID);
}
return partIDs;
}
std::string Invoice::serialize() const
{
std::ostringstream serializedInvoice;
serializedInvoice << m_id << ','
<< m_bookingId << ','
<< m_invoiceDate.toString() << ','
<< m_laborCost << ','
<< getPartIDsAsString(m_partIDs) << ','
<< m_partsCost << ','
<< m_discountPercentage << ','
<< m_totalAmount << ','
<< m_paymentDate.toString() << ','
<< util::getPaymentModeString(m_paymentMethod) << ','
<< util::getPaymentStatusString(m_status);
return serializedInvoice.str();
}
Invoice* Invoice::deserialize(const std::string& record)
{
std::string id, bookingId;
std::string invoiceDateString, laborCostString, partIDsString;
std::string partsCostString, discountPercentageString, totalAmountString;
std::string paymentDateString, paymentMethodString, statusString;
double laborCost, partsCost, discountPercentage, totalAmount;
std::istringstream serializedInvoice(record);
getline(serializedInvoice, id, ',');
getline(serializedInvoice, bookingId, ',');
getline(serializedInvoice, invoiceDateString, ',');
getline(serializedInvoice, laborCostString, ',');
getline(serializedInvoice, partIDsString, ',');
getline(serializedInvoice, partsCostString, ',');
getline(serializedInvoice, discountPercentageString, ',');
getline(serializedInvoice, totalAmountString, ',');
getline(serializedInvoice, paymentDateString, ',');
getline(serializedInvoice, paymentMethodString, ',');
getline(serializedInvoice, statusString, ',');
util::Timestamp invoiceDate;
util::Timestamp paymentDate;
try
{
invoiceDate = util::Timestamp::fromString(invoiceDateString);
paymentDate = util::Timestamp::fromString(paymentDateString);
laborCost = std::stod(laborCostString);
partsCost = std::stod(partsCostString);
discountPercentage = std::stod(discountPercentageString);
totalAmount = std::stod(totalAmountString);
}
catch (...)
{
throw std::runtime_error("Invalid invoice data");
}
util::Vector<std::string> partIDs = getPartIDsAsVector(partIDsString);
util::PaymentMode paymentMethod = util::getPaymentMode(paymentMethodString);
util::PaymentStatus status = util::getPaymentStatus(statusString);
return Factory::getObject<Invoice>(
id,
bookingId,
invoiceDate,
partIDs,
laborCost,
partsCost,
discountPercentage,
totalAmount,
paymentDate,
paymentMethod,
status
);
}
std::string Invoice::getHeaders()
{
return "ID,BookingID,InvoiceDate,LaborCost,PartIDs,PartsCost,DiscountPercentage,TotalAmount,PaymentDate,PaymentMethod,Status";
}
@@ -10,6 +10,7 @@ Date: 19-May-2026
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
#include "Vector.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "Enums.h" #include "Enums.h"
@@ -25,6 +26,7 @@ private:
ServiceBooking* m_booking; ServiceBooking* m_booking;
util::Timestamp m_invoiceDate; util::Timestamp m_invoiceDate;
double m_laborCost; double m_laborCost;
util::Vector<std::string> m_partIDs;
util::Map<std::string, InventoryItem*> m_parts; util::Map<std::string, InventoryItem*> m_parts;
double m_partsCost; double m_partsCost;
double m_discountPercentage; double m_discountPercentage;
@@ -32,7 +34,6 @@ private:
util::Timestamp m_paymentDate; util::Timestamp m_paymentDate;
util::PaymentMode m_paymentMethod; util::PaymentMode m_paymentMethod;
util::PaymentStatus m_status; util::PaymentStatus m_status;
public: public:
Invoice(); Invoice();
Invoice( Invoice(
@@ -48,11 +49,25 @@ public:
util::PaymentMode paymentMethod, util::PaymentMode paymentMethod,
util::PaymentStatus status util::PaymentStatus status
); );
Invoice(
const std::string& id,
const std::string& bookingId,
const util::Timestamp& invoiceDate,
const util::Vector<std::string>& partIDs,
double laborCost,
double partsCost,
double discountPercentage,
double totalAmount,
const util::Timestamp& paymentDate,
util::PaymentMode paymentMethod,
util::PaymentStatus status
);
const std::string& getId() const; const std::string& getId() const;
const std::string& getBookingId() const; const std::string& getBookingId() const;
ServiceBooking* getBooking() const; ServiceBooking* getBooking() const;
const util::Timestamp& getInvoiceDate() const; const util::Timestamp& getInvoiceDate() const;
double getLaborCost() const; double getLaborCost() const;
const util::Vector<std::string>& getPartIDs() const;
const util::Map<std::string, InventoryItem*>& getParts() const; const util::Map<std::string, InventoryItem*>& getParts() const;
double getPartsCost() const; double getPartsCost() const;
double getDiscountPercentage() const; double getDiscountPercentage() const;
@@ -72,4 +87,7 @@ public:
void setPaymentDate(const util::Timestamp& paymentDate); void setPaymentDate(const util::Timestamp& paymentDate);
void setPaymentMethod(util::PaymentMode paymentMethod); void setPaymentMethod(util::PaymentMode paymentMethod);
void setStatus(util::PaymentStatus status); void setStatus(util::PaymentStatus status);
std::string serialize() const;
static Invoice* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -6,7 +6,12 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <sstream>
#include <stdexcept>
#include "JobCard.h" #include "JobCard.h"
#include "Factory.h"
#include "StringHelper.h"
#include "Enums.h"
int JobCard::m_uid = 0; int JobCard::m_uid = 0;
@@ -62,6 +67,32 @@ JobCard::JobCard(const std::string& bookingId,
m_status(status), m_status(status),
m_completionDate(completionDate) {} m_completionDate(completionDate) {}
JobCard::JobCard(const std::string& id,
const std::string& bookingId,
const std::string& serviceId,
const std::string& technicianId,
const util::Timestamp& assignedDate,
util::ServiceJobStatus status,
const util::Timestamp& completionDate
)
: m_id(id),
m_bookingId(bookingId),
m_booking(nullptr),
m_service(nullptr),
m_serviceId(serviceId),
m_technicianId(technicianId),
m_technician(nullptr),
m_assignedDate(assignedDate),
m_status(status),
m_completionDate(completionDate)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/* /*
Function: getId Function: getId
Description: Retrieves the unique ID of the job card. Description: Retrieves the unique ID of the job card.
@@ -299,3 +330,56 @@ void JobCard::setCompletionDate(const util::Timestamp& completionDate)
{ {
m_completionDate = completionDate; m_completionDate = completionDate;
} }
std::string JobCard::serialize() const
{
std::ostringstream serializedJobCard;
serializedJobCard << m_id << ','
<< m_bookingId << ','
<< m_serviceId << ','
<< m_technicianId << ','
<< m_assignedDate.toString() << ','
<< util::getServiceJobStatusString(m_status) << ','
<< m_completionDate.toString();
return serializedJobCard.str();
}
JobCard* JobCard::deserialize(const std::string& record)
{
std::string id, bookingId, serviceId, technicianId;
std::string assignedDateString, statusString, completionDateString;
std::istringstream serializedJobCard(record);
getline(serializedJobCard, id, ',');
getline(serializedJobCard, bookingId, ',');
getline(serializedJobCard, serviceId, ',');
getline(serializedJobCard, technicianId, ',');
getline(serializedJobCard, assignedDateString, ',');
getline(serializedJobCard, statusString, ',');
getline(serializedJobCard, completionDateString, ',');
util::Timestamp assignedDate;
util::Timestamp completionDate;
try
{
assignedDate = util::Timestamp::fromString(assignedDateString);
completionDate = util::Timestamp::fromString(completionDateString);
}
catch (...)
{
throw std::runtime_error("Invalid timestamp");
}
util::ServiceJobStatus status = util::getServiceJobStatus(statusString);
return Factory::getObject<JobCard>(
id,
bookingId,
serviceId,
technicianId,
assignedDate,
status,
completionDate
);
}
std::string JobCard::getHeaders()
{
return "ID,BookingID,ServiceID,TechnicianID,AssignedDate,Status,CompletionDate";
}
@@ -42,6 +42,14 @@ public:
util::ServiceJobStatus status, util::ServiceJobStatus status,
const util::Timestamp& completionDate const util::Timestamp& completionDate
); );
JobCard(const std::string& id,
const std::string& bookingId,
const std::string& serviceId,
const std::string& technicianId,
const util::Timestamp& assignedDate,
util::ServiceJobStatus status,
const util::Timestamp& completionDate
);
const std::string& getId() const; const std::string& getId() const;
const std::string& getBookingId() const; const std::string& getBookingId() const;
ServiceBooking* getBooking() const; ServiceBooking* getBooking() const;
@@ -62,4 +70,7 @@ public:
void setAssignedDate(const util::Timestamp& assignedDate); void setAssignedDate(const util::Timestamp& assignedDate);
void setStatus(util::ServiceJobStatus status); void setStatus(util::ServiceJobStatus status);
void setCompletionDate(const util::Timestamp& completionDate); void setCompletionDate(const util::Timestamp& completionDate);
std::string serialize() const;
static JobCard* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -6,7 +6,10 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#include <sstream>
#include "Notification.h" #include "Notification.h"
#include "StringHelper.h"
#include "Factory.h"
int Notification::m_uid = 0; int Notification::m_uid = 0;
@@ -42,6 +45,21 @@ Notification::Notification(const std::string& recipientUserId, User* recipient,
m_message(message), m_message(message),
m_createdAt(createdAt) {} m_createdAt(createdAt) {}
Notification::Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt)
: m_id(id),
m_recipientUserId(recipientUserId),
m_recipient(nullptr),
m_title(title),
m_message(message),
m_createdAt(createdAt)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/* /*
Function: getId Function: getId
Description: Retrieves the unique ID of the notification. Description: Retrieves the unique ID of the notification.
@@ -185,3 +203,46 @@ void Notification::setCreatedAt(const util::Timestamp& createdAt)
{ {
m_createdAt = createdAt; m_createdAt = createdAt;
} }
std::string Notification::serialize() const
{
std::ostringstream serializedNotification;
serializedNotification << m_id << ','
<< m_recipientUserId << ','
<< m_title << ','
<< m_message << ','
<< m_createdAt.toString();
return serializedNotification.str();
}
Notification* Notification::deserialize(const std::string& record)
{
std::string id, recipientUserId, title, message, createdAtTimestampString;
std::istringstream serializedNotification(record);
getline(serializedNotification, id, ',');
getline(serializedNotification, recipientUserId, ',');
getline(serializedNotification, title, ',');
getline(serializedNotification, message, ',');
getline(serializedNotification, createdAtTimestampString, ',');
util::Timestamp createdAtTimestamp;
try
{
createdAtTimestamp = util::Timestamp::fromString(createdAtTimestampString);
}
catch (...)
{
throw std::runtime_error("Invalid createdAt timestamp");
}
return Factory::getObject<Notification>(
id,
recipientUserId,
title,
message,
createdAtTimestamp
);
}
std::string Notification::getHeaders()
{
return "ID,RecipientID,Title,Message,Timestamp";
}
@@ -25,6 +25,7 @@ private:
public: public:
Notification(); Notification();
Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt); Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt);
Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt);
const std::string& getId() const; const std::string& getId() const;
const std::string& getRecipientUserId() const; const std::string& getRecipientUserId() const;
User* getRecipient() const; User* getRecipient() const;
@@ -37,4 +38,7 @@ public:
void setTitle(const std::string& title); void setTitle(const std::string& title);
void setMessage(const std::string& message); void setMessage(const std::string& message);
void setCreatedAt(const util::Timestamp& createdAt); void setCreatedAt(const util::Timestamp& createdAt);
std::string serialize() const;
static Notification* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -7,7 +7,11 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#include <sstream>
#include "Service.h" #include "Service.h"
#include "InventoryItem.h"
#include "StringHelper.h"
#include "Factory.h"
int Service::m_uid = 0; int Service::m_uid = 0;
@@ -40,7 +44,29 @@ Service::Service(const std::string& name, const util::Map<std::string, Inventory
m_name(name), m_name(name),
m_requiredInventoryItems(requiredInventoryItems), m_requiredInventoryItems(requiredInventoryItems),
m_status(util::State::ACTIVE), m_status(util::State::ACTIVE),
m_laborCost(laborCost) {} m_laborCost(laborCost)
{
int numberOfInventoryItems = m_requiredInventoryItems.getSize();
auto inventoryItemPointers = m_requiredInventoryItems.getValues();
for (int index = 0; index < numberOfInventoryItems; index++)
{
m_requiredInventoryItemIDs.push_back(inventoryItemPointers[index]->getId());
}
}
Service::Service(const std::string& id, const std::string& name, const util::Vector<std::string>& requiredInventoryItemIDs, double laborCost, util::State status)
: m_id(id),
m_name(name),
m_requiredInventoryItemIDs(requiredInventoryItemIDs),
m_status(status),
m_laborCost(laborCost)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/* /*
Function: getId Function: getId
@@ -64,6 +90,11 @@ const std::string& Service::getName() const
return m_name; return m_name;
} }
const util::Vector<std::string>& Service::getRequiredInventoryItemIDs() const
{
return m_requiredInventoryItemIDs;
}
/* /*
Function: getRequiredInventoryItems Function: getRequiredInventoryItems
Description: Retrieves the map of inventory items required for the service. Description: Retrieves the map of inventory items required for the service.
@@ -134,6 +165,13 @@ Returns:
void Service::setRequiredInventoryItems(const util::Map<std::string, InventoryItem*>& requiredInventoryItems) void Service::setRequiredInventoryItems(const util::Map<std::string, InventoryItem*>& requiredInventoryItems)
{ {
m_requiredInventoryItems = requiredInventoryItems; m_requiredInventoryItems = requiredInventoryItems;
m_requiredInventoryItemIDs.clear();
int numberOfRequiredInventoryItems = m_requiredInventoryItems.getSize();
auto inventoryItemPointers = m_requiredInventoryItems.getValues();
for (int index = 0; index < numberOfRequiredInventoryItems; index++)
{
m_requiredInventoryItemIDs.push_back(inventoryItemPointers[index]->getId());
}
} }
/* /*
@@ -161,3 +199,76 @@ void Service::setState(util::State status)
{ {
m_status = status; m_status = status;
} }
static std::string getInventoryItemIDsAsString(const util::Vector<std::string>& inventoryItemIds)
{
int numberOfInventoryItems = inventoryItemIds.getSize();
std::string inventoryItemIDs;
for (int index = 0; index < numberOfInventoryItems; index++)
{
inventoryItemIDs += inventoryItemIds[index];
if (index < numberOfInventoryItems - 1)
{
inventoryItemIDs += '|';
}
}
return inventoryItemIDs;
}
static util::Vector<std::string> getInventoryItemIDsAsVector(const std::string& inventoryItemIDsString)
{
util::Vector<std::string> inventoryItemIDs;
std::string inventoryItemID;
std::istringstream serializedInventoryItemIDs(inventoryItemIDsString);
while (getline(serializedInventoryItemIDs, inventoryItemID, '|'))
{
inventoryItemIDs.push_back(inventoryItemID);
}
return inventoryItemIDs;
}
std::string Service::serialize() const
{
std::ostringstream serializedService;
serializedService << m_id << ','
<< m_name << ','
<< getInventoryItemIDsAsString(m_requiredInventoryItemIDs) << ','
<< m_laborCost << ','
<< util::getStateString(m_status);
return serializedService.str();
}
Service* Service::deserialize(const std::string& record)
{
std::string id, name;
std::string inventoryItemIDsString, laborCostString, statusString;
double laborCost;
std::istringstream serializedService(record);
getline(serializedService, id, ',');
getline(serializedService, name, ',');
getline(serializedService, inventoryItemIDsString, ',');
getline(serializedService, laborCostString, ',');
getline(serializedService, statusString, ',');
util::Vector<std::string> inventoryItemIDs = getInventoryItemIDsAsVector(inventoryItemIDsString);
try
{
laborCost = std::stod(laborCostString);
}
catch (...)
{
throw std::runtime_error("Invalid labor cost");
}
util::State status = util::getState(statusString);
return Factory::getObject<Service>(
id,
name,
inventoryItemIDs,
laborCost,
status
);
}
std::string Service::getHeaders()
{
return "ID,Name,InventoryIDs,LaborCost,Status";
}
@@ -10,6 +10,7 @@ Date: 19-May-2026
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
#include "Vector.h"
#include "Enums.h" #include "Enums.h"
class InventoryItem; class InventoryItem;
@@ -20,14 +21,17 @@ private:
static int m_uid; static int m_uid;
std::string m_id; std::string m_id;
std::string m_name; std::string m_name;
util::Vector<std::string> m_requiredInventoryItemIDs;
util::Map<std::string, InventoryItem*> m_requiredInventoryItems; util::Map<std::string, InventoryItem*> m_requiredInventoryItems;
double m_laborCost; double m_laborCost;
util::State m_status; util::State m_status;
public: public:
Service(); Service();
Service(const std::string& name, const util::Map<std::string, InventoryItem*>& requiredInventoryItems, double laborCost); Service(const std::string& name, const util::Map<std::string, InventoryItem*>& requiredInventoryItems, double laborCost);
Service(const std::string& id, const std::string& name, const util::Vector<std::string>& requiredInventoryItemIDs, double laborCost, util::State state);
const std::string& getId() const; const std::string& getId() const;
const std::string& getName() const; const std::string& getName() const;
const util::Vector<std::string>& getRequiredInventoryItemIDs() const;
const util::Map<std::string, InventoryItem*>& getRequiredInventoryItems() const; const util::Map<std::string, InventoryItem*>& getRequiredInventoryItems() const;
double getLaborCost() const; double getLaborCost() const;
util::State getState() const; util::State getState() const;
@@ -36,4 +40,7 @@ public:
void setRequiredInventoryItems(const util::Map<std::string, InventoryItem*>& requiredInventoryItems); void setRequiredInventoryItems(const util::Map<std::string, InventoryItem*>& requiredInventoryItems);
void setLaborCost(double laborCost); void setLaborCost(double laborCost);
void setState(util::State status); void setState(util::State status);
std::string serialize() const;
static Service* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -6,7 +6,13 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include <stdexcept>
#include <sstream>
#include "ServiceBooking.h" #include "ServiceBooking.h"
#include "Service.h"
#include "Enums.h"
#include "Factory.h"
#include "StringHelper.h"
int ServiceBooking::m_uid = 0; int ServiceBooking::m_uid = 0;
@@ -37,8 +43,6 @@ Parameter: const std::string& id - booking ID
const std::string& vehicleNumber - vehicle registration number const std::string& vehicleNumber - vehicle registration number
const std::string& vehicleBrand - brand of the vehicle const std::string& vehicleBrand - brand of the vehicle
const std::string& vehicleModel - model of the vehicle const std::string& vehicleModel - model of the vehicle
const std::string& assignedTechnicianId - ID of the assigned technician
User* assignedTechnician - pointer to the technician object
double discountPercentage - discount applied to the booking double discountPercentage - discount applied to the booking
Return type: Constructor Return type: Constructor
*/ */
@@ -65,14 +69,44 @@ ServiceBooking::ServiceBooking(
m_assignedTechnician(nullptr), m_assignedTechnician(nullptr),
m_discountPercentage(discountPercentage) m_discountPercentage(discountPercentage)
{ {
int numberOfServices = m_services.getSize();
auto servicePointers = m_services.getValues();
for (int index = 0; index < numberOfServices; index++)
{
m_serviceIDs.push_back(servicePointers[index]->getId());
}
}
ServiceBooking::ServiceBooking(
const std::string& id,
util::ServiceJobStatus status,
const util::Vector<std::string>& serviceIDs,
const std::string& customerId,
const std::string& vehicleNumber,
const std::string& vehicleBrand,
const std::string& vehicleModel,
const std::string& assignedTechnicianId,
double discountPercentage
)
: m_id(id),
m_status(status),
m_serviceIDs(serviceIDs),
m_customerId(customerId),
m_customer(nullptr),
m_vehicleNumber(vehicleNumber),
m_vehicleBrand(vehicleBrand),
m_vehicleModel(vehicleModel),
m_assignedTechnicianId(assignedTechnicianId),
m_assignedTechnician(nullptr),
m_discountPercentage(discountPercentage)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
} }
/*
Function: getId
Description: Retrieves the unique ID of the service booking.
Returns:
- const std::string& representing the booking ID.
*/
const std::string& ServiceBooking::getId() const const std::string& ServiceBooking::getId() const
{ {
return m_id; return m_id;
@@ -89,6 +123,11 @@ util::ServiceJobStatus ServiceBooking::getStatus() const
return m_status; return m_status;
} }
const util::Vector<std::string>& ServiceBooking::getServiceIDs() const
{
return m_serviceIDs;
}
/* /*
Function: getServices Function: getServices
Description: Retrieves the map of services included in the booking. Description: Retrieves the map of services included in the booking.
@@ -225,6 +264,13 @@ Returns:
void ServiceBooking::setServices(const util::Map<std::string, Service*>& services) void ServiceBooking::setServices(const util::Map<std::string, Service*>& services)
{ {
m_services = services; m_services = services;
m_serviceIDs.clear();
int numberOfServices = m_services.getSize();
auto servicePointers = m_services.getValues();
for (int index = 0; index < numberOfServices; index++)
{
m_serviceIDs.push_back(servicePointers[index]->getId());
}
} }
/* /*
@@ -328,3 +374,88 @@ void ServiceBooking::setDiscountPercentage(double discountPercentage)
{ {
m_discountPercentage = discountPercentage; m_discountPercentage = discountPercentage;
} }
static std::string getServiceIDsAsString(const util::Vector<std::string>& serviceIDs)
{
int numberOfServices = serviceIDs.getSize();
std::string serviceIDsString;
for (int index = 0; index < numberOfServices; index++)
{
serviceIDsString += serviceIDs[index];
if (index < numberOfServices - 1)
{
serviceIDsString += '|';
}
}
return serviceIDsString;
}
static util::Vector<std::string> getServiceIDsAsVector(const std::string& serviceIDsString)
{
util::Vector<std::string> serviceIDs;
std::string serviceID;
std::istringstream serializedServiceIDs(serviceIDsString);
while (getline(serializedServiceIDs, serviceID, '|'))
{
serviceIDs.push_back(serviceID);
}
return serviceIDs;
}
std::string ServiceBooking::serialize() const
{
std::ostringstream serializedBooking;
serializedBooking << m_id << ','
<< util::getServiceJobStatusString(m_status) << ','
<< getServiceIDsAsString(m_serviceIDs) << ','
<< m_customerId << ','
<< m_vehicleNumber << ','
<< m_vehicleBrand << ','
<< m_vehicleModel << ','
<< m_assignedTechnicianId << ','
<< m_discountPercentage << ',';
return serializedBooking.str();
}
ServiceBooking* ServiceBooking::deserialize(const std::string& record)
{
std::string id, customerId, vehicleNumber, vehicleBrand, vehicleModel, assignedTechnicianId;
std::string serviceJobStatusString, serviceIDsString, discountPercentageString;
double discountPercentage;
std::istringstream serializedBooking(record);
getline(serializedBooking, id, ',');
getline(serializedBooking, serviceJobStatusString, ',');
getline(serializedBooking, serviceIDsString, ',');
getline(serializedBooking, customerId, ',');
getline(serializedBooking, vehicleNumber, ',');
getline(serializedBooking, vehicleBrand, ',');
getline(serializedBooking, vehicleModel, ',');
getline(serializedBooking, assignedTechnicianId, ',');
getline(serializedBooking, discountPercentageString, ',');
util::Vector<std::string> serviceIDs = getServiceIDsAsVector(serviceIDsString);
try
{
discountPercentage = std::stod(discountPercentageString);
}
catch (...)
{
throw std::runtime_error("Invalid discount percentage");
}
util::ServiceJobStatus status = util::getServiceJobStatus(serviceJobStatusString);
return Factory::getObject<ServiceBooking>(
id,
status,
serviceIDs,
customerId,
vehicleNumber,
vehicleBrand,
vehicleModel,
assignedTechnicianId,
discountPercentage
);
}
std::string ServiceBooking::getHeaders()
{
return "ID,Status,ServiceIDs,CustomerID,VehicleNumber,VehicleBrand,VehicleModel,AssignedTechnicianID,DiscountPercentage";
}
@@ -9,6 +9,7 @@ Date:19-May-2026
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
#include "Vector.h"
#include "Enums.h" #include "Enums.h"
class Service; class Service;
@@ -20,6 +21,7 @@ private:
static int m_uid; static int m_uid;
std::string m_id; std::string m_id;
util::ServiceJobStatus m_status; util::ServiceJobStatus m_status;
util::Vector<std::string> m_serviceIDs;
util::Map<std::string, Service*> m_services; util::Map<std::string, Service*> m_services;
std::string m_customerId; std::string m_customerId;
User* m_customer; User* m_customer;
@@ -42,8 +44,20 @@ public:
const std::string& vehicleModel, const std::string& vehicleModel,
double discountPercentage double discountPercentage
); );
ServiceBooking(
const std::string& id,
util::ServiceJobStatus status,
const util::Vector<std::string>& serviceIDs,
const std::string& customerId,
const std::string& vehicleNumber,
const std::string& vehicleBrand,
const std::string& vehicleModel,
const std::string& assignedTechnicianId,
double discountPercentage
);
const std::string& getId() const; const std::string& getId() const;
util::ServiceJobStatus getStatus() const; util::ServiceJobStatus getStatus() const;
const util::Vector<std::string>& getServiceIDs() const;
const util::Map<std::string, Service*>& getServices() const; const util::Map<std::string, Service*>& getServices() const;
const std::string& getCustomerId() const; const std::string& getCustomerId() const;
User* getCustomer() const; User* getCustomer() const;
@@ -64,4 +78,7 @@ public:
void setAssignedTechnicianId(const std::string& assignedTechnicianId); void setAssignedTechnicianId(const std::string& assignedTechnicianId);
void setAssignedTechnician(User* assignedTechnician); void setAssignedTechnician(User* assignedTechnician);
void setDiscountPercentage(double discountPercentage); void setDiscountPercentage(double discountPercentage);
std::string serialize() const;
static ServiceBooking* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -7,9 +7,12 @@ Author: Trenser
Date: 19-May-2026 Date: 19-May-2026
*/ */
#include <sstream>
#include "User.h" #include "User.h"
#include "Notification.h" #include "Notification.h"
#include "Enums.h" #include "Enums.h"
#include "Factory.h"
#include "StringHelper.h"
int User::m_uid = 0; int User::m_uid = 0;
@@ -50,6 +53,23 @@ User::User(const std::string& userName, const std::string& password, const std::
m_type(role), m_type(role),
m_status(util::State::ACTIVE) {} m_status(util::State::ACTIVE) {}
User::User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status)
: m_id(userId),
m_userName(userName),
m_password(password),
m_name(name),
m_phone(phone),
m_email(email),
m_type(role),
m_status(status)
{
int idNumber = util::extractNumber(m_id);
if (idNumber > m_uid)
{
m_uid = idNumber;
}
}
/* /*
Function: ~User Function: ~User
Description: Destructor that cleans up dynamically allocated notifications associated with the user. Description: Destructor that cleans up dynamically allocated notifications associated with the user.
@@ -60,9 +80,10 @@ Returns:
*/ */
User::~User() User::~User()
{ {
for (int index = 0; index < m_notifications.getSize(); index++) auto values = m_notifications.getValues();
for (int index = 0; index < values.getSize(); index++)
{ {
delete m_notifications.getValues()[index]; delete values[index];
} }
} }
@@ -284,3 +305,48 @@ void User::setState(util::State status)
{ {
m_status = status; m_status = status;
} }
std::string User::serialize() const
{
std::ostringstream serializedUser;
serializedUser << m_id << ','
<< m_userName << ','
<< m_password << ','
<< m_name << ','
<< m_phone << ','
<< m_email << ','
<< util::getUserTypeString(m_type) << ','
<< util::getStateString(m_status);
return serializedUser.str();
}
User* User::deserialize(const std::string& record)
{
std::string id, name, username, phone, password, email;
std::string userTypeString, stateString;
std::istringstream serializedUser(record);
getline(serializedUser, id, ',');
getline(serializedUser, username, ',');
getline(serializedUser, password, ',');
getline(serializedUser, name, ',');
getline(serializedUser, phone, ',');
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);
}
std::string User::getHeaders()
{
return "ID,Username,Password,Name,Phone,Email,UserType,UserStatus";
}
@@ -31,6 +31,7 @@ private:
public: public:
User(); User();
User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role); User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role);
User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status);
~User(); ~User();
const std::string& getId() const; const std::string& getId() const;
const std::string& getUserName() const; const std::string& getUserName() const;
@@ -50,4 +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);
std::string serialize() const;
static User* deserialize(const std::string&);
static std::string getHeaders();
}; };
@@ -7,6 +7,7 @@ Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include "InventoryManagementService.h" #include "InventoryManagementService.h"
#include "Config.h"
#include "Vector.h" #include "Vector.h"
#include "Enums.h" #include "Enums.h"
#include "InventoryItem.h" #include "InventoryItem.h"
@@ -14,6 +15,8 @@ Date:19-May-2026
#include "User.h" #include "User.h"
#include "Factory.h" #include "Factory.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "FileManager.h"
#include "Utility.h"
util::Map<std::string, User*> InventoryManagementService::m_observers{}; util::Map<std::string, User*> InventoryManagementService::m_observers{};
@@ -196,3 +199,47 @@ void InventoryManagementService::sendLowStockAlerts()
} }
} }
} }
util::Vector<std::string> InventoryManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
void InventoryManagementService::loadInventoryItems()
{
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
auto& inventoryItems = m_dataStore.getInventoryItems();
auto inventoryItemsMap = inventoryItemFileManager.load();
int numberOfInventoryItems = inventoryItemsMap.getSize();
for (int index = 0; index < numberOfInventoryItems; index++)
{
inventoryItems[inventoryItemsMap.getKeyAt(index)] = inventoryItemsMap.getValueAt(index);
}
}
void InventoryManagementService::saveInventoryItems()
{
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
auto& inventoryItems = m_dataStore.getInventoryItems();
inventoryItemFileManager.save(inventoryItems);
}
void InventoryManagementService::loadObservers()
{
util::loadObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this, m_dataStore);
}
void InventoryManagementService::saveObservers()
{
util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this);
}
@@ -9,6 +9,7 @@ Date:19-May-2026
#pragma once #pragma once
#include <string> #include <string>
#include "Map.h" #include "Map.h"
#include "Vector.h"
#include "NotificationManagementService.h" #include "NotificationManagementService.h"
#include "DataStore.h" #include "DataStore.h"
@@ -19,6 +20,7 @@ class InventoryManagementService : public NotificationManagementService
private: private:
DataStore& m_dataStore; DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers; static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public: public:
InventoryManagementService() : m_dataStore(DataStore::getInstance()) {} InventoryManagementService() : m_dataStore(DataStore::getInstance()) {}
util::Map<std::string, InventoryItem*> getInventoryItems(); util::Map<std::string, InventoryItem*> getInventoryItems();
@@ -30,4 +32,8 @@ public:
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
void detach(User* user) override; void detach(User* user) override;
void loadInventoryItems();
void saveInventoryItems();
void loadObservers();
void saveObservers();
}; };
@@ -19,4 +19,5 @@ public:
virtual void sendNotification(User* recipient, const std::string& title, const std::string& message) = 0; virtual void sendNotification(User* recipient, const std::string& title, const std::string& message) = 0;
virtual void attach(User* user) = 0; virtual void attach(User* user) = 0;
virtual void detach(User* user) = 0; virtual void detach(User* user) = 0;
virtual util::Vector<std::string> getObserverIDs() = 0;
}; };
@@ -7,15 +7,15 @@ Author: Trenser
Date: 20-May-2026 Date: 20-May-2026
*/ */
#include <stdexcept>
#include "PaymentManagementService.h"
#include "Config.h" #include "Config.h"
#include "Enums.h" #include "Enums.h"
#include <stdexcept>
#include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "Invoice.h" #include "Invoice.h"
#include "JobCard.h" #include "JobCard.h"
#include "PaymentManagementService.h"
#include "Service.h" #include "Service.h"
#include "ServiceBooking.h" #include "ServiceBooking.h"
#include "Timestamp.h" #include "Timestamp.h"
@@ -61,7 +61,7 @@ void PaymentManagementService::generateInvoice(ServiceBooking* booking)
{ {
createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService); createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService);
totalLabourCost += currentService->getLaborCost(); totalLabourCost += currentService->getLaborCost();
totalPartsCost += calculatePartsCost(currentService); totalPartsCost += util::calculatePartsCost(currentService);
} }
} }
totalServiceCost = totalLabourCost + totalPartsCost; totalServiceCost = totalLabourCost + totalPartsCost;
@@ -223,3 +223,68 @@ void PaymentManagementService::sendPaymentReminders()
} }
} }
} }
util::Vector<std::string> PaymentManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
void PaymentManagementService::loadInvoices()
{
util::FileManager<Invoice> invoiceFileManager(config::file::INVOICE_FILE);
auto& invoices = m_dataStore.getInvoices();
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& inventoryItems = m_dataStore.getInventoryItems();
auto invoicesMap = invoiceFileManager.load();
for (int invoiceIndex = 0; invoiceIndex < invoicesMap.getSize(); invoiceIndex++)
{
Invoice* invoice = invoicesMap.getValueAt(invoiceIndex);
int bookingIndex = serviceBookings.find(invoice->getBookingId());
if (bookingIndex == -1)
{
throw std::runtime_error("Invalid Booking ID");
}
ServiceBooking* booking = serviceBookings.getValueAt(bookingIndex);
invoice->setBooking(booking);
util::Map<std::string, InventoryItem*> invoiceParts;
auto& partIDs = invoice->getPartIDs();
for (int partIndex = 0; partIndex < partIDs.getSize(); partIndex++)
{
const std::string& partID = partIDs[partIndex];
int inventoryIndex = inventoryItems.find(partID);
if (inventoryIndex == -1)
{
throw std::runtime_error("Invalid Part ID");
}
invoiceParts[partID] = inventoryItems.getValueAt(inventoryIndex);
}
invoice->setParts(invoiceParts);
invoices[invoice->getId()] = invoice;
}
}
void PaymentManagementService::saveInvoices()
{
util::FileManager<Invoice> invoiceFileManager(config::file::INVOICE_FILE);
auto& invoices = m_dataStore.getInvoices();
invoiceFileManager.save(invoices);
}
void PaymentManagementService::loadObservers()
{
util::loadObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this, m_dataStore);
}
void PaymentManagementService::saveObservers()
{
util::saveObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this);
}
@@ -22,6 +22,7 @@ class PaymentManagementService : public NotificationManagementService
private: private:
DataStore& m_dataStore; DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers; static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public: public:
PaymentManagementService() : m_dataStore(DataStore::getInstance()) {} PaymentManagementService() : m_dataStore(DataStore::getInstance()) {}
void generateInvoice(ServiceBooking* booking); void generateInvoice(ServiceBooking* booking);
@@ -31,4 +32,8 @@ public:
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
void detach(User* user) override; void detach(User* user) override;
void loadInvoices();
void saveInvoices();
void loadObservers();
void saveObservers();
}; };
@@ -6,12 +6,16 @@ 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 "AuthenticationManagementService.h" #include "AuthenticationManagementService.h"
#include "ComboPackage.h" #include "ComboPackage.h"
#include "Config.h"
#include "Enums.h" #include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "Invoice.h"
#include "JobCard.h" #include "JobCard.h"
#include "NotificationManagementService.h" #include "NotificationManagementService.h"
#include "PaymentManagementService.h" #include "PaymentManagementService.h"
@@ -21,6 +25,7 @@ Date:19-May-2026
#include "Timestamp.h" #include "Timestamp.h"
#include "User.h" #include "User.h"
#include "UserManagementService.h" #include "UserManagementService.h"
#include "Utility.h"
util::Map<std::string, User*> ServiceManagementService::m_observers{}; util::Map<std::string, User*> ServiceManagementService::m_observers{};
@@ -590,3 +595,205 @@ void ServiceManagementService::sendNotification(User* user, const std::string& t
} }
} }
} }
util::Vector<std::string> ServiceManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
void ServiceManagementService::loadServices()
{
util::FileManager<Service> serviceFileManager(config::file::SERVICE_FILE);
auto& services = m_dataStore.getServices();
auto& inventoryItems = m_dataStore.getInventoryItems();
auto servicesMap = serviceFileManager.load();
for (int serviceIndex = 0; serviceIndex < servicesMap.getSize(); serviceIndex++)
{
Service* service = servicesMap.getValueAt(serviceIndex);
services[service->getId()] = service;
util::Map<std::string, InventoryItem*> inventoryItemsMap;
auto& inventoryItemIDs = service->getRequiredInventoryItemIDs();
for (int inventoryItemIndex = 0; inventoryItemIndex < inventoryItemIDs.getSize(); inventoryItemIndex++)
{
const std::string& inventoryItemID = inventoryItemIDs[inventoryItemIndex];
int index = inventoryItems.find(inventoryItemID);
if (index == -1)
{
throw std::runtime_error("Invalid Inventory Item ID");
}
inventoryItemsMap[inventoryItemID] = inventoryItems.getValueAt(index);
}
service->setRequiredInventoryItems(inventoryItemsMap);
}
}
void ServiceManagementService::saveServices()
{
util::FileManager<Service> serviceFileManager(config::file::SERVICE_FILE);
auto& services = m_dataStore.getServices();
serviceFileManager.save(services);
}
void ServiceManagementService::loadComboPackages()
{
util::FileManager<ComboPackage> comboPackageFileManager(config::file::COMBOPACKAGE_FILE);
auto& comboPackages = m_dataStore.getComboPackages();
auto& services = m_dataStore.getServices();
auto comboPackagesMap = comboPackageFileManager.load();
for (int packageIndex = 0; packageIndex < comboPackagesMap.getSize(); packageIndex++)
{
ComboPackage* comboPackage = comboPackagesMap.getValueAt(packageIndex);
util::Map<std::string, Service*> packageServices;
auto& serviceIDs = comboPackage->getServiceIDs();
for (int serviceIndex = 0; serviceIndex < serviceIDs.getSize(); serviceIndex++)
{
const std::string& serviceID = serviceIDs[serviceIndex];
int serviceMapIndex = services.find(serviceID);
if (serviceMapIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
packageServices[serviceID] = services.getValueAt(serviceMapIndex);
}
comboPackage->setServices(packageServices);
comboPackages[comboPackage->getId()] = comboPackage;
}
}
void ServiceManagementService::saveComboPackages()
{
util::FileManager<ComboPackage> comboPackageFileManager(config::file::COMBOPACKAGE_FILE);
auto& comboPackages = m_dataStore.getComboPackages();
comboPackageFileManager.save(comboPackages);
}
void ServiceManagementService::loadServiceBookings()
{
util::FileManager<ServiceBooking> bookingFileManager(config::file::SERVICEBOOKING_FILE);
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& services = m_dataStore.getServices();
auto& users = m_dataStore.getUsers();
auto bookingsMap = bookingFileManager.load();
for (int bookingIndex = 0; bookingIndex < bookingsMap.getSize(); bookingIndex++)
{
ServiceBooking* booking = bookingsMap.getValueAt(bookingIndex);
util::Map<std::string, Service*> bookingServices;
auto& serviceIDs = booking->getServiceIDs();
for (int serviceIndex = 0; serviceIndex < serviceIDs.getSize(); serviceIndex++)
{
const std::string& serviceID = serviceIDs[serviceIndex];
int serviceMapIndex = services.find(serviceID);
if (serviceMapIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
bookingServices[serviceID] = services.getValueAt(serviceMapIndex);
}
booking->setServices(bookingServices);
int customerIndex = users.find(booking->getCustomerId());
if (customerIndex == -1)
{
throw std::runtime_error("Invalid Customer ID");
}
User* customer = users.getValueAt(customerIndex);
if (customer->getUserType() != util::UserType::CUSTOMER)
{
throw std::runtime_error("User is not a customer");
}
booking->setCustomer(customer);
const std::string& technicianId = booking->getAssignedTechnicianId();
if (!technicianId.empty())
{
int technicianIndex = users.find(technicianId);
if (technicianIndex == -1)
{
throw std::runtime_error("Invalid Technician ID");
}
User* technician = users.getValueAt(technicianIndex);
if (technician->getUserType() != util::UserType::TECHNICIAN)
{
throw std::runtime_error("User is not a technician");
}
booking->setAssignedTechnician(technician);
}
serviceBookings[booking->getId()] = booking;
}
}
void ServiceManagementService::saveServiceBookings()
{
util::FileManager<ServiceBooking> bookingFileManager(config::file::SERVICEBOOKING_FILE);
auto& serviceBookings = m_dataStore.getServiceBookings();
bookingFileManager.save(serviceBookings);
}
void ServiceManagementService::loadJobCards()
{
util::FileManager<JobCard> jobCardFileManager(config::file::JOBCARD_FILE);
auto& jobCards = m_dataStore.getJobCards();
auto& serviceBookings = m_dataStore.getServiceBookings();
auto& services = m_dataStore.getServices();
auto& users = m_dataStore.getUsers();
auto jobCardsMap = jobCardFileManager.load();
for (int jobCardIndex = 0; jobCardIndex < jobCardsMap.getSize(); jobCardIndex++)
{
JobCard* jobCard = jobCardsMap.getValueAt(jobCardIndex);
int bookingIndex = serviceBookings.find(jobCard->getBookingId());
if (bookingIndex == -1)
{
throw std::runtime_error("Invalid Booking ID");
}
ServiceBooking* booking = serviceBookings.getValueAt(bookingIndex);
jobCard->setBooking(booking);
int serviceIndex = services.find(jobCard->getServiceId());
if (serviceIndex == -1)
{
throw std::runtime_error("Invalid Service ID");
}
Service* service = services.getValueAt(serviceIndex);
if (booking->getServices().find(jobCard->getServiceId()) == -1)
{
throw std::runtime_error("Service does not belong to booking");
}
jobCard->setService(service);
int technicianIndex = users.find(jobCard->getTechnicianId());
if (technicianIndex == -1)
{
throw std::runtime_error("Invalid Technician ID");
}
User* technician = users.getValueAt(technicianIndex);
if (technician->getUserType() != util::UserType::TECHNICIAN)
{
throw std::runtime_error("User is not a technician");
}
jobCard->setTechnician(technician);
jobCards[jobCard->getId()] = jobCard;
}
}
void ServiceManagementService::saveJobCards()
{
util::FileManager<JobCard> jobCardFileManager(config::file::JOBCARD_FILE);
auto& jobCards = m_dataStore.getJobCards();
jobCardFileManager.save(jobCards);
}
void ServiceManagementService::loadObservers()
{
util::loadObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this, m_dataStore);
}
void ServiceManagementService::saveObservers()
{
util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this);
}
@@ -22,6 +22,7 @@ class ServiceManagementService : public NotificationManagementService
private: private:
DataStore& m_dataStore; DataStore& m_dataStore;
static util::Map<std::string, User*> m_observers; static util::Map<std::string, User*> m_observers;
util::Vector<std::string> getObserverIDs() override;
public: public:
ServiceManagementService() : m_dataStore(DataStore::getInstance()) {} ServiceManagementService() : m_dataStore(DataStore::getInstance()) {}
util::Map<std::string, Service*> getServices(); util::Map<std::string, Service*> getServices();
@@ -43,4 +44,14 @@ public:
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
void detach(User* user) override; void detach(User* user) override;
void loadServices();
void saveServices();
void loadComboPackages();
void saveComboPackages();
void loadServiceBookings();
void saveServiceBookings();
void loadJobCards();
void saveJobCards();
void loadObservers();
void saveObservers();
}; };
@@ -5,16 +5,20 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include "UserManagementService.h"
#include <stdexcept>
#include "Config.h" #include "Config.h"
#include "Enums.h" #include "Enums.h"
#include "Factory.h" #include "Factory.h"
#include "FileManager.h"
#include "InventoryManagementService.h" #include "InventoryManagementService.h"
#include "Invoice.h"
#include "PaymentManagementService.h" #include "PaymentManagementService.h"
#include "ServiceManagementService.h" #include "ServiceManagementService.h"
#include "User.h" #include "User.h"
#include "UserManagementService.h"
#include "Utility.h"
#include "Vector.h" #include "Vector.h"
#include <stdexcept>
void UserManagementService::ensureAdminExists() void UserManagementService::ensureAdminExists()
{ {
@@ -203,3 +207,50 @@ void UserManagementService::deleteNotification(const std::string& notificationID
} }
notifications.remove(notificationID); notifications.remove(notificationID);
} }
void UserManagementService::loadUsers()
{
util::FileManager<User> userFileManager(config::file::USER_FILE);
util::FileManager<Notification> notificationFileManager(config::file::NOTIFICATION_FILE);
auto& users = m_dataStore.getUsers();
auto usersMap = userFileManager.load();
auto notificationsMap = notificationFileManager.load();
int numberOfUsers = usersMap.getSize();
int numberOfNotifications = notificationsMap.getSize();
for (int index = 0; index < numberOfUsers; index++)
{
users[usersMap.getKeyAt(index)] = usersMap.getValueAt(index);
}
for (int index = 0; index < numberOfNotifications; index++)
{
Notification* notification = notificationsMap.getValueAt(index);
const std::string& recipientUserId = notification->getRecipientUserId();
int userIndex = users.find(recipientUserId);
if (userIndex == -1)
{
throw std::runtime_error("Invalid recipient user ID");
}
User* user = users.getValueAt(userIndex);
user->addNotification(notification);
}
}
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);
}
@@ -29,4 +29,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();
}; };
@@ -24,4 +24,19 @@ namespace config
constexpr int INVENTORY_LOW_STOCK_THRESHOLD = 5; constexpr int INVENTORY_LOW_STOCK_THRESHOLD = 5;
constexpr int PAYMENT_REMINDER_THRESHOLD_HOURS = 168; constexpr int PAYMENT_REMINDER_THRESHOLD_HOURS = 168;
} }
namespace file
{
constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.csv";
constexpr const char* USER_FILE = "files/User.csv";
constexpr const char* NOTIFICATION_FILE = "files/Notification.csv";
constexpr const char* SERVICE_FILE = "files/Service.csv";
constexpr const char* COMBOPACKAGE_FILE = "files/ComboPackage.csv";
constexpr const char* SERVICEBOOKING_FILE = "files/ServiceBooking.csv";
constexpr const char* JOBCARD_FILE = "files/JobCard.csv";
constexpr const char* INVOICE_FILE = "files/Invoice.csv";
constexpr const char* SERVICEMANAGEMENTOBSERVERS = "files/ServiceManagementObservers.csv";
constexpr const char* PAYMENTMANAGEMENTOBSERVERS = "files/PaymentManagementObservers.csv";
constexpr const char* INVENTORYMANAGEMENTOBSERVERS = "files/InventoryManagementObservers.csv";
}
} }
@@ -253,9 +253,9 @@ namespace util
switch (status) switch (status)
{ {
case State::ACTIVE: case State::ACTIVE:
return "STARTED"; return "ACTIVE";
case State::INACTIVE: case State::INACTIVE:
return "COMPLETED"; return "INACTIVE";
} }
throw std::invalid_argument("Invalid State"); throw std::invalid_argument("Invalid State");
} }
@@ -276,7 +276,7 @@ namespace util
{ {
return State::ACTIVE; return State::ACTIVE;
} }
if (value == "COMPLETED") if (value == "INACTIVE")
{ {
return State::INACTIVE; return State::INACTIVE;
} }
@@ -0,0 +1,47 @@
#pragma once
#include <fstream>
#include <string>
#include <stdexcept>
#include "Vector.h"
namespace util
{
inline util::Vector<std::string> loadRecords(const std::string& filePath)
{
util::Vector<std::string> records;
std::ifstream file(filePath);
if (!file.is_open())
{
std::ofstream newFile(filePath);
newFile.close();
file.open(filePath);
}
std::string line;
bool isHeader = true;
while (std::getline(file, line))
{
if (isHeader)
{
isHeader = false;
continue;
}
records.push_back(line);
}
return records;
}
inline void saveRecords(const std::string& filePath, const util::Vector<std::string>& records)
{
std::ofstream file(filePath, std::ios::trunc);
if (!file.is_open())
{
throw std::runtime_error("Failed to open file " + filePath);
}
file << "Values" << '\n';
int numberOfRecords = records.getSize();
for (int index = 0; index < numberOfRecords; index++)
{
file << records[index] << '\n';
}
}
}
@@ -0,0 +1,83 @@
#pragma once
#include <string>
#include <stdexcept>
#include <fstream>
#include "Vector.h"
#include "Map.h"
namespace util
{
template <typename T> using objects = util::Map<std::string, T*>;
template <typename T>
class FileManager
{
private:
std::string m_filePath;
public:
FileManager() : m_filePath("") {}
FileManager(const std::string& filePath) : m_filePath(filePath) {}
objects<T> load();
void save(const objects<T>&);
};
template <typename T>
objects<T> FileManager<T>::load()
{
objects<T> records;
std::ifstream file(m_filePath);
if (!file.is_open())
{
std::ofstream newFile(m_filePath);
newFile.close();
file.open(m_filePath);
}
util::Vector<std::string> lines;
std::string line;
while (std::getline(file, line))
{
lines.push_back(line);
}
int numberOfLines = lines.getSize();
bool isHeader = true;
for (int lineIndex = 0; lineIndex < numberOfLines; lineIndex++)
{
const auto& record = lines[lineIndex];
if (isHeader)
{
isHeader = false;
continue;
}
auto object = T::deserialize(record);
if (!object)
{
throw std::runtime_error("Failed to deserialize record");
}
records[object->getId()] = object;
}
return records;
}
template <typename T>
void FileManager<T>::save(const objects<T>& records)
{
util::Vector<std::string> lines;
lines.push_back(T::getHeaders());
int numberOfRecords = records.getSize();
for (int recordIndex = 0; recordIndex < numberOfRecords; recordIndex++)
{
const auto& record = records.getValueAt(recordIndex);
lines.push_back(record->serialize());
}
std::ofstream file(m_filePath, std::ios::trunc);
if (!file.is_open())
{
throw std::runtime_error("Failed to open file " + m_filePath);
}
int numberOfLines = lines.getSize();
for (int lineIndex = 0; lineIndex < numberOfLines; lineIndex++)
{
file << lines[lineIndex] << '\n';
}
}
}
@@ -34,7 +34,7 @@ namespace util
/* /*
* Function: read * Function: read
* Description: Reads a line of text input from console into a string. * Description: Reads a line of text input from console into a string and cleans it up.
* Parameters: * Parameters:
* value - reference to a string where the input will be stored * value - reference to a string where the input will be stored
* Returns: * Returns:
@@ -43,6 +43,15 @@ namespace util
inline void read(std::string& value) inline void read(std::string& value)
{ {
std::getline(std::cin >> std::ws, value); std::getline(std::cin >> std::ws, value);
std::string cleanedValue;
for (int index = 0; index < value.length(); index++)
{
if (value[index] != ',')
{
cleanedValue += value[index];
}
}
value = cleanedValue;
} }
/* /*
@@ -0,0 +1,18 @@
#include <cctype>
#include <string>
namespace util
{
inline int extractNumber(const std::string& input)
{
int result = 0;
for (char character : input)
{
if (std::isdigit(static_cast<unsigned char>(character)))
{
result = result * 10 + (character - '0');
}
}
return result;
}
}
@@ -9,7 +9,12 @@ Date:19-May-2026
#include "Service.h" #include "Service.h"
#include "ComboPackage.h" #include "ComboPackage.h"
#include "InventoryItem.h" #include "InventoryItem.h"
#include "NotificationManagementService.h"
#include "FileHelper.h"
#include "DataStore.h"
namespace util
{
/* /*
Function: calculatePartsCost Function: calculatePartsCost
Description: Calculates the total cost of parts required for a given service Description: Calculates the total cost of parts required for a given service
@@ -50,3 +55,26 @@ inline double calculateComboServiceEstimatedCost(const ComboPackage* comboPackag
} }
return cost; return cost;
} }
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");
}
service->attach(users.getValueAt(userIndex));
}
}
inline void saveObservers(const std::string& filePath, NotificationManagementService* service)
{
auto observerIDs = service->getObserverIDs();
util::saveRecords(filePath, observerIDs);
}
}
@@ -858,7 +858,7 @@ static const Service* selectServiceFromServices(const util::Map<std::string, con
continue; continue;
} }
activeServicesMap.insert(currentIndex, currentService); activeServicesMap.insert(currentIndex, currentService);
double partsCost = calculatePartsCost(currentService); double partsCost = util::calculatePartsCost(currentService);
std::cout << std::left std::cout << std::left
<< std::setw(10) << currentIndex << std::setw(10) << currentIndex
<< std::setw(15) << currentService->getId() << std::setw(15) << currentService->getId()
@@ -177,7 +177,7 @@ static const Service* selectServiceFromServices(const util::Map<std::string, con
continue; continue;
} }
activeServicesMap.insert(currentIndex, currentService); activeServicesMap.insert(currentIndex, currentService);
double partsCost = calculatePartsCost(currentService); double partsCost = util::calculatePartsCost(currentService);
std::cout << std::left std::cout << std::left
<< std::setw(10) << currentIndex << std::setw(10) << currentIndex
<< std::setw(15) << currentService->getId() << std::setw(15) << currentService->getId()
@@ -250,7 +250,7 @@ static const ComboPackage* selectComboPackageFromPackages(const util::Map<std::s
<< std::setw(10) << currentIndex << std::setw(10) << currentIndex
<< std::setw(15) << currentComboPackage->getId() << std::setw(15) << currentComboPackage->getId()
<< std::setw(25) << currentComboPackage->getPackageName() << std::setw(25) << currentComboPackage->getPackageName()
<< std::setw(15) << calculateComboServiceEstimatedCost(currentComboPackage) << std::setw(15) << util::calculateComboServiceEstimatedCost(currentComboPackage)
<< std::endl; << std::endl;
currentIndex++; currentIndex++;
} }
@@ -22,6 +22,7 @@ Return type: void
*/ */
void UserInterface::run() void UserInterface::run()
{ {
m_controller.loadSystemData();
m_controller.runSystemChecks(); m_controller.runSystemChecks();
bool isMenuActive = true; bool isMenuActive = true;
while (isMenuActive) while (isMenuActive)
@@ -43,6 +44,7 @@ void UserInterface::run()
util::pressEnter(); util::pressEnter();
} }
} }
m_controller.saveSystemData();
} }
/* /*