Fix Service Removal and Combo Package Management Issues

- Added ComboPackage dependency check in removeService; deactivates related packages when a service is removed.
- Added filterActiveServices helper to list only active services.
- Updated removeService and removeComboPackage with headings, empty-state checks, and consistent success/error messages.
- Enhanced createComboPackages:
  - Uses active services only.
  - Added cancel option and confirmation after first selection.
  - Prevented duplicate selection and infinite loop when limited services exist.
  - Improved feedback when all available services are selected.
- Updated selectServicesToRemove and selectComboPackage to handle empty states gracefully without exceptions.

Fixes #1749
This commit is contained in:
Jissin Mathew
2026-05-26 21:04:30 +05:30
committed by Joel Thomas
parent 7646ce6644
commit 8268b90d82
3 changed files with 83 additions and 22 deletions
@@ -26,6 +26,7 @@ Date:19-May-2026
#include "User.h" #include "User.h"
#include "UserManagementService.h" #include "UserManagementService.h"
#include "Utility.h" #include "Utility.h"
#include "ComboPackage.h"
/* /*
Function: purchaseService Function: purchaseService
@@ -909,9 +910,27 @@ Throws:
void ServiceManagementService::removeService(const std::string& serviceID) void ServiceManagementService::removeService(const std::string& serviceID)
{ {
util::Map<std::string, Service*>& currentServices = m_dataStore.getServices(); util::Map<std::string, Service*>& currentServices = m_dataStore.getServices();
util::Map<std::string, ComboPackage*>& currentComboPackages = m_dataStore.getComboPackages();
if (currentServices.find(serviceID) != -1) if (currentServices.find(serviceID) != -1)
{ {
currentServices.getValueAt(currentServices.find(serviceID))->setState(util::State::INACTIVE); currentServices.getValueAt(currentServices.find(serviceID))->setState(util::State::INACTIVE);
for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++)
{
ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator);
if (currentComboPackage && currentComboPackage->getState() == util::State::ACTIVE)
{
util::Map<std::string, Service*> currentServices = currentComboPackage->getServices();
for (int iterator = 0; iterator < currentServices.getSize(); iterator++)
{
auto currentService = currentServices.getValueAt(iterator);
if (currentService->getId() == serviceID)
{
currentComboPackage->setState(util::State::INACTIVE);
break;
}
}
}
}
} }
else else
{ {
@@ -420,17 +420,19 @@ Returns:
void AdminMenu::removeService() void AdminMenu::removeService()
{ {
util::clear(); util::clear();
std::cout << "Remove Service\n";
std::string selectedServiceID; std::string selectedServiceID;
util::Map<std::string, const Service*> currentServices = m_controller.getServices(); util::Map<std::string, const Service*> currentServices = m_controller.getServices();
selectedServiceID = selectServicesToRemove(currentServices); util::Map<std::string, const Service*> currentActiveServices = filterActiveServices(currentServices);
selectedServiceID = selectServicesToRemove(currentActiveServices);
if (selectedServiceID != "") if (selectedServiceID != "")
{ {
m_controller.removeService(selectedServiceID); m_controller.removeService(selectedServiceID);
std::cout << "Service removed sucessfully."; std::cout << "Service removed sucessfully.\n\n";
} }
else else
{ {
std::cout << "Failed to remove service."; std::cout << "Failed to remove service.\n\n";
} }
util::pressEnter(); util::pressEnter();
} }
@@ -527,7 +529,10 @@ Return type: void
void AdminMenu::createComboPackages() void AdminMenu::createComboPackages()
{ {
util::clear(); util::clear();
std::cout << "Create Combo Packages\n";
auto serviceList = m_controller.getServices(); auto serviceList = m_controller.getServices();
auto activeServices = filterActiveServices(serviceList);
int currentActiveServicesCount = activeServices.getSize();
const int NUMBER_OF_SERVICE_PER_PACKAGE = 2; const int NUMBER_OF_SERVICE_PER_PACKAGE = 2;
util::Vector<std::string> selectedServiceID; util::Vector<std::string> selectedServiceID;
for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++) for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++)
@@ -535,10 +540,10 @@ void AdminMenu::createComboPackages()
const Service* chosenService = nullptr; const Service* chosenService = nullptr;
while (true) while (true)
{ {
chosenService = selectServiceFromServices(serviceList); chosenService = selectServiceFromServices(activeServices);
if (chosenService == nullptr) if (chosenService == nullptr)
{ {
std::cout << "Failed to create combo package!"; std::cout << "Failed to create combo package!\n\n";
util::pressEnter(); util::pressEnter();
return; return;
} }
@@ -553,13 +558,21 @@ void AdminMenu::createComboPackages()
} }
if (alreadyChosen) if (alreadyChosen)
{ {
if (currentActiveServicesCount < 2)
{
break;
}
std::cout << "Service already selected. Please choose a different one." << std::endl; std::cout << "Service already selected. Please choose a different one." << std::endl;
continue; continue;
} }
selectedServiceID.push_back(chosenService->getId()); selectedServiceID.push_back(chosenService->getId());
util::clear();
break; break;
} }
if (currentActiveServicesCount < 2)
{
std::cout << "All the available services selected\n\n";
break;
}
} }
std::string packageName; std::string packageName;
double discountPercentage; double discountPercentage;
@@ -587,16 +600,17 @@ Return type: void
void AdminMenu::removeComboPackage() void AdminMenu::removeComboPackage()
{ {
util::clear(); util::clear();
std::cout << "Remove Combo Package\n";
util::Map<std::string, const ComboPackage*> currentComboPackages = m_controller.getComboPackages(); util::Map<std::string, const ComboPackage*> currentComboPackages = m_controller.getComboPackages();
std::string selectedComboPackageID = selectComboPackage(currentComboPackages); std::string selectedComboPackageID = selectComboPackage(currentComboPackages);
if (selectedComboPackageID != "") if (!selectedComboPackageID.empty())
{ {
m_controller.removeComboPackage(selectedComboPackageID); m_controller.removeComboPackage(selectedComboPackageID);
std::cout << "Combo Package removed successfully.\n"; std::cout << "Combo Package removed successfully.\n\n";
} }
else else
{ {
std::cout << "Combo package removal failed.\n"; std::cout << "Combo package removal failed.\n\n";
} }
util::pressEnter(); util::pressEnter();
} }
@@ -39,8 +39,12 @@ Returns:
*/ */
inline std::string selectServicesToRemove(util::Map<std::string, const Service*> currentServices) inline std::string selectServicesToRemove(util::Map<std::string, const Service*> currentServices)
{ {
if (currentServices.getSize() == 0)
{
std::cout << "No Services Currently Available.\n";
return "";
}
util::Map<int, const Service*> currentServicesMap; util::Map<int, const Service*> currentServicesMap;
bool hasServices = false;
int currentIndex = 1, choice; int currentIndex = 1, choice;
std::cout << std::left std::cout << std::left
<< std::setw(6) << "Index" << std::setw(6) << "Index"
@@ -51,23 +55,17 @@ inline std::string selectServicesToRemove(util::Map<std::string, const Service*>
for (int iterator = 0; iterator < currentServices.getSize(); iterator++) for (int iterator = 0; iterator < currentServices.getSize(); iterator++)
{ {
const Service* currentService = currentServices.getValueAt(iterator); const Service* currentService = currentServices.getValueAt(iterator);
if (currentService->getState() == util::State::INACTIVE) if (currentService == nullptr || currentService->getState() == util::State::INACTIVE)
{ {
continue; continue;
} }
std::cout << std::left std::cout << std::left
<< std::setw(6) << currentIndex << std::setw(6) << currentIndex
<< std::setw(12) << currentService->getId() << std::setw(12) << currentService->getId()
<< std::setw(20) << currentService->getName() << std::setw(20) << currentService->getName()
<< std::setw(10) << currentService->getLaborCost() << std::setw(10) << currentService->getLaborCost()
<< std::endl; << std::endl;
hasServices = true;
currentServicesMap.insert(currentIndex++, currentService); currentServicesMap.insert(currentIndex++, currentService);
}
if (!hasServices)
{
std::cout << "No services currently available." << std::endl;
return "";
} }
std::cout << "Enter your choice: "; std::cout << "Enter your choice: ";
util::read(choice); util::read(choice);
@@ -744,6 +742,28 @@ inline void displayAllActiveUsers(util::Map<std::string, const User*>& activeUse
} }
} }
/*
Function: filterActiveServices
Description: Filters the given list of services and returns only those that are active.
Parameters:
- serviceList: Map of service IDs to Service pointers.
Returns:
- util::Map<std::string, const Service*> containing only active services.
*/
inline util::Map<std::string, const Service*> filterActiveServices(util::Map<std::string, const Service*> serviceList)
{
util::Map<std::string, const Service*> activeServices;
for (int iterator = 0; iterator < serviceList.getSize(); iterator++)
{
const Service* currentService = serviceList.getValueAt(iterator);
if (currentService && currentService->getState() == util::State::ACTIVE)
{
activeServices.insert(currentService->getId(), currentService);
}
}
return activeServices;
}
/* /*
Function: selectServiceFromServices Function: selectServiceFromServices
Description: Displays active services and allows the customer to select one by index. Description: Displays active services and allows the customer to select one by index.
@@ -752,9 +772,15 @@ Return type: const Service* - selected service
*/ */
inline const Service* selectServiceFromServices(const util::Map<std::string, const Service*>& services) inline const Service* selectServiceFromServices(const util::Map<std::string, const Service*>& services)
{ {
if (services.getSize() == 0)
{
std::cout << "No active services available." << std::endl;
return nullptr;
}
util::Map<int, const Service*> activeServicesMap; util::Map<int, const Service*> activeServicesMap;
int currentIndex = 1; int currentIndex = 1;
int userInputIndex; int userInputIndex;
std::cout << std::endl;
std::cout << std::left std::cout << std::left
<< std::setw(10) << "Index" << std::setw(10) << "Index"
<< std::setw(15) << "Service ID" << std::setw(15) << "Service ID"
@@ -1030,7 +1056,8 @@ inline std::string selectComboPackage(util::Map<std::string, const ComboPackage*
util::Map<int, const ComboPackage*> currentComboPackageIndexMap; util::Map<int, const ComboPackage*> currentComboPackageIndexMap;
if (currentComboPackages.getSize() == 0) if (currentComboPackages.getSize() == 0)
{ {
throw std::runtime_error("No combo packages are available.\n"); std::cout << "No combo packages are available.\n";
return "";
} }
int currentIndex = 1, choice, selectedIndex; int currentIndex = 1, choice, selectedIndex;
for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++) for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++)
@@ -1043,7 +1070,8 @@ inline std::string selectComboPackage(util::Map<std::string, const ComboPackage*
} }
if (currentComboPackageIndexMap.getSize() == 0) if (currentComboPackageIndexMap.getSize() == 0)
{ {
throw std::runtime_error("No combo packages currently active."); std::cout << "No combo packages currently active.\n";
return "";
} }
displayComboPackagesWithIndex(currentComboPackageIndexMap); displayComboPackagesWithIndex(currentComboPackageIndexMap);
std::cout << "Enter your choice(Index): "; std::cout << "Enter your choice(Index): ";