edd0c60e40
<UserStory> 1954: Implement Service Refactoring </UserStory> UserStory #1954 <Changes> 1. Refactored notification handling to persist notifications directly in the datastore instead of maintaining notification collections within User objects. 2. Removed recipient User pointer dependencies from Notification and retained recipient user identification through recipientUserId. 3. Implemented generic observer persistence support in DataStore with shared helper methods for loading and saving observer subscriptions. 4. Added datastore-backed observer management for ServiceManagementService, PaymentManagementService, and InventoryManagementService. 5. Updated attach() and detach() operations to load, modify, and persist observer subscriptions using shared memory mappings. 6. Refactored sendNotification() implementations to create and persist Notification records directly to the datastore for subscribed observers. 7. Updated UserManagementService notification retrieval and deletion logic to operate on datastore notification records filtered by recipient user ID. 8. Removed notification ownership and observer-specific notification APIs from User and Observer classes. 9. Added configurable shared memory growth factor support and updated mapping expansion logic to use centralized configuration values. 10. Removed obsolete NotificationManagementService implementation and updated project configuration references. 11. Added DataStoreLockGuard integration for observer and notification persistence operations to ensure synchronized datastore access. </Changes> <Test> N/A </Test> <Review> Sreeja Reghukumar, please review </Review>
350 lines
10 KiB
C++
350 lines
10 KiB
C++
/*
|
|
File: InventoryManagementService.cpp
|
|
Description: Implements the InventoryManagementService class, which manages inventory
|
|
items and observer relationships within the system. Provides methods
|
|
for loading and saving inventory items from persistent storage, as well
|
|
as attaching and persisting observers for notification handling.
|
|
Author: Trenser
|
|
Date: 22-May-2026
|
|
*/
|
|
|
|
#include <stdexcept>
|
|
#include "Config.h"
|
|
#include "Enums.h"
|
|
#include "Factory.h"
|
|
#include "FileManager.h"
|
|
#include "InventoryItem.h"
|
|
#include "InventoryManagementService.h"
|
|
#include "Timestamp.h"
|
|
#include "User.h"
|
|
#include "Utility.h"
|
|
#include "Vector.h"
|
|
#include "DataStoreLockGuard.h"
|
|
|
|
util::Map<std::string, User*> InventoryManagementService::m_observers{};
|
|
|
|
/*
|
|
Function: sendLowStockAlertsToAdmins (static helper)
|
|
Description: Sends low stock alert notifications to all admin users for a given inventory item.
|
|
Parameters:
|
|
- inventoryManagementService: InventoryManagementService&, service used to send notifications
|
|
- inventoryItem: const InventoryItem*, pointer to the low-stock inventory item
|
|
- adminUsers: const util::Vector<User*>&, list of admin users to notify
|
|
Returns:
|
|
- None
|
|
*/
|
|
static void sendLowStockAlertsToAdmins(InventoryManagementService& inventoryManagementService, const InventoryItem* inventoryItem, const util::Vector<User*>& adminUsers)
|
|
{
|
|
int adminUsersSize = adminUsers.getSize();
|
|
for (int index = 0; index < adminUsersSize; index++)
|
|
{
|
|
std::string title = "Low Stock Alert";
|
|
std::string message = "The inventory item with ID " + inventoryItem->getId() + " has very low quantity in the inventory";
|
|
inventoryManagementService.sendNotification(
|
|
adminUsers[index],
|
|
title,
|
|
message
|
|
);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Function: sendLowStockAlerts
|
|
Description: Sends alerts to user for inventory items with low stock
|
|
Parameters:
|
|
- None
|
|
Returns:
|
|
- None
|
|
*/
|
|
void InventoryManagementService::sendLowStockAlerts()
|
|
{
|
|
auto& inventoryItems = m_dataStore.getInventoryItems();
|
|
if (inventoryItems.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
int inventoryItemsSize = inventoryItems.getSize();
|
|
auto& usersMap = m_dataStore.getUsers();
|
|
int usersMapSize = usersMap.getSize();
|
|
util::Vector<User*> adminUsers;
|
|
for (int index = 0; index < usersMapSize; index++)
|
|
{
|
|
User* user = usersMap.getValueAt(index);
|
|
if (user->getUserType() == util::UserType::ADMIN)
|
|
{
|
|
adminUsers.push_back(user);
|
|
}
|
|
}
|
|
int adminUsersSize = adminUsers.getSize();
|
|
if (adminUsersSize < 1)
|
|
{
|
|
throw std::runtime_error("The system has no admins present!");
|
|
}
|
|
for (int index = 0; index < inventoryItemsSize; index++)
|
|
{
|
|
InventoryItem* inventoryItem = inventoryItems.getValueAt(index);
|
|
if (inventoryItem && inventoryItem->getQuantity() < config::threshold::INVENTORY_LOW_STOCK_THRESHOLD)
|
|
{
|
|
sendLowStockAlertsToAdmins(*this, inventoryItem, adminUsers);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Function: getObserverIDs
|
|
Description: Retrieves the IDs of all observers currently attached to the
|
|
InventoryManagementService.
|
|
Parameters:
|
|
- None
|
|
Returns:
|
|
- util::Vector<std::string>: Vector of observer user IDs
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/*
|
|
Function: loadInventoryItems
|
|
Description: Loads inventory items from persistent storage into the datastore.
|
|
Uses FileManager to deserialize inventory items from the configured file.
|
|
Parameters:
|
|
- None
|
|
Returns:
|
|
- void
|
|
*/
|
|
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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
Function: saveInventoryItems
|
|
Description: Saves inventory items from the datastore to persistent storage.
|
|
Uses FileManager to serialize inventory items into the configured file.
|
|
Parameters:
|
|
- None
|
|
Returns:
|
|
- void
|
|
*/
|
|
void InventoryManagementService::saveInventoryItems()
|
|
{
|
|
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
|
|
auto& inventoryItems = m_dataStore.getInventoryItems();
|
|
inventoryItemFileManager.save(inventoryItems);
|
|
}
|
|
|
|
/*
|
|
Function: loadObservers
|
|
Description: Loads observer IDs from persistent storage and attaches corresponding
|
|
users as observers to the InventoryManagementService.
|
|
Parameters:
|
|
- None
|
|
Returns:
|
|
- void
|
|
*/
|
|
void InventoryManagementService::loadObservers()
|
|
{
|
|
util::loadObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this, m_dataStore);
|
|
}
|
|
|
|
/*
|
|
Function: saveObservers
|
|
Description: Saves the current observer IDs of the InventoryManagementService
|
|
to persistent storage for future retrieval.
|
|
Parameters:
|
|
- None
|
|
Returns:
|
|
- void
|
|
*/
|
|
void InventoryManagementService::saveObservers()
|
|
{
|
|
util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this);
|
|
}
|
|
|
|
/*
|
|
Function: addInventoryItem
|
|
Description: Creates a new inventory item using the Factory and inserts it
|
|
into the DataStore.
|
|
Parameter: const std::string& partName - name of the part
|
|
int quantity - initial quantity of the part
|
|
double price - price of the part
|
|
Return type: void
|
|
*/
|
|
void InventoryManagementService::addInventoryItem(const std::string& partName, int quantity, double price)
|
|
{
|
|
InventoryItem* newItem = Factory::getObject<InventoryItem>(partName, quantity, price);
|
|
m_dataStore.getInventoryItems().insert(newItem->getId(), newItem);
|
|
}
|
|
|
|
/*
|
|
Function: addInventoryItemStock
|
|
Description: Increases the stock quantity of an existing inventory item.
|
|
Parameter: const std::string& selectedItemId - ID of the inventory item
|
|
int quantity - quantity to add
|
|
Return type: void
|
|
*/
|
|
void InventoryManagementService::addInventoryItemStock(const std::string& selectedItemId, int quantity)
|
|
{
|
|
int index = m_dataStore.getInventoryItems().find(selectedItemId);
|
|
if (index != -1)
|
|
{
|
|
InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index);
|
|
if (item != nullptr)
|
|
{
|
|
int totalQuantity = item->getQuantity() + quantity;
|
|
item->setQuantity(totalQuantity);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Function: getInventoryItems
|
|
Description: Retrieves all inventory items stored in the DataStore.
|
|
Parameter: None
|
|
Return type: util::Map<std::string, InventoryItem*>
|
|
*/
|
|
util::Map<std::string, InventoryItem*> InventoryManagementService::getInventoryItems()
|
|
{
|
|
return m_dataStore.getInventoryItems();
|
|
}
|
|
|
|
/*
|
|
Function: removeInventoryItem
|
|
Description: Marks an inventory item as inactive instead of deleting it.
|
|
Parameter: const std::string& inventoryItemID - ID of the inventory item
|
|
Return type: void
|
|
*/
|
|
void InventoryManagementService::removeInventoryItem(const std::string& inventoryItemID)
|
|
{
|
|
int index = m_dataStore.getInventoryItems().find(inventoryItemID);
|
|
if (index != -1)
|
|
{
|
|
InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index);
|
|
if (item != nullptr)
|
|
{
|
|
item->setState(util::State::INACTIVE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Function: getInventoryItem
|
|
Description: Retrieves a specific inventory item by its ID from the DataStore.
|
|
Parameter: const std::string& inventoryItemID - ID of the inventory item
|
|
Return type: InventoryItem*
|
|
*/
|
|
InventoryItem* InventoryManagementService::getInventoryItem(const std::string& inventoryItemID)
|
|
{
|
|
int index = m_dataStore.getInventoryItems().find(inventoryItemID);
|
|
if (index != -1)
|
|
{
|
|
return m_dataStore.getInventoryItems().getValueAt(index);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/*
|
|
Function: attach
|
|
Description: Adds a user to the observer list for receiving inventory notifications.
|
|
Parameters:
|
|
- user: User*, pointer to the user to be attached as an observer
|
|
Returns:
|
|
- None
|
|
*/
|
|
void InventoryManagementService::attach(User* user)
|
|
{
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
m_observers.clear();
|
|
m_observers = m_dataStore.getInventoryManagementObservers();
|
|
if (user)
|
|
{
|
|
const std::string& userID = user->getId();
|
|
if (m_observers.find(userID) == -1)
|
|
{
|
|
m_observers[userID] = user;
|
|
}
|
|
}
|
|
m_dataStore.saveInventoryManagementObservers(m_observers);
|
|
}
|
|
|
|
/*
|
|
Function: detach
|
|
Description: Removes a user from the observer list so they no longer receive inventory notifications.
|
|
Parameters:
|
|
- user: User*, pointer to the user to be detached from the observer list
|
|
Returns:
|
|
- None
|
|
*/
|
|
void InventoryManagementService::detach(User* user)
|
|
{
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
m_observers.clear();
|
|
m_observers = m_dataStore.getInventoryManagementObservers();
|
|
if (user)
|
|
{
|
|
const std::string& userID = user->getId();
|
|
if (m_observers.find(userID) != -1)
|
|
{
|
|
m_observers.remove(userID);
|
|
}
|
|
}
|
|
m_dataStore.saveInventoryManagementObservers(m_observers);
|
|
}
|
|
|
|
/*
|
|
Function: sendNotification
|
|
Description: Sends a notification to a user if they are subscribed as an observer.
|
|
Parameters:
|
|
- user: User*, pointer to the user receiving the notification
|
|
- title: std::string, title of the notification
|
|
- message: std::string, body/content of the notification
|
|
Returns:
|
|
- None
|
|
Throws:
|
|
- std::runtime_error if notification creation fails
|
|
*/
|
|
void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message)
|
|
{
|
|
if (!user)
|
|
{
|
|
return;
|
|
}
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
m_observers = m_dataStore.getInventoryManagementObservers();
|
|
if (m_observers.find(user->getId()) == -1)
|
|
{
|
|
return;
|
|
}
|
|
Notification* notification = Factory::getObject<Notification>(
|
|
user->getId(),
|
|
title,
|
|
message,
|
|
util::Timestamp());
|
|
if (!notification)
|
|
{
|
|
throw std::runtime_error("Failed to create notification");
|
|
}
|
|
auto& trackedNotificationsMap = m_dataStore.getNotifications();
|
|
trackedNotificationsMap.insert(notification->getId(), util::createNewRecord(notification));
|
|
m_dataStore.saveNotifications();
|
|
}
|
|
|