Implement Service Refactoring

<UserStory> 1950: Implement Service Refactorings </UserStory>

UserStory #1950

<Changes>

1. Added `DataStoreLockGuard` integration in `PaymentManagementService` methods (`sendPaymentReminders`, `generateInvoice`, `getInvoices`, `completePayment`, `getAllInvoices`, `confirmPayment`) to ensure thread-safe access to the datastore.

2. Implemented record enrichment logic in `DataStore::getInvoices()` to automatically link `Invoice` objects with their corresponding `ServiceBooking` and `InventoryItem` entities during loading, validating relationships and throwing exceptions for invalid references.

3. Refactored invoice persistence by implementing `saveInvoices()` using `saveRecords<Invoice, SerializedInvoice>` to write tracked records directly to shared memory.

4. Updated invoice creation and modification flows:
   - `generateInvoice`: Uses `createNewRecord` to insert new invoices into the tracked cache and triggers immediate persistence.
   - `completePayment` & `confirmPayment`: Marks records as `MODIFIED` in the `TrackedRecord` state before saving changes.

5. Updated data access patterns across `PaymentManagementService` to use `.data` pointers from `TrackedRecord` objects returned by the datastore, replacing direct pointer access to mapped objects.

6. Added necessary header dependencies including `DataStoreLockGuard.h`, `Invoice.h`, and `SerializedRecords.h` to support locking mechanisms and structured serialization.

</Changes>

<Test>

N/A

</Test>

<Review>

Sreeja Reghukumar, please review

</Review>
This commit is contained in:
Jissin Mathew
2026-06-15 12:43:44 +05:30
parent f545d57f79
commit 7047e96b3c
4 changed files with 104 additions and 18 deletions
@@ -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<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++)
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<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);
auto& currentTrackedInvoices = m_dataStore.getInvoices();
currentTrackedInvoices.insert(invoice->getId(), util::createNewRecord(invoice));
m_dataStore.saveInvoices();
}
/*
@@ -336,11 +340,12 @@ Returns:
*/
util::Map<std::string, Invoice*> PaymentManagementService::getInvoices(const std::string& customerID)
{
util::Map<std::string, Invoice*>& currentInvoices = m_dataStore.getInvoices();
DataStoreLockGuard lock(m_dataStore);
auto& currentTrackedInvoices = m_dataStore.getInvoices();
util::Map<std::string, Invoice*> 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<std::string, Invoice*>& PaymentManagementService::getAllInvoices()
{
return m_dataStore.getInvoices();
DataStoreLockGuard lock(m_dataStore);
util::Map<std::string, Invoice*> 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();
}