Merged PR 1114: Fix Admin Menu, Service Management, Technician Assignment, and Invoice Display Issues

**Changes:**

- Fixed booking status flow (PENDING → STARTED) during job card creation
- Updated purchaseService to initialize bookings with PENDING status
- Filtered active users and services before listing/selection
- Improved Assign Job flow: pending bookings only, clearer technician prompts, consistent feedback
- Enhanced View Invoices: reference parameter, empty items handling, improved formatting
- Added filterActiveServices helper for consistent active service filtering
- Fixed Remove Service to also deactivate dependent combo packages
- Improved Create Combo Packages: cancel option, confirmation step, duplicate/edge case handling
- Updated Remove Combo Package to handle empty states gracefully without exceptions

Related work items: #1646, #1740, #1744, #1745, #1747, #1749, #1752
This commit is contained in:
Jissin Mathew
2026-05-26 21:26:37 +05:30
6 changed files with 306 additions and 196 deletions
@@ -23,10 +23,10 @@ Date:19-May-2026
#include "ServiceBooking.h" #include "ServiceBooking.h"
#include "ServiceManagementService.h" #include "ServiceManagementService.h"
#include "Timestamp.h" #include "Timestamp.h"
#include "Timestamp.h"
#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
@@ -817,6 +817,10 @@ void ServiceManagementService::createJobCard(const std::string& bookingID, const
} }
currentBooking->setAssignedTechnician(selectedTechnician); currentBooking->setAssignedTechnician(selectedTechnician);
currentBooking->setAssignedTechnicianId(selectedTechnician->getId()); currentBooking->setAssignedTechnicianId(selectedTechnician->getId());
if (currentBooking->getStatus() == util::ServiceJobStatus::PENDING)
{
currentBooking->setStatus(util::ServiceJobStatus::STARTED);
}
std::string title = "Job card created"; std::string title = "Job card created";
std::string message = "Job card created for the service and you are assigned for that."; std::string message = "Job card created for the service and you are assigned for that.";
JobCard* jobCard = Factory::getObject<JobCard>(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::Timestamp(), util::ServiceJobStatus::STARTED, util::Timestamp()); JobCard* jobCard = Factory::getObject<JobCard>(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::Timestamp(), util::ServiceJobStatus::STARTED, util::Timestamp());
@@ -906,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
{ {
@@ -315,7 +315,7 @@ util::Map<std::string, User*> UserManagementService::getUsers(util::UserType typ
for (int iterator = 0; iterator < currentUsers.getSize(); iterator++) for (int iterator = 0; iterator < currentUsers.getSize(); iterator++)
{ {
User* currentUser = currentUsers.getValueAt(iterator); User* currentUser = currentUsers.getValueAt(iterator);
if (currentUser->getUserType() == type) if (currentUser && currentUser->getState() == util::State::ACTIVE && currentUser->getUserType() == type)
{ {
filteredUsersMap.insert(currentUser->getId(), currentUser); filteredUsersMap.insert(currentUser->getId(), currentUser);
} }
@@ -218,13 +218,15 @@ void AdminMenu::addInventoryItem()
int choice, quantity; int choice, quantity;
double price; double price;
std::string partName; std::string partName;
std::cout << "1. Add new item \n2. Add Quantity\nEnter your choice : "; std::cout << "Add Inventory Item\n";
std::cout << "1. Add new item \n2. Restock Item\n\nEnter your choice : ";
util::read(choice); util::read(choice);
switch (choice) switch (choice)
{ {
case 1: case 1:
{ {
std::cout << "--------Enter Item Details----------\n"; util::clear();
std::cout << "Enter Item Details\n";
std::cout << "Part Name : "; std::cout << "Part Name : ";
util::read(partName); util::read(partName);
std::cout << "Quantity : "; std::cout << "Quantity : ";
@@ -232,15 +234,21 @@ void AdminMenu::addInventoryItem()
std::cout << "Price : "; std::cout << "Price : ";
util::read(price); util::read(price);
m_controller.addInventoryItem(partName, quantity, price); m_controller.addInventoryItem(partName, quantity, price);
std::cout << "New Item " << partName << " added to the Inventory.\n"; std::cout << "\nNew Item " << partName << " added to the Inventory.\n\n";
break; break;
} }
case 2: case 2:
{ {
util::clear();
std::cout << "Select Item to Restock\n";
auto inventoryItems = m_controller.getInventoryItems(); auto inventoryItems = m_controller.getInventoryItems();
addQuantityToItem(inventoryItems, m_controller); addQuantityToItem(inventoryItems, m_controller);
break; break;
} }
default:
{
std::cout << "\nEnter a valid choice.\n\n";
}
} }
util::pressEnter(); util::pressEnter();
} }
@@ -333,14 +341,16 @@ Returns:
void AdminMenu::assignJob() void AdminMenu::assignJob()
{ {
util::clear(); util::clear();
std::cout << "Assign Job to Technician\n";
std::string selectedService; std::string selectedService;
bool hasPendingService = false; bool hasPendingService = false;
auto currentBookings = m_controller.getServiceBookings(); auto currentBookings = m_controller.getServiceBookings();
auto pendingServiceBookings = filterActiveServiceBookings(currentBookings);
auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN); auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN);
int bookingsSize = currentBookings.getSize(); int bookingsSize = pendingServiceBookings.getSize();
util::Map<int, const ServiceBooking*> serviceBookingsMap; util::Map<int, const ServiceBooking*> serviceBookingsMap;
util::Map<int, const User*> currentAvailableTechniciansMap; util::Map<int, const User*> currentAvailableTechniciansMap;
if (listServiceBookings(currentBookings, bookingsSize, serviceBookingsMap)) if (listServiceBookings(pendingServiceBookings, bookingsSize, serviceBookingsMap))
{ {
const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap); const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap);
if (selectedService) if (selectedService)
@@ -356,14 +366,19 @@ void AdminMenu::assignJob()
{ {
m_controller.createJobCard(selectedService->getId(), selectedTechnician->getId(), servicesInBooking.getValueAt(iterator)->getId()); m_controller.createJobCard(selectedService->getId(), selectedTechnician->getId(), servicesInBooking.getValueAt(iterator)->getId());
} }
std::cout << "Job card created for each service and technician successfully assigned.\n\n";
} }
} }
else else
{ {
std::cout << "No technicians are currently available."; std::cout << "No technicians are currently available.\n\n";
} }
} }
} }
else
{
std::cout << "No pending service bookings available.\n\n";
}
util::pressEnter(); util::pressEnter();
} }
@@ -378,17 +393,19 @@ Returns:
void AdminMenu::createService() void AdminMenu::createService()
{ {
util::clear(); util::clear();
std::cout << "Create Service\n";
std::string serviceName; std::string serviceName;
double labourCost; double labourCost;
std::cout << "Enter the service name: "; std::cout << "Enter the service name: ";
util::read(serviceName); util::read(serviceName);
util::Map<std::string, const InventoryItem*> currentInventoryItems = m_controller.getInventoryItems(); util::Map<std::string, const InventoryItem*> currentInventoryItems = m_controller.getInventoryItems();
util::Map<std::string, const InventoryItem*> activeInventoryItems = filterActiveItems(currentInventoryItems);
util::Vector<std::string> selectedInventoryItems; util::Vector<std::string> selectedInventoryItems;
selectInventoryItems(currentInventoryItems,selectedInventoryItems); selectInventoryItems(activeInventoryItems,selectedInventoryItems);
std::cout << "Enter the labour cost: "; std::cout << "\nEnter the labour cost: ";
util::read(labourCost); util::read(labourCost);
m_controller.createService(serviceName, selectedInventoryItems, labourCost); m_controller.createService(serviceName, selectedInventoryItems, labourCost);
std::cout << "Service created sucessfully.\n"; std::cout << "\nService created sucessfully.\n\n";
util::pressEnter(); util::pressEnter();
} }
@@ -403,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();
} }
@@ -428,36 +447,37 @@ void AdminMenu::addTechnician()
{ {
util::clear(); util::clear();
std::string username, name, password, email, phoneNumber; std::string username, name, password, email, phoneNumber;
std::cout << std::left << std::setw(25) << "Enter Technician Username: "; std::cout << "Add Technician\n";
std::cout << "Enter Technician Username: ";
util::read(username); util::read(username);
std::cout << std::left << std::setw(25) << "Enter Technician Name: "; std::cout << "Enter Technician Name: ";
util::read(name); util::read(name);
std::cout << std::setw(25) << "Enter Technician Password: "; std::cout << "Enter Technician Password: ";
util::read(password); util::read(password);
if(!util::isPasswordValid(password)) if(!util::isPasswordValid(password))
{ {
std::cout << "Error: Password is invalid!"; std::cout << "\nError: Password is invalid!\n\n";
util::pressEnter(); util::pressEnter();
return; return;
} }
std::cout << std::setw(25) << "Enter Technician Email: "; std::cout << "Enter Technician Email: ";
util::read(email); util::read(email);
if(!util::isEmailValid(email)) if(!util::isEmailValid(email))
{ {
std::cout << "Error: Email is invalid!"; std::cout << "\nError: Email is invalid!\n\n";
util::pressEnter(); util::pressEnter();
return; return;
} }
std::cout << std::setw(25) << "Enter Technician Phone: "; std::cout << "Enter Technician Phone: ";
util::read(phoneNumber); util::read(phoneNumber);
if(!util::isPhoneNumberValid(phoneNumber)) if(!util::isPhoneNumberValid(phoneNumber))
{ {
std::cout << "Error: Phone Number is invalid!"; std::cout << "\nError: Phone Number is invalid!\n\n";
util::pressEnter(); util::pressEnter();
return; return;
} }
m_controller.createTechnician(username, name, password, email, phoneNumber); m_controller.createTechnician(username, name, password, email, phoneNumber);
std::cout << "\nTechnician Added Successfully.\n"; std::cout << "\nTechnician Added Successfully.\n\n";
util::pressEnter(); util::pressEnter();
} }
@@ -509,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++)
@@ -517,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;
} }
@@ -535,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;
@@ -569,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();
} }
@@ -358,6 +358,7 @@ Returns:
void CustomerMenu::viewInvoices() void CustomerMenu::viewInvoices()
{ {
util::clear(); util::clear();
std::cout << "View Invoices\n";
util::Map<std::string, const Invoice*> currentUserInvoices = m_controller.getInvoicesByUser(); util::Map<std::string, const Invoice*> currentUserInvoices = m_controller.getInvoicesByUser();
displayInvoices(currentUserInvoices); displayInvoices(currentUserInvoices);
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);
@@ -93,69 +91,89 @@ Returns:
*/ */
inline void selectInventoryItems(util::Map<std::string, const InventoryItem*>& currentInventoryItems, util::Vector<std::string>& selectedInventoryItems) inline void selectInventoryItems(util::Map<std::string, const InventoryItem*>& currentInventoryItems, util::Vector<std::string>& selectedInventoryItems)
{ {
bool doRun = true, hasInventoryItems = false; bool doRun = true;
util::Map<int, const InventoryItem*> currentInventoryMap; util::Map<int, const InventoryItem*> currentInventoryMap;
int currentIndex = 1; int choice;
int choice; if (currentInventoryItems.getSize() == 0)
if (currentInventoryItems.getSize() == 0)
{
std::cout << "Inventory empty.";
}
while (doRun)
{
bool hasInventoryItems = false;
int currentIndex = 1;
currentInventoryMap.clear();
std::cout << std::left
<< std::setw(6) << "Index"
<< std::setw(12) << "Item ID"
<< std::setw(20) << "Part Name"
<< std::setw(10) << "Price"
<< std::setw(10) << "Quantity"
<< std::endl;
for (int iterator = 0; iterator < currentInventoryItems.getSize(); iterator++)
{ {
const InventoryItem* currentInventoryItem = currentInventoryItems.getValueAt(iterator); std::cout << "No Items Present, Inventory empty.\n";
if (currentInventoryItem->getState() == util::State::INACTIVE) return;
{
continue;
}
std::cout << std::left
<< std::setw(6) << currentIndex
<< std::setw(12) << currentInventoryItem->getId()
<< std::setw(20) << currentInventoryItem->getPartName()
<< std::setw(10) << currentInventoryItem->getPrice()
<< std::setw(10) << currentInventoryItem->getQuantity()
<< std::endl;
hasInventoryItems = true;
currentInventoryMap.insert(currentIndex++, currentInventoryItem);
}
if (!hasInventoryItems)
{
std::cout << "No items present in the inventory." << std::endl;
doRun = false;
break;
} }
std::cout << "Select the item (Index) or enter -1 to exit: "; while (doRun)
util::read(choice); {
std::cout << "\nSelect Required Items\n";
if (choice == -1) bool hasInventoryItems = false;
{ int currentIndex = 1;
doRun = false; currentInventoryMap.clear();
std::cout << std::left
<< std::setw(6) << "Index"
<< std::setw(12) << "Item ID"
<< std::setw(20) << "Part Name"
<< std::setw(10) << "Price"
<< std::setw(10) << "Quantity"
<< std::endl;
for (int iterator = 0; iterator < currentInventoryItems.getSize(); iterator++)
{
const InventoryItem* currentInventoryItem = currentInventoryItems.getValueAt(iterator);
if (currentInventoryItem == nullptr || currentInventoryItem->getState() == util::State::INACTIVE)
{
continue;
}
std::cout << std::left
<< std::setw(6) << currentIndex
<< std::setw(12) << currentInventoryItem->getId()
<< std::setw(20) << currentInventoryItem->getPartName()
<< std::setw(10) << currentInventoryItem->getPrice()
<< std::setw(10) << currentInventoryItem->getQuantity()
<< std::endl;
currentInventoryMap.insert(currentIndex++, currentInventoryItem);
hasInventoryItems = true;
} }
else if (currentInventoryMap.find(choice) != -1) if (!hasInventoryItems)
{ {
selectedInventoryItems.push_back(currentInventoryMap.getValueAt(choice)->getId()); break;
std::cout << "Item added successfully." << std::endl; }
std::cout << "Select the item (Index) or enter -1 to exit: ";
util::read(choice);
if (choice == -1)
{
doRun = false;
}
else if (currentInventoryMap.find(choice) != -1)
{
selectedInventoryItems.push_back(currentInventoryMap.getValueAt(currentInventoryMap.find(choice))->getId());
std::cout << "Item added successfully.\n" << std::endl;
} }
else else
{ {
std::cout << "Enter a valid integer." << std::endl; std::cout << "Enter a valid integer.\n" << std::endl;
} }
} }
} }
/*
Function: filterActiveServiceBookings
Description: Filters the given service bookings and returns only bookings with PENDING status.
Parameters:
- currentBookings: util::Map<std::string, const ServiceBooking*>, collection of current service bookings
Returns:
- util::Map<std::string, const ServiceBooking*>: map containing only active (PENDING) service bookings
*/
inline util::Map<std::string, const ServiceBooking*> filterActiveServiceBookings(util::Map<std::string, const ServiceBooking*> currentBookings)
{
util::Map<std::string, const ServiceBooking*> activeServiceBookings;
for (int iterator = 0; iterator < currentBookings.getSize(); iterator++)
{
const ServiceBooking* currentServiceBooking = currentBookings.getValueAt(iterator);
if (currentServiceBooking && currentServiceBooking->getStatus() == util::ServiceJobStatus::PENDING)
{
activeServiceBookings.insert(currentServiceBooking->getId(), currentServiceBooking);
}
}
return activeServiceBookings;
}
/* /*
Function: listServiceBookings Function: listServiceBookings
Description: Lists all pending service bookings and maps them to indices for selection. Description: Lists all pending service bookings and maps them to indices for selection.
@@ -168,48 +186,46 @@ Returns:
*/ */
inline bool listServiceBookings(util::Map<std::string, const ServiceBooking*>& currentBookings, int& bookingsSize, util::Map<int, const ServiceBooking*>& serviceBookingsMap) inline bool listServiceBookings(util::Map<std::string, const ServiceBooking*>& currentBookings, int& bookingsSize, util::Map<int, const ServiceBooking*>& serviceBookingsMap)
{ {
if (currentBookings.getSize() == 0)
{
return false;
}
int currentIndex = 1; int currentIndex = 1;
bool hasPendingService = false; std::cout << "\nSelect Service Booking" << std::endl;
std::cout << std::left std::cout << std::left
<< std::setw(10) << "Index" << std::setw(10) << "Index"
<< std::setw(10) << "ID" << std::setw(10) << "ID"
<< std::setw(12) << "Status" << std::setw(12) << "Status"
<< std::setw(12) << "CustID" << std::setw(12) << "CustID"
<< std::setw(20) << "Customer" << std::setw(20) << "Customer"
<< std::setw(15) << "VehicleNo" << std::setw(15) << "VehicleNo"
<< std::setw(15) << "Brand" << std::setw(15) << "Brand"
<< std::setw(15) << "Model" << std::setw(15) << "Model"
<< std::setw(20) << "Technician" << std::setw(20) << "Technician"
<< std::setw(15) << "TechnicianID" << std::setw(15) << "TechnicianID"
<< std::endl; << std::endl;
for (int iterator = 0; iterator < bookingsSize; iterator++) for (int iterator = 0; iterator < bookingsSize; iterator++)
{ {
const ServiceBooking* currentBooking = currentBookings.getValueAt(iterator); const ServiceBooking* currentBooking = currentBookings.getValueAt(iterator);
if (currentBooking && currentBooking->getStatus() == util::ServiceJobStatus::PENDING) if (currentBooking && currentBooking->getStatus() == util::ServiceJobStatus::PENDING)
{ {
hasPendingService = true; const User* currentAssignedTechnician = currentBooking->getAssignedTechnician();
const User* currentAssignedTechnician = currentBooking->getAssignedTechnician(); std::cout << std::left
std::cout << std::left << std::setw(10) << currentIndex
<< std::setw(10) << currentIndex << std::setw(10) << currentBooking->getId()
<< std::setw(10) << currentBooking->getId() << std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus())
<< std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus()) << std::setw(12) << currentBooking->getCustomerId()
<< std::setw(12) << currentBooking->getCustomerId() << std::setw(20) << currentBooking->getCustomer()->getName()
<< std::setw(20) << currentBooking->getCustomer()->getName() << std::setw(15) << currentBooking->getVehicleNumber()
<< std::setw(15) << currentBooking->getVehicleNumber() << std::setw(15) << currentBooking->getVehicleBrand()
<< std::setw(15) << currentBooking->getVehicleBrand() << std::setw(15) << currentBooking->getVehicleModel()
<< std::setw(15) << currentBooking->getVehicleModel() << std::setw(20) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getName().empty()) ? "NULL" : currentAssignedTechnician->getName())
<< std::setw(20) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getName().empty()) ? "Null" : currentAssignedTechnician->getName()) << std::setw(15) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getId().empty()) ? "NULL" : currentAssignedTechnician->getId())
<< std::setw(15) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getId().empty()) ? "Null" : currentAssignedTechnician->getId()) << std::endl;
<< std::endl; serviceBookingsMap.insert(currentIndex++, currentBooking);
serviceBookingsMap.insert(currentIndex++, currentBooking); }
} }
} return true;
if (!hasPendingService)
{
std::cout << "No pending service available." << std::endl;
return false;
}
return true;
} }
/* /*
@@ -223,15 +239,15 @@ Returns:
inline const ServiceBooking* selectPendingServiceBookings(util::Map<int, const ServiceBooking*>& serviceBookingsMap) inline const ServiceBooking* selectPendingServiceBookings(util::Map<int, const ServiceBooking*>& serviceBookingsMap)
{ {
int userInputIndex; int userInputIndex;
std::cout << "Enter a valid service index: "; std::cout << "\nEnter a valid service index: ";
util::read(userInputIndex); util::read(userInputIndex);
if (serviceBookingsMap.find(userInputIndex) != -1) if (serviceBookingsMap.find(userInputIndex) != -1)
{ {
return serviceBookingsMap.getValueAt(userInputIndex); return serviceBookingsMap.getValueAt(serviceBookingsMap.find(userInputIndex));
} }
else else
{ {
std::cout << "Enter a valid index."; std::cout << "Enter a valid index.\n\n";
return nullptr; return nullptr;
} }
} }
@@ -250,6 +266,7 @@ inline void listAvailableTechnicians(util::Map<std::string, const User*> current
{ {
bool hasTechnicians = false; bool hasTechnicians = false;
int currentIndex = 1; int currentIndex = 1;
std::cout << "\nSelect Technician\n";
std::cout << std::left std::cout << std::left
<< std::setw(6) << "Index" << std::setw(6) << "Index"
<< std::setw(15) << "Technician ID" << std::setw(15) << "Technician ID"
@@ -272,7 +289,7 @@ inline void listAvailableTechnicians(util::Map<std::string, const User*> current
} }
if (!hasTechnicians) if (!hasTechnicians)
{ {
std::cout << "No technicians currently available."; std::cout << "No technicians currently available.\n\n";
} }
} }
@@ -285,17 +302,18 @@ Returns:
- const User*: Pointer to the selected technician, or nullptr if invalid - const User*: Pointer to the selected technician, or nullptr if invalid
*/ */
inline const User* selectTechnician(util::Map<int, const User*>& currentAvailableTechniciansMap) inline const User* selectTechnician(util::Map<int, const User*>& currentAvailableTechniciansMap)
{
int userInputIndex;
std::cout << "\nEnter valid technician index: ";
util::read(userInputIndex);
if (currentAvailableTechniciansMap.find(userInputIndex) != -1)
{ {
int userInputIndex; return currentAvailableTechniciansMap.getValueAt(currentAvailableTechniciansMap.find(userInputIndex));
util::read(userInputIndex); }
if (currentAvailableTechniciansMap.find(userInputIndex) != -1) else
{ {
return currentAvailableTechniciansMap.getValueAt(userInputIndex); std::cout << "Enter a valid index.\n\n";
} return nullptr;
else
{
std::cout << "Enter a valid index.";
return nullptr;
} }
} }
@@ -408,59 +426,63 @@ Throws:
*/ */
inline void displayInvoices(util::Map<std::string, const Invoice*> currentUserInvoices) inline void displayInvoices(util::Map<std::string, const Invoice*> currentUserInvoices)
{ {
if (currentUserInvoices.getSize() == 0) if (currentUserInvoices.getSize() == 0)
{ {
std::cout << "No invoices found for this account." << std::endl; std::cout << "No invoices found for this account." << std::endl << std::endl;
util::pressEnter();
return; return;
} }
else else
{ {
for (int index = 0; index < currentUserInvoices.getSize(); index++) for (int index = 0; index < currentUserInvoices.getSize(); index++)
{
const Invoice* currentInvoice = currentUserInvoices.getValueAt(index);
if (currentInvoice)
{
const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician();
std::cout << "\nInvoice Details\n";
std::cout << "Booking ID: " << currentInvoice->getBookingId() << std::endl;
std::cout << "Vehicle Brand: " << currentInvoice->getBooking()->getVehicleBrand() << std::endl;
std::cout << "Vehicle Number: " << currentInvoice->getBooking()->getVehicleNumber() << std::endl;
std::cout << "Technician ID: " <<
((currentTechnician != nullptr && currentTechnician->getId() != "") ?
currentTechnician->getId() : "Null") << std::endl;
std::cout << "Technician Name: " <<
((currentTechnician != nullptr && currentTechnician->getName() != "") ?
currentTechnician->getName() : "Null") << std::endl;
std::cout << "Discount(%): " << currentInvoice->getDiscountPercentage() << std::endl;
std::cout << "Total Amount: " << currentInvoice->getTotalAmount() << std::endl;
std::cout << "Invoice Date: " << currentInvoice->getInvoiceDate().toString() << std::endl;
std::cout << "Payment Status: " << util::getPaymentStatusString(currentInvoice->getStatus()) << std::endl;
auto inventoryItemsInInvoice = currentInvoice->getParts();
std::cout << "\nItems Used:\n";
std::cout << std::left
<< std::setw(20) << "ItemName"
<< std::setw(10) << "Quantity"
<< std::setw(10) << "Price"
<< std::endl;
std::cout << std::string(40, '-') << std::endl;
for (int iterator = 0; iterator < inventoryItemsInInvoice.getSize(); iterator++)
{
InventoryItem* currentItem = inventoryItemsInInvoice.getValueAt(iterator);
std::cout << std::left
<< std::setw(20) << currentItem->getPartName()
<< std::setw(10) << currentItem->getQuantity()
<< std::setw(10) << currentItem->getPrice()
<< std::endl;
}
}
else
{ {
throw std::runtime_error("Null invoice encountered while displaying invoices."); const Invoice* currentInvoice = currentUserInvoices.getValueAt(index);
util::pressEnter(); if (currentInvoice)
} {
const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician();
std::cout << "\nInvoice Details\n";
std::cout << "Booking ID: " << currentInvoice->getBookingId() << std::endl;
std::cout << "Vehicle Brand: " << currentInvoice->getBooking()->getVehicleBrand() << std::endl;
std::cout << "Vehicle Number: " << currentInvoice->getBooking()->getVehicleNumber() << std::endl;
std::cout << "Technician ID: " <<
((currentTechnician != nullptr && currentTechnician->getId() != "") ?
currentTechnician->getId() : "Null") << std::endl;
std::cout << "Technician Name: " <<
((currentTechnician != nullptr && currentTechnician->getName() != "") ?
currentTechnician->getName() : "Null") << std::endl;
std::cout << "Discount(%): " << currentInvoice->getDiscountPercentage() << std::endl;
std::cout << "Total Amount: " << currentInvoice->getTotalAmount() << std::endl;
std::cout << "Invoice Date: " << currentInvoice->getInvoiceDate().toString() << std::endl;
std::cout << "Payment Status: " << util::getPaymentStatusString(currentInvoice->getStatus()) << std::endl;
auto inventoryItemsInInvoice = currentInvoice->getParts();
if (inventoryItemsInInvoice.isEmpty())
{
std::cout << "No inventory items used.\n\n";
continue;
}
std::cout << "\nItems Used:\n";
std::cout << std::left
<< std::setw(20) << "ItemName"
<< std::setw(10) << "Quantity"
<< std::setw(10) << "Price"
<< std::endl;
std::cout << std::string(40, '-') << std::endl;
for (int iterator = 0; iterator < inventoryItemsInInvoice.getSize(); iterator++)
{
InventoryItem* currentItem = inventoryItemsInInvoice.getValueAt(iterator);
std::cout << std::left
<< std::setw(20) << currentItem->getPartName()
<< std::setw(10) << currentItem->getQuantity()
<< std::setw(10) << currentItem->getPrice()
<< std::endl;
}
}
else
{
throw std::runtime_error("Null invoice encountered while displaying invoices.");
}
} }
} }
util::pressEnter();
} }
/* /*
@@ -720,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.
@@ -728,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"
@@ -908,6 +958,7 @@ inline void displayInventoryWithItems(util::Map<std::string, const InventoryItem
<< std::endl; << std::endl;
} }
} }
std::cout << std::endl;
} }
/* /*
@@ -927,7 +978,7 @@ inline void addQuantityToItem(util::Map<std::string, const InventoryItem*>& inve
int activeSize = activeItems.getSize(); int activeSize = activeItems.getSize();
if (activeSize == 0) if (activeSize == 0)
{ {
std::cout << "No active items available in Inventory" << std::endl; std::cout << "\nNo active items available in Inventory" << std::endl << std::endl;
return; return;
} }
displayInventoryWithItems(activeItems); displayInventoryWithItems(activeItems);
@@ -935,7 +986,7 @@ inline void addQuantityToItem(util::Map<std::string, const InventoryItem*>& inve
util::read(itemIndex); util::read(itemIndex);
if (itemIndex < 1 || itemIndex > activeSize) if (itemIndex < 1 || itemIndex > activeSize)
{ {
std::cout << "Invalid index selected." << std::endl; std::cout << "\nInvalid index selected." << std::endl << std::endl;
return; return;
} }
std::cout << "Enter quantity to add: "; std::cout << "Enter quantity to add: ";
@@ -950,13 +1001,14 @@ inline void addQuantityToItem(util::Map<std::string, const InventoryItem*>& inve
{ {
std::string selectedItemId = selectedItem->getId(); std::string selectedItemId = selectedItem->getId();
m_controller.addInventoryItemStock(selectedItemId, quantity); m_controller.addInventoryItemStock(selectedItemId, quantity);
std::cout << "Updated " << selectedItem->getPartName() std::cout << "\nUpdated " << selectedItem->getPartName()
<< " stock. New quantity: " << selectedItem->getQuantity() << " stock. New quantity: " << selectedItem->getQuantity()
<< std::endl
<< std::endl; << std::endl;
} }
else else
{ {
std::cout << "Error: Selected item could not be found." << std::endl; std::cout << "\nError: Selected item could not be found." << std::endl << std::endl;
} }
} }
@@ -1004,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++)
@@ -1017,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): ";
@@ -6,6 +6,7 @@ Description: Implementation file containing the method definitions of the
Author: Trenser Author: Trenser
Date:19-May-2026 Date:19-May-2026
*/ */
#include "Enums.h" #include "Enums.h"
#include "InputHelper.h" #include "InputHelper.h"
#include "JobCard.h" #include "JobCard.h"