8aaa4eeec0
Changes: - Implements #2061 - Introduce EventManager for user-specific Windows event publishing/listening - Add real-time notification and account-disabled event propagation - Register authentication events through Controller and AuthenticationManagementService - Trigger notification events from Inventory, Payment, and Service Management modules - Trigger account-disabled events when users are deactivated - Extract common menu event listener logic into Menu base class - Add notification popup handling for Admin, Customer, and Technician menus - Refactor shared memory components into core/sharedmemory - Update project structure and include paths for events and shared memory modules
288 lines
8.9 KiB
C++
288 lines
8.9 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 "InventoryItem.h"
|
|
#include "InventoryManagementService.h"
|
|
#include "Timestamp.h"
|
|
#include "User.h"
|
|
#include "Utility.h"
|
|
#include "Vector.h"
|
|
#include "DataStoreLockGuard.h"
|
|
#include "EventManager.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()
|
|
{
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
auto& trackedInventoryItemsMap = m_dataStore.getInventoryItems();
|
|
auto& trackedUserMap = m_dataStore.getUsers();
|
|
if (trackedInventoryItemsMap.isEmpty())
|
|
{
|
|
return;
|
|
}
|
|
int inventoryItemsSize = trackedInventoryItemsMap.getSize();
|
|
int usersMapSize = trackedUserMap.getSize();
|
|
util::Vector<User*> adminUsers;
|
|
for (int index = 0; index < usersMapSize; index++)
|
|
{
|
|
User* user = trackedUserMap.getValueAt(index).data;
|
|
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 = trackedInventoryItemsMap.getValueAt(index).data;
|
|
if (inventoryItem && inventoryItem->getQuantity() < config::threshold::INVENTORY_LOW_STOCK_THRESHOLD)
|
|
{
|
|
sendLowStockAlertsToAdmins(*this, inventoryItem, adminUsers);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
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)
|
|
{
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
|
|
InventoryItem* newItem = Factory::getObject<InventoryItem>(partName, quantity, price);
|
|
trackedInventoryItemMap.insert(newItem->getId(), util::createNewRecord(newItem));
|
|
m_dataStore.saveInventoryItems();
|
|
}
|
|
|
|
/*
|
|
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)
|
|
{
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
|
|
int index = trackedInventoryItemMap.find(selectedItemId);
|
|
if (index == -1)
|
|
{
|
|
throw std::runtime_error("Inventory update failed: Item ID '" + selectedItemId + "' not found.");
|
|
}
|
|
InventoryItem* item = trackedInventoryItemMap.getValueAt(index).data;
|
|
if (item == nullptr)
|
|
{
|
|
throw std::runtime_error("Inventory update failed. Item does not exist.\n");
|
|
}
|
|
int totalQuantity = item->getQuantity() + quantity;
|
|
item->setQuantity(totalQuantity);
|
|
trackedInventoryItemMap.getValueAt(index).state = RecordState::MODIFIED;
|
|
m_dataStore.saveInventoryItems();
|
|
}
|
|
|
|
/*
|
|
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()
|
|
{
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
|
|
auto inventoryMap = util::getObjects(trackedInventoryItemMap);
|
|
return inventoryMap;
|
|
}
|
|
|
|
/*
|
|
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)
|
|
{
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
|
|
int index = trackedInventoryItemMap.find(inventoryItemID);
|
|
if (index == -1)
|
|
{
|
|
throw std::runtime_error("Inventory removal failed: Item ID '" + inventoryItemID + "' not found.");
|
|
}
|
|
InventoryItem* item = trackedInventoryItemMap.getValueAt(index).data;
|
|
if (item == nullptr)
|
|
{
|
|
throw std::runtime_error("Inventory removal failed: Item ID does not exist.");
|
|
}
|
|
item->setState(util::State::INACTIVE);
|
|
trackedInventoryItemMap.getValueAt(index).state = RecordState::MODIFIED;
|
|
m_dataStore.saveInventoryItems();
|
|
}
|
|
|
|
/*
|
|
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)
|
|
{
|
|
DataStoreLockGuard lock(m_dataStore);
|
|
auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
|
|
int index = trackedInventoryItemMap.find(inventoryItemID);
|
|
if (index == -1)
|
|
{
|
|
return nullptr;
|
|
}
|
|
InventoryItem* inventoryItem = trackedInventoryItemMap.getValueAt(index).data;
|
|
if (inventoryItem == nullptr)
|
|
{
|
|
throw std::runtime_error("Item ID does not exist.");
|
|
}
|
|
return inventoryItem;
|
|
}
|
|
|
|
/*
|
|
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();
|
|
EventManager::sendNotificationAvailableEvent(user->getId());
|
|
}
|
|
|