diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj
index 6a269f5..7c4bfd3 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj
@@ -157,6 +157,7 @@
+
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp
index af6fdc6..3092551 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp
@@ -12,6 +12,7 @@ Date: 19-May-2026
#include "Config.h"
#include "SerializedRecords.h"
#include "FileHelper.h"
+#include "Invoice.h"
/*
Function: DataStore
@@ -319,6 +320,45 @@ Returns:
*/
util::Map>& DataStore::getInvoices()
{
+ auto& serviceBookings = getServiceBookings();
+ auto& inventoryItems = getInventoryItems();
+ util::Map> invoices = loadRecords(m_invoices);
+ refreshCache(m_invoiceCache, invoices);
+ for (int iterator = 0; iterator < m_invoiceCache.getSize(); iterator++)
+ {
+ auto& trackedInvoice = m_invoiceCache.getValueAt(iterator);
+ Invoice* invoice = trackedInvoice.data;
+ if (!invoice)
+ {
+ continue;
+ }
+ const std::string& currentBookingId = invoice->getBookingId();
+ int currentBookingIndex = serviceBookings.find(currentBookingId);
+ if (currentBookingIndex == -1)
+ {
+ throw std::runtime_error("Invalid Service Booking Index.");
+ }
+ ServiceBooking* currentBooking = serviceBookings.getValueAt(currentBookingIndex).data;
+ auto& currentInventoryItemIds = invoice->getPartIDs();
+ util::Map currentInventoryItems;
+ for (int iterator = 0; iterator < currentInventoryItemIds.getSize(); iterator++)
+ {
+ const std::string& currentItemId = currentInventoryItemIds[iterator];
+ int currentItemIndex = inventoryItems.find(currentItemId);
+ if (currentItemIndex == -1)
+ {
+ throw std::runtime_error("Invalid Inventory item id.");
+ }
+ InventoryItem* currentItem = inventoryItems.getValueAt(currentItemIndex).data;
+ if (!currentItem)
+ {
+ continue;
+ }
+ currentInventoryItems[currentItemId] = currentItem;
+ }
+ invoice->setBooking(currentBooking);
+ invoice->setParts(currentInventoryItems);
+ }
return m_invoiceCache;
}
@@ -455,6 +495,7 @@ Returns:
*/
void DataStore::saveInvoices()
{
+ saveRecords(m_invoices, m_invoiceCache);
}
/*
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h
new file mode 100644
index 0000000..2e04eb0
--- /dev/null
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h
@@ -0,0 +1,28 @@
+/*
+File: DataStoreLockGuard.h
+Description: Defines the DataStoreLockGuard class used to manage DataStore
+ locking and unlocking automatically within a scope.
+Author: Trenser
+Date: 12-June-2026
+*/
+
+#pragma once
+#include "DataStore.h"
+
+class DataStoreLockGuard
+{
+public:
+ explicit DataStoreLockGuard(DataStore& dataStore)
+ : m_dataStore(dataStore)
+ {
+ m_dataStore.lockDataStore();
+ }
+ ~DataStoreLockGuard()
+ {
+ m_dataStore.unlockDataStore();
+ }
+ DataStoreLockGuard(const DataStoreLockGuard&) = delete;
+ DataStoreLockGuard& operator=(const DataStoreLockGuard&) = delete;
+private:
+ DataStore& m_dataStore;
+};
\ No newline at end of file
diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp
index 1fc1ff8..45f1742 100644
--- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp
+++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp
@@ -16,6 +16,7 @@ Date: 20-May-2026
#include "Invoice.h"
#include "JobCard.h"
#include "PaymentManagementService.h"
+#include "DataStoreLockGuard.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "Timestamp.h"
@@ -113,11 +114,12 @@ Returns:
*/
void PaymentManagementService::sendPaymentReminders()
{
- auto& invoicesMap = m_dataStore.getInvoices();
- int invoicesMapSize = invoicesMap.getSize();
+ DataStoreLockGuard lock(m_dataStore);
+ auto& trackedInvoicesMap = m_dataStore.getInvoices();
+ int invoicesMapSize = trackedInvoicesMap.getSize();
for (int index = 0; index < invoicesMapSize; index++)
{
- const Invoice* invoice = invoicesMap.getValueAt(index);
+ const Invoice* invoice = trackedInvoicesMap.getValueAt(index).data;
if (invoice && invoice->getStatus() == util::PaymentStatus::PENDING)
{
util::Timestamp invoiceCreationTimestamp = invoice->getInvoiceDate();
@@ -290,6 +292,7 @@ Throws:
*/
void PaymentManagementService::generateInvoice(ServiceBooking* booking)
{
+ DataStoreLockGuard lock(m_dataStore);
if (!booking)
{
throw std::runtime_error("Invoice generation failed: booking is null.");
@@ -299,10 +302,10 @@ void PaymentManagementService::generateInvoice(ServiceBooking* booking)
std::string bookingID = booking->getId();
util::Map servicesInTheBookedService = booking->getServices();
util::Map completeInventoryItemMapOfBooking;
- util::Map currentJobCards = m_dataStore.getJobCards();
- for (int iterator = 0; iterator < currentJobCards.getSize(); iterator++)
+ auto& currentTrackedJobCards = m_dataStore.getJobCards();
+ for (int iterator = 0; iterator < currentTrackedJobCards.getSize(); iterator++)
{
- JobCard* currentJobCard = currentJobCards.getValueAt(iterator);
+ JobCard* currentJobCard = currentTrackedJobCards.getValueAt(iterator).data;
util::ServiceJobStatus currentJobCardStatus = currentJobCard->getStatus();
if (currentJobCard->getBookingId() == bookingID && currentJobCardStatus != util::ServiceJobStatus::CANCELLED && currentJobCardStatus != util::ServiceJobStatus::COMPLETED)
{
@@ -322,8 +325,9 @@ void PaymentManagementService::generateInvoice(ServiceBooking* booking)
totalServiceCost = totalLaborCost + totalPartsCost;
totalServiceCost -= (totalServiceCost * (discountPercentage / 100));
Invoice* invoice = Factory::getObject(bookingID, booking, util::Timestamp(), totalLaborCost, completeInventoryItemMapOfBooking, totalPartsCost, discountPercentage, totalServiceCost, util::Timestamp(), util::PaymentMode::NOTSET, util::PaymentStatus::PENDING);
- util::Map& currentInvoices = m_dataStore.getInvoices();
- currentInvoices.insert(invoice->getId(), invoice);
+ auto& currentTrackedInvoices = m_dataStore.getInvoices();
+ currentTrackedInvoices.insert(invoice->getId(), util::createNewRecord(invoice));
+ m_dataStore.saveInvoices();
}
/*
@@ -336,11 +340,12 @@ Returns:
*/
util::Map PaymentManagementService::getInvoices(const std::string& customerID)
{
- util::Map& currentInvoices = m_dataStore.getInvoices();
+ DataStoreLockGuard lock(m_dataStore);
+ auto& currentTrackedInvoices = m_dataStore.getInvoices();
util::Map currentUserInvoices;
- for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
+ for (int iterator = 0; iterator < currentTrackedInvoices.getSize(); iterator++)
{
- Invoice* currentInvoice = currentInvoices.getValueAt(iterator);
+ Invoice* currentInvoice = currentTrackedInvoices.getValueAt(iterator).data;
if (currentInvoice->getBooking()->getCustomerId() == customerID)
{
currentUserInvoices.insert(currentInvoice->getId(), currentInvoice);
@@ -363,11 +368,13 @@ Throws:
*/
void PaymentManagementService::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode)
{
- auto& currentInvoices = m_dataStore.getInvoices();
- int invoiceIndex = currentInvoices.find(invoiceID);
+ DataStoreLockGuard lock(m_dataStore);
+ auto& currentTrackedInvoices = m_dataStore.getInvoices();
+ int invoiceIndex = currentTrackedInvoices.find(invoiceID);
if (invoiceIndex != -1)
{
- Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
+ auto& trackedInvoice = currentTrackedInvoices.getValueAt(invoiceIndex);
+ Invoice* invoice = trackedInvoice.data;
if (invoice && invoice->getStatus() != util::PaymentStatus::PAID)
{
User* currentUser = invoice->getBooking()->getCustomer();
@@ -378,12 +385,14 @@ void PaymentManagementService::completePayment(const std::string& invoiceID, uti
title = "Payment successful";
message = "Payment successful for Invoice ID " + invoiceID;
sendNotification(currentUser, title, message);
+ trackedInvoice.state = RecordState::MODIFIED;
}
}
else
{
throw std::runtime_error("Payment failed: invalid invoice ID.");
}
+ m_dataStore.saveInvoices();
}
/*
@@ -396,7 +405,10 @@ Returns:
*/
util::Map& PaymentManagementService::getAllInvoices()
{
- return m_dataStore.getInvoices();
+ DataStoreLockGuard lock(m_dataStore);
+ util::Map invoices;
+ invoices = util::getObjects(m_dataStore.getInvoices());
+ return invoices;
}
/*
@@ -412,20 +424,24 @@ Throws:
*/
void PaymentManagementService::confirmPayment(const std::string& invoiceID)
{
- auto& currentInvoices = m_dataStore.getInvoices();
- int invoiceIndex = currentInvoices.find(invoiceID);
+ DataStoreLockGuard lock(m_dataStore);
+ auto& currentTrackedInvoices = m_dataStore.getInvoices();
+ int invoiceIndex = currentTrackedInvoices.find(invoiceID);
if (invoiceIndex == -1)
{
throw std::runtime_error("Payment confirmation failed: invalid invoice ID.");
}
- Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
+ auto& trackedInvoice = currentTrackedInvoices.getValueAt(invoiceIndex);
+ Invoice* invoice = trackedInvoice.data;
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);
+ trackedInvoice.state = RecordState::MODIFIED;
std::string title = "Payment Confirmed";
std::string message = "Payment Confirmed for Invoice ID " + invoiceID;
sendNotification(currentUser, title, message);
+ m_dataStore.saveInvoices();
}
\ No newline at end of file