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 "UserManagementService.h"
#include "Utility.h"
#include "ComboPackage.h"
/*
Function: purchaseService
@@ -909,9 +910,27 @@ Throws:
void ServiceManagementService::removeService(const std::string& serviceID)
{
util::Map<std::string, Service*>& currentServices = m_dataStore.getServices();
util::Map<std::string, ComboPackage*>& currentComboPackages = m_dataStore.getComboPackages();
if (currentServices.find(serviceID) != -1)
{
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
{
@@ -420,17 +420,19 @@ Returns:
void AdminMenu::removeService()
{
util::clear();
std::cout << "Remove Service\n";
std::string selectedServiceID;
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 != "")
{
m_controller.removeService(selectedServiceID);
std::cout << "Service removed sucessfully.";
std::cout << "Service removed sucessfully.\n\n";
}
else
{
std::cout << "Failed to remove service.";
std::cout << "Failed to remove service.\n\n";
}
util::pressEnter();
}
@@ -527,7 +529,10 @@ Return type: void
void AdminMenu::createComboPackages()
{
util::clear();
std::cout << "Create Combo Packages\n";
auto serviceList = m_controller.getServices();
auto activeServices = filterActiveServices(serviceList);
int currentActiveServicesCount = activeServices.getSize();
const int NUMBER_OF_SERVICE_PER_PACKAGE = 2;
util::Vector<std::string> selectedServiceID;
for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++)
@@ -535,10 +540,10 @@ void AdminMenu::createComboPackages()
const Service* chosenService = nullptr;
while (true)
{
chosenService = selectServiceFromServices(serviceList);
chosenService = selectServiceFromServices(activeServices);
if (chosenService == nullptr)
{
std::cout << "Failed to create combo package!";
std::cout << "Failed to create combo package!\n\n";
util::pressEnter();
return;
}
@@ -553,11 +558,19 @@ void AdminMenu::createComboPackages()
}
if (alreadyChosen)
{
if (currentActiveServicesCount < 2)
{
break;
}
std::cout << "Service already selected. Please choose a different one." << std::endl;
continue;
}
selectedServiceID.push_back(chosenService->getId());
util::clear();
break;
}
if (currentActiveServicesCount < 2)
{
std::cout << "All the available services selected\n\n";
break;
}
}
@@ -587,16 +600,17 @@ Return type: void
void AdminMenu::removeComboPackage()
{
util::clear();
std::cout << "Remove Combo Package\n";
util::Map<std::string, const ComboPackage*> currentComboPackages = m_controller.getComboPackages();
std::string selectedComboPackageID = selectComboPackage(currentComboPackages);
if (selectedComboPackageID != "")
if (!selectedComboPackageID.empty())
{
m_controller.removeComboPackage(selectedComboPackageID);
std::cout << "Combo Package removed successfully.\n";
std::cout << "Combo Package removed successfully.\n\n";
}
else
{
std::cout << "Combo package removal failed.\n";
std::cout << "Combo package removal failed.\n\n";
}
util::pressEnter();
}
@@ -39,8 +39,12 @@ Returns:
*/
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;
bool hasServices = false;
int currentIndex = 1, choice;
std::cout << std::left
<< std::setw(6) << "Index"
@@ -51,7 +55,7 @@ inline std::string selectServicesToRemove(util::Map<std::string, const Service*>
for (int iterator = 0; iterator < currentServices.getSize(); iterator++)
{
const Service* currentService = currentServices.getValueAt(iterator);
if (currentService->getState() == util::State::INACTIVE)
if (currentService == nullptr || currentService->getState() == util::State::INACTIVE)
{
continue;
}
@@ -61,14 +65,8 @@ inline std::string selectServicesToRemove(util::Map<std::string, const Service*>
<< std::setw(20) << currentService->getName()
<< std::setw(10) << currentService->getLaborCost()
<< std::endl;
hasServices = true;
currentServicesMap.insert(currentIndex++, currentService);
}
if (!hasServices)
{
std::cout << "No services currently available." << std::endl;
return "";
}
std::cout << "Enter your choice: ";
util::read(choice);
if (currentServicesMap.find(choice) != -1)
@@ -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
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)
{
if (services.getSize() == 0)
{
std::cout << "No active services available." << std::endl;
return nullptr;
}
util::Map<int, const Service*> activeServicesMap;
int currentIndex = 1;
int userInputIndex;
std::cout << std::endl;
std::cout << std::left
<< std::setw(10) << "Index"
<< 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;
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;
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)
{
throw std::runtime_error("No combo packages currently active.");
std::cout << "No combo packages currently active.\n";
return "";
}
displayComboPackagesWithIndex(currentComboPackageIndexMap);
std::cout << "Enter your choice(Index): ";