Implement Create Combo Package Functionality
<UserStory> ADM006:Create Combo Package </UserStory>
<Changes>
1. Added ServiceManagementService::createComboPackage to validate package name, included services, and discount percentage before creation.
2. Integrated Controller::createComboPackage to delegate combo package creation to ServiceManagementService.
3. Enhanced AdminMenu::createComboPackages to allow admin input for package name, service selection, and discount percentage.
4. Implemented service validation to ensure only active services are selectable and that duplicate combos are prevented.
5. Added formatted output for service listing with cost calculation and confirmation messages upon successful package creation.
</Changes>
<Test>
Precondition:
1. Admin is logged into the system.
2. At least two active services exist in the system.
3. ServiceManagementService is connected to DataStore for services and combo packages.
Steps:
1. Navigate to Admin Menu and select "Create Combo Package".
2. Enter package name, select two active services, and provide discount percentage.
- Verify that system validates service IDs and ensures discount is between 0 and 100.
3. Attempt to create a package with invalid service IDs or duplicate services.
- Verify that system rejects with appropriate error messages.
4. Enter valid package details.
- Verify that combo package is saved successfully and visible to customers.
</Test>
<Review>
Sreeja Reghukumar
</Review>
This commit is contained in:
+1
@@ -176,6 +176,7 @@
|
||||
<ClInclude Include="utilities\Map.h" />
|
||||
<ClInclude Include="utilities\OutputHelper.h" />
|
||||
<ClInclude Include="utilities\Timestamp.h" />
|
||||
<ClInclude Include="utilities\Utility.h" />
|
||||
<ClInclude Include="utilities\Validator.h" />
|
||||
<ClInclude Include="utilities\Vector.h" />
|
||||
<ClInclude Include="views\AdminMenu.h" />
|
||||
|
||||
+3
@@ -233,5 +233,8 @@
|
||||
<ClInclude Include="models\ComboPackage.h">
|
||||
<Filter>Header Files\Models</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="utilities\Utility.h">
|
||||
<Filter>Header Files\Utilities</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -113,6 +113,7 @@ void Controller::removeUser(const std::string& userID)
|
||||
|
||||
void Controller::createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage)
|
||||
{
|
||||
m_serviceManagementService.createComboPackage(name, serviceIDs, discountPercentage);
|
||||
}
|
||||
|
||||
void Controller::removeComboPackage(const std::string& comboPackageID)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Map.h"
|
||||
#include <string>
|
||||
#include "Enums.h"
|
||||
#include "ServiceManagementService.h"
|
||||
|
||||
class Service;
|
||||
class ComboPackage;
|
||||
@@ -14,6 +15,8 @@ class Notification;
|
||||
|
||||
class Controller
|
||||
{
|
||||
private:
|
||||
ServiceManagementService m_serviceManagementService;
|
||||
public:
|
||||
bool login(const std::string& username, const std::string& password);
|
||||
void logout();
|
||||
|
||||
+63
@@ -1 +1,64 @@
|
||||
#include "ServiceManagementService.h"
|
||||
#include "Factory.h"
|
||||
#include "ComboPackage.h"
|
||||
|
||||
void ServiceManagementService::createComboPackage(const std::string& packageName, const util::Vector<std::string>& serviceIDsInNewCombo, double discountPercentage)
|
||||
{
|
||||
if (packageName.empty())
|
||||
{
|
||||
throw std::invalid_argument("The Combo Package Name cannot be empty.\n");
|
||||
}
|
||||
if (serviceIDsInNewCombo.getSize() < 2 || serviceIDsInNewCombo.getSize() > 2)
|
||||
{
|
||||
throw std::invalid_argument("Combo package must contain only two services.");
|
||||
}
|
||||
if (discountPercentage < 0.0 || discountPercentage > 100.0)
|
||||
{
|
||||
throw std::invalid_argument("Discount percentage must be between 0 and 100.");
|
||||
}
|
||||
auto& servicesMap = m_dataStore.getServices();
|
||||
for (int index = 0; index < serviceIDsInNewCombo.getSize(); index++)
|
||||
{
|
||||
const std::string serviceid = serviceIDsInNewCombo[index];
|
||||
if (servicesMap.find(serviceid) == -1)
|
||||
{
|
||||
throw std::runtime_error("Service ID not found: " + serviceid);
|
||||
}
|
||||
}
|
||||
auto& comboPackageMap = m_dataStore.getComboPackages();
|
||||
for (int iterator = 0; iterator < comboPackageMap.getSize(); iterator++)
|
||||
{
|
||||
ComboPackage* existingCombos = comboPackageMap.getValueAt(iterator);
|
||||
const util::Map<std::string, Service*>& servicesInsideExistingCombos = existingCombos->getServices();
|
||||
if (servicesInsideExistingCombos.getSize() == serviceIDsInNewCombo.getSize())
|
||||
{
|
||||
bool isIdentical = true;
|
||||
for (int serviceIterator = 0; serviceIterator < serviceIDsInNewCombo.getSize(); serviceIterator++)
|
||||
{
|
||||
const std::string& id = serviceIDsInNewCombo[serviceIterator];
|
||||
if (servicesInsideExistingCombos.find(id) == -1)
|
||||
{
|
||||
isIdentical = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isIdentical)
|
||||
{
|
||||
throw std::runtime_error("A combo package with the same services already exists.");
|
||||
}
|
||||
}
|
||||
}
|
||||
util::Map<std::string, Service*> selectedServices;
|
||||
for (int iteratorOne = 0; iteratorOne < serviceIDsInNewCombo.getSize(); iteratorOne++)
|
||||
{
|
||||
const std::string& serviceId = serviceIDsInNewCombo[iteratorOne];
|
||||
int serviceIndex = servicesMap.find(serviceId);
|
||||
if (serviceIndex == -1)
|
||||
{
|
||||
throw std::runtime_error("Service ID not found: " + serviceId);
|
||||
}
|
||||
selectedServices.insert(serviceId, servicesMap.getValueAt(serviceIndex));
|
||||
}
|
||||
ComboPackage* newComboPackage = Factory::getObject<ComboPackage>(packageName, discountPercentage, selectedServices);
|
||||
comboPackageMap.insert(newComboPackage->getId(), newComboPackage);
|
||||
}
|
||||
+1
-1
@@ -29,7 +29,7 @@ public:
|
||||
void completeJob(const std::string& jobID);
|
||||
void cancelCustomerServiceBookings(const std::string& customerID);
|
||||
void cancelTechnicianJobs(const std::string& technicianID);
|
||||
void createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage);
|
||||
void createComboPackage(const std::string& packageName, const util::Vector<std::string>& serviceIDs, double discountPercentage);
|
||||
void removeComboPackage(const std::string& comboPackageID);
|
||||
void sendNotification(User* user, const std::string& title, const std::string& message) override;
|
||||
void attach(User* user) override;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "Service.h"
|
||||
#include "InventoryItem.h"
|
||||
|
||||
inline double calculatePartsCost(const Service* service)
|
||||
{
|
||||
double cost = 0;
|
||||
auto& requiredInventoryItems = service->getRequiredInventoryItems();
|
||||
int requiredInventoryItemsSize = requiredInventoryItems.getSize();
|
||||
for (int index = 0; index < requiredInventoryItemsSize; index++)
|
||||
{
|
||||
cost += requiredInventoryItems.getValueAt(index)->getPrice();
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
#include <iomanip>
|
||||
#include "AdminMenu.h"
|
||||
#include "InputHelper.h"
|
||||
#include "OutputHelper.h"
|
||||
#include "Service.h"
|
||||
#include "Utility.h"
|
||||
|
||||
void AdminMenu::showMenu()
|
||||
{
|
||||
@@ -76,8 +79,82 @@ void AdminMenu::removeUser()
|
||||
{
|
||||
}
|
||||
|
||||
static const Service* selectServiceFromServices(const util::Map<std::string, const Service*>& services)
|
||||
{
|
||||
util::Map<int, const Service*> activeServicesMap;
|
||||
int currentIndex = 1;
|
||||
int userInputIndex;
|
||||
std::cout << std::left
|
||||
<< std::setw(10) << "Index"
|
||||
<< std::setw(15) << "Service ID"
|
||||
<< std::setw(25) << "Service Name"
|
||||
<< std::setw(15) << "Estimated Cost"
|
||||
<< std::endl;
|
||||
for (int index = 0; index < services.getSize(); index++)
|
||||
{
|
||||
const Service* currentService = services.getValueAt(index);
|
||||
if (currentService->getState() != util::State::ACTIVE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
activeServicesMap.insert(currentIndex, currentService);
|
||||
double partsCost = calculatePartsCost(currentService);
|
||||
std::cout << std::left
|
||||
<< std::setw(10) << currentIndex
|
||||
<< std::setw(15) << currentService->getId()
|
||||
<< std::setw(25) << currentService->getName()
|
||||
<< std::setw(15) << (currentService->getLaborCost() + partsCost)
|
||||
<< std::endl;
|
||||
currentIndex++;
|
||||
}
|
||||
if (activeServicesMap.getSize() == 0)
|
||||
{
|
||||
std::cout << "No active services available." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
std::cout << "Enter service index: ";
|
||||
util::read(userInputIndex);
|
||||
if (activeServicesMap.find(userInputIndex) == -1)
|
||||
{
|
||||
std::cout << "Invalid service index." << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
return activeServicesMap[userInputIndex];
|
||||
}
|
||||
|
||||
void AdminMenu::createComboPackages()
|
||||
{
|
||||
util::clear();
|
||||
auto serviceList = m_controller.getServices();
|
||||
const int numberOfServicesInPackage = 2;
|
||||
util::Vector<std::string> selectedServiceID;
|
||||
for (int iterator = 0; iterator < numberOfServicesInPackage; iterator++)
|
||||
{
|
||||
const Service* chosenService = selectServiceFromServices(serviceList);
|
||||
if (chosenService == nullptr)
|
||||
{
|
||||
std::cout << "Failed to create combo package!";
|
||||
util::pressEnter();
|
||||
return;
|
||||
}
|
||||
selectedServiceID.push_back(chosenService->getId());
|
||||
util::clear();
|
||||
}
|
||||
std::string packageName;
|
||||
double discountPercentage;
|
||||
std::cout << "Enter combo package name: ";
|
||||
util::read(packageName);
|
||||
std::cout << "Enter discount percentage: ";
|
||||
util::read(discountPercentage);
|
||||
if (discountPercentage < 0.0 || discountPercentage > 100.0)
|
||||
{
|
||||
std::cout << "Error: Discount percentage must be between 0 and 100." << std::endl;
|
||||
util::pressEnter();
|
||||
return;
|
||||
}
|
||||
m_controller.createComboPackage(packageName, selectedServiceID, discountPercentage);
|
||||
std::cout << "Combo package '" << packageName << "' created successfully." << std::endl;
|
||||
util::pressEnter();
|
||||
}
|
||||
|
||||
void AdminMenu::removeComboPackage()
|
||||
|
||||
Reference in New Issue
Block a user