From 937ba2e7cf739ab97728897ba9c11522631a5e2d Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Tue, 26 May 2026 12:23:23 +0530 Subject: [PATCH 1/6] Fix Add Inventory Item Issues - Added heading "Add Inventory Item" to submenu for clearer user guidance. - Updated option text from "Add Quantity" to "Restock Item". - Ensured console clearing (util::clear) before add item and restock operations. - Reformatted prompts with consistent spacing and line breaks (e.g., "Enter Item Details", "Select Item to Restock"). - Added default case handling in AdminMenu for invalid choices. - Enhanced MenuHelper output: - Extra line breaks for readability. - Improved error messages ("Invalid index selected", "No active items available"). - Clearer success message when updating stock with new quantity. Fixes #1740 --- .../views/AdminMenu.cpp | 16 ++++++++++++---- .../views/MenuHelper.h | 10 ++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 660decf..329e76c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -218,13 +218,15 @@ void AdminMenu::addInventoryItem() int choice, quantity; double price; 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); switch (choice) { - case 1: + case 1: { - std::cout << "--------Enter Item Details----------\n"; + util::clear(); + std::cout << "Enter Item Details\n"; std::cout << "Part Name : "; util::read(partName); std::cout << "Quantity : "; @@ -232,15 +234,21 @@ void AdminMenu::addInventoryItem() std::cout << "Price : "; util::read(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; } case 2: { + util::clear(); + std::cout << "Select Item to Restock\n"; auto inventoryItems = m_controller.getInventoryItems(); addQuantityToItem(inventoryItems, m_controller); break; } + default: + { + std::cout << "\nEnter a valid choice.\n\n"; + } } util::pressEnter(); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index 462391b..b2f8fd3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -908,6 +908,7 @@ inline void displayInventoryWithItems(util::Map& inve int activeSize = activeItems.getSize(); 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; } displayInventoryWithItems(activeItems); @@ -935,7 +936,7 @@ inline void addQuantityToItem(util::Map& inve util::read(itemIndex); if (itemIndex < 1 || itemIndex > activeSize) { - std::cout << "Invalid index selected." << std::endl; + std::cout << "\nInvalid index selected." << std::endl << std::endl; return; } std::cout << "Enter quantity to add: "; @@ -950,13 +951,14 @@ inline void addQuantityToItem(util::Map& inve { std::string selectedItemId = selectedItem->getId(); m_controller.addInventoryItemStock(selectedItemId, quantity); - std::cout << "Updated " << selectedItem->getPartName() + std::cout << "\nUpdated " << selectedItem->getPartName() << " stock. New quantity: " << selectedItem->getQuantity() + << std::endl << std::endl; } 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; } } From 3b82648e45a06db4e3923eb4697585afee9a4896 Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Tue, 26 May 2026 12:47:47 +0530 Subject: [PATCH 2/6] Fix Add Technician submenu - Updated AdminMenu::addTechnician: - Added heading "Add Technician" for better user guidance. - Removed setw formatting, replaced with simpler prompts. - Ensured console clears before operation for consistency. - Improved error messages for password, email, and phone validation with line breaks for readability. - Enhanced success message with consistent spacing. - Minor cleanup in TechnicianMenu.cpp by adding a blank line after file header for formatting consistency. Fixed #1744 --- .../files/README.md | 1 - .../views/AdminMenu.cpp | 19 ++++++++++--------- .../views/TechnicianMenu.cpp | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) delete mode 100644 Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/files/README.md diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/files/README.md b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/files/README.md deleted file mode 100644 index 6e6b93e..0000000 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/files/README.md +++ /dev/null @@ -1 +0,0 @@ -Place files here. \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 329e76c..9c6105d 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -436,36 +436,37 @@ void AdminMenu::addTechnician() { util::clear(); 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); - std::cout << std::left << std::setw(25) << "Enter Technician Name: "; + std::cout << "Enter Technician Name: "; util::read(name); - std::cout << std::setw(25) << "Enter Technician Password: "; + std::cout << "Enter Technician Password: "; util::read(password); if(!util::isPasswordValid(password)) { - std::cout << "Error: Password is invalid!"; + std::cout << "\nError: Password is invalid!\n\n"; util::pressEnter(); return; } - std::cout << std::setw(25) << "Enter Technician Email: "; + std::cout << "Enter Technician Email: "; util::read(email); if(!util::isEmailValid(email)) { - std::cout << "Error: Email is invalid!"; + std::cout << "\nError: Email is invalid!\n\n"; util::pressEnter(); return; } - std::cout << std::setw(25) << "Enter Technician Phone: "; + std::cout << "Enter Technician Phone: "; util::read(phoneNumber); if(!util::isPhoneNumberValid(phoneNumber)) { - std::cout << "Error: Phone Number is invalid!"; + std::cout << "\nError: Phone Number is invalid!\n\n"; util::pressEnter(); return; } m_controller.createTechnician(username, name, password, email, phoneNumber); - std::cout << "\nTechnician Added Successfully.\n"; + std::cout << "\nTechnician Added Successfully.\n\n"; util::pressEnter(); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp index 7aaddcc..d50c73e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp @@ -6,6 +6,7 @@ Description: Implementation file containing the method definitions of the Author: Trenser Date:19-May-2026 */ + #include "Enums.h" #include "InputHelper.h" #include "JobCard.h" From 05499e489013acf169fc67b17ec1e0360759a6e1 Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Tue, 26 May 2026 16:29:03 +0530 Subject: [PATCH 3/6] Fix Create Service Submenu - Added heading "Create Service" to submenu for clearer user guidance. - Ensured console clears before service creation for consistent UI behavior. - Filtered active inventory items before selection to avoid showing inactive items. - Updated prompts with improved formatting and spacing (e.g., labour cost input, success message). - Refactored selectInventoryItems: - Added "Select Required Items" heading for clarity. - Skipped null or inactive items during listing. - Improved empty inventory message ("No Items Present, Inventory empty"). - Enhanced success and error messages with consistent line breaks. - Simplified logic for item selection and exit handling. Fixes #1747 --- .../views/AdminMenu.cpp | 8 +- .../views/MenuHelper.h | 104 +++++++++--------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 9c6105d..abec3a6 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -386,17 +386,19 @@ Returns: void AdminMenu::createService() { util::clear(); + std::cout << "Create Service\n"; std::string serviceName; double labourCost; std::cout << "Enter the service name: "; util::read(serviceName); util::Map currentInventoryItems = m_controller.getInventoryItems(); + util::Map activeInventoryItems = filterActiveItems(currentInventoryItems); util::Vector selectedInventoryItems; - selectInventoryItems(currentInventoryItems,selectedInventoryItems); - std::cout << "Enter the labour cost: "; + selectInventoryItems(activeInventoryItems,selectedInventoryItems); + std::cout << "\nEnter the labour cost: "; util::read(labourCost); m_controller.createService(serviceName, selectedInventoryItems, labourCost); - std::cout << "Service created sucessfully.\n"; + std::cout << "\nService created sucessfully.\n\n"; util::pressEnter(); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index b2f8fd3..a09950d 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -93,65 +93,63 @@ Returns: */ inline void selectInventoryItems(util::Map& currentInventoryItems, util::Vector& selectedInventoryItems) { - bool doRun = true, hasInventoryItems = false; - util::Map currentInventoryMap; - int currentIndex = 1; - int choice; - 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++) + bool doRun = true; + util::Map currentInventoryMap; + int choice; + if (currentInventoryItems.getSize() == 0) { - const InventoryItem* currentInventoryItem = currentInventoryItems.getValueAt(iterator); - if (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; - - hasInventoryItems = true; - currentInventoryMap.insert(currentIndex++, currentInventoryItem); - } - if (!hasInventoryItems) - { - std::cout << "No items present in the inventory." << std::endl; - doRun = false; - break; + std::cout << "No Items Present, Inventory empty.\n"; + return; } - std::cout << "Select the item (Index) or enter -1 to exit: "; - util::read(choice); - - if (choice == -1) -{ - doRun = false; + while (doRun) + { + std::cout << "\nSelect Required Items\n"; + 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); + 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) -{ - selectedInventoryItems.push_back(currentInventoryMap.getValueAt(choice)->getId()); - std::cout << "Item added successfully." << std::endl; + if (!hasInventoryItems) + { + break; + } + 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 { - std::cout << "Enter a valid integer." << std::endl; + std::cout << "Enter a valid integer.\n" << std::endl; } } } From 7646ce66446ceddb772f62e832eb531cda3c5fa7 Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Tue, 26 May 2026 19:06:52 +0530 Subject: [PATCH 4/6] Fix Assign Job to Technician issues and View invoices issues - Assign Job to Technician: - Added heading for clearer user guidance. - Filtered only pending service bookings for assignment. - Improved technician listing and selection with clearer prompts. - Ensured booking status transitions correctly from PENDING to STARTED when job cards are created. - Enhanced feedback messages for technician availability and job card creation. - View Invoices: - Added heading "View Invoices" for better UI consistency. - Updated displayInvoices to take map by reference for efficiency. - Improved formatting of invoice details with consistent spacing and line breaks. - Added handling for empty invoice parts list (shows "No inventory items used"). - Enhanced error messages when encountering null invoices. Fixes #1745 Fixes #1752 --- .../services/ServiceManagementService.cpp | 5 +- .../services/UserManagementService.cpp | 2 +- .../views/AdminMenu.cpp | 13 +- .../views/CustomerMenu.cpp | 3 +- .../views/MenuHelper.h | 216 ++++++++++-------- 5 files changed, 138 insertions(+), 101 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 45c6fe4..03a2bfa 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -23,7 +23,6 @@ Date:19-May-2026 #include "ServiceBooking.h" #include "ServiceManagementService.h" #include "Timestamp.h" -#include "Timestamp.h" #include "User.h" #include "UserManagementService.h" #include "Utility.h" @@ -817,6 +816,10 @@ void ServiceManagementService::createJobCard(const std::string& bookingID, const } currentBooking->setAssignedTechnician(selectedTechnician); currentBooking->setAssignedTechnicianId(selectedTechnician->getId()); + if (currentBooking->getStatus() == util::ServiceJobStatus::PENDING) + { + currentBooking->setStatus(util::ServiceJobStatus::STARTED); + } std::string title = "Job card created"; std::string message = "Job card created for the service and you are assigned for that."; JobCard* jobCard = Factory::getObject(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::Timestamp(), util::ServiceJobStatus::STARTED, util::Timestamp()); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 39f9148..e086def 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -315,7 +315,7 @@ util::Map UserManagementService::getUsers(util::UserType typ for (int iterator = 0; iterator < currentUsers.getSize(); 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); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index abec3a6..d218535 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -341,14 +341,16 @@ Returns: void AdminMenu::assignJob() { util::clear(); + std::cout << "Assign Job to Technician\n"; std::string selectedService; bool hasPendingService = false; auto currentBookings = m_controller.getServiceBookings(); + auto pendingServiceBookings = filterActiveServiceBookings(currentBookings); auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN); - int bookingsSize = currentBookings.getSize(); + int bookingsSize = pendingServiceBookings.getSize(); util::Map serviceBookingsMap; util::Map currentAvailableTechniciansMap; - if (listServiceBookings(currentBookings, bookingsSize, serviceBookingsMap)) + if (listServiceBookings(pendingServiceBookings, bookingsSize, serviceBookingsMap)) { const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap); if (selectedService) @@ -364,14 +366,19 @@ void AdminMenu::assignJob() { 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 { - 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(); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index d354a3c..05f85cf 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -358,6 +358,7 @@ Returns: void CustomerMenu::viewInvoices() { util::clear(); + std::cout << "View Invoices\n"; util::Map currentUserInvoices = m_controller.getInvoicesByUser(); displayInvoices(currentUserInvoices); util::pressEnter(); @@ -393,4 +394,4 @@ void CustomerMenu::configureNotifications() util::clear(); std::cout << "Notification preferences updated successfully.\n"; util::pressEnter(); -} +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index a09950d..c370dd4 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -154,6 +154,28 @@ inline void selectInventoryItems(util::Map& c } } +/* +Function: filterActiveServiceBookings +Description: Filters the given service bookings and returns only bookings with PENDING status. +Parameters: + - currentBookings: util::Map, collection of current service bookings +Returns: + - util::Map: map containing only active (PENDING) service bookings +*/ +inline util::Map filterActiveServiceBookings(util::Map currentBookings) +{ + util::Map activeServcieBookings; + for (int iterator = 0; iterator < currentBookings.getSize(); iterator++) + { + const ServiceBooking* currentServiceBooking = currentBookings.getValueAt(iterator); + if (currentServiceBooking && currentServiceBooking->getStatus() == util::ServiceJobStatus::PENDING) + { + activeServcieBookings.insert(currentServiceBooking->getId(), currentServiceBooking); + } + } + return activeServcieBookings; +} + /* Function: listServiceBookings Description: Lists all pending service bookings and maps them to indices for selection. @@ -166,48 +188,46 @@ Returns: */ inline bool listServiceBookings(util::Map& currentBookings, int& bookingsSize, util::Map& serviceBookingsMap) { + if (currentBookings.getSize() == 0) + { + return false; + } int currentIndex = 1; - bool hasPendingService = false; + std::cout << "\nSelect Service Booking" << std::endl; std::cout << std::left << std::setw(10) << "Index" - << std::setw(10) << "ID" - << std::setw(12) << "Status" - << std::setw(12) << "CustID" - << std::setw(20) << "Customer" - << std::setw(15) << "VehicleNo" - << std::setw(15) << "Brand" - << std::setw(15) << "Model" - << std::setw(20) << "Technician" - << std::setw(15) << "TechnicianID" + << std::setw(10) << "ID" + << std::setw(12) << "Status" + << std::setw(12) << "CustID" + << std::setw(20) << "Customer" + << std::setw(15) << "VehicleNo" + << std::setw(15) << "Brand" + << std::setw(15) << "Model" + << std::setw(20) << "Technician" + << std::setw(15) << "TechnicianID" << std::endl; - for (int iterator = 0; iterator < bookingsSize; iterator++) + for (int iterator = 0; iterator < bookingsSize; iterator++) { - const ServiceBooking* currentBooking = currentBookings.getValueAt(iterator); - if (currentBooking && currentBooking->getStatus() == util::ServiceJobStatus::PENDING) + const ServiceBooking* currentBooking = currentBookings.getValueAt(iterator); + if (currentBooking && currentBooking->getStatus() == util::ServiceJobStatus::PENDING) { - hasPendingService = true; - const User* currentAssignedTechnician = currentBooking->getAssignedTechnician(); - std::cout << std::left - << std::setw(10) << currentIndex - << std::setw(10) << currentBooking->getId() - << std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus()) - << std::setw(12) << currentBooking->getCustomerId() - << std::setw(20) << currentBooking->getCustomer()->getName() - << std::setw(15) << currentBooking->getVehicleNumber() - << std::setw(15) << currentBooking->getVehicleBrand() - << std::setw(15) << currentBooking->getVehicleModel() - << std::setw(20) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getName().empty()) ? "Null" : currentAssignedTechnician->getName()) - << std::setw(15) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getId().empty()) ? "Null" : currentAssignedTechnician->getId()) - << std::endl; - serviceBookingsMap.insert(currentIndex++, currentBooking); + const User* currentAssignedTechnician = currentBooking->getAssignedTechnician(); + std::cout << std::left + << std::setw(10) << currentIndex + << std::setw(10) << currentBooking->getId() + << std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus()) + << std::setw(12) << currentBooking->getCustomerId() + << std::setw(20) << currentBooking->getCustomer()->getName() + << std::setw(15) << currentBooking->getVehicleNumber() + << std::setw(15) << currentBooking->getVehicleBrand() + << std::setw(15) << currentBooking->getVehicleModel() + << std::setw(20) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getName().empty()) ? "NULL" : currentAssignedTechnician->getName()) + << std::setw(15) << ((currentAssignedTechnician == nullptr || currentAssignedTechnician->getId().empty()) ? "NULL" : currentAssignedTechnician->getId()) + << std::endl; + serviceBookingsMap.insert(currentIndex++, currentBooking); + } } - } - if (!hasPendingService) - { - std::cout << "No pending service available." << std::endl; - return false; - } - return true; + return true; } /* @@ -221,15 +241,15 @@ Returns: inline const ServiceBooking* selectPendingServiceBookings(util::Map& serviceBookingsMap) { int userInputIndex; - std::cout << "Enter a valid service index: "; + std::cout << "\nEnter a valid service index: "; util::read(userInputIndex); if (serviceBookingsMap.find(userInputIndex) != -1) { - return serviceBookingsMap.getValueAt(userInputIndex); + return serviceBookingsMap.getValueAt(serviceBookingsMap.find(userInputIndex)); } else { - std::cout << "Enter a valid index."; + std::cout << "Enter a valid index.\n\n"; return nullptr; } } @@ -248,6 +268,7 @@ inline void listAvailableTechnicians(util::Map current { bool hasTechnicians = false; int currentIndex = 1; + std::cout << "\nSelect Technician\n"; std::cout << std::left << std::setw(6) << "Index" << std::setw(15) << "Technician ID" @@ -270,7 +291,7 @@ inline void listAvailableTechnicians(util::Map current } if (!hasTechnicians) { - std::cout << "No technicians currently available."; + std::cout << "No technicians currently available.\n\n"; } } @@ -283,17 +304,18 @@ Returns: - const User*: Pointer to the selected technician, or nullptr if invalid */ inline const User* selectTechnician(util::Map& currentAvailableTechniciansMap) +{ + int userInputIndex; + std::cout << "\nEnter valid technician index: "; + util::read(userInputIndex); + if (currentAvailableTechniciansMap.find(userInputIndex) != -1) { - int userInputIndex; - util::read(userInputIndex); - if (currentAvailableTechniciansMap.find(userInputIndex) != -1) - { - return currentAvailableTechniciansMap.getValueAt(userInputIndex); - } - else - { - std::cout << "Enter a valid index."; - return nullptr; + return currentAvailableTechniciansMap.getValueAt(currentAvailableTechniciansMap.find(userInputIndex)); + } + else + { + std::cout << "Enter a valid index.\n\n"; + return nullptr; } } @@ -406,57 +428,61 @@ Throws: */ inline void displayInvoices(util::Map currentUserInvoices) { - if (currentUserInvoices.getSize() == 0) + if (currentUserInvoices.getSize() == 0) { - std::cout << "No invoices found for this account." << std::endl; - util::pressEnter(); + std::cout << "No invoices found for this account." << std::endl << std::endl; return; } - else + else { - 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 + for (int index = 0; index < currentUserInvoices.getSize(); index++) { - throw std::runtime_error("Null invoice encountered while displaying invoices."); - util::pressEnter(); - } + 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(); + 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(); + } } } } From 8268b90d8252741ae873940f5765bb888c808000 Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Tue, 26 May 2026 21:04:30 +0530 Subject: [PATCH 5/6] 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 --- .../services/ServiceManagementService.cpp | 19 +++++++ .../views/AdminMenu.cpp | 32 +++++++---- .../views/MenuHelper.h | 54 ++++++++++++++----- 3 files changed, 83 insertions(+), 22 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 03a2bfa..2135b5e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -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& currentServices = m_dataStore.getServices(); + util::Map& 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 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 { diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index d218535..bb7e995 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -420,17 +420,19 @@ Returns: void AdminMenu::removeService() { util::clear(); + std::cout << "Remove Service\n"; std::string selectedServiceID; util::Map currentServices = m_controller.getServices(); - selectedServiceID = selectServicesToRemove(currentServices); + util::Map 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 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,13 +558,21 @@ 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; + } } std::string packageName; double discountPercentage; @@ -587,16 +600,17 @@ Return type: void void AdminMenu::removeComboPackage() { util::clear(); + std::cout << "Remove Combo Package\n"; util::Map 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(); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index c370dd4..18f500c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -39,8 +39,12 @@ Returns: */ inline std::string selectServicesToRemove(util::Map currentServices) { + if (currentServices.getSize() == 0) + { + std::cout << "No Services Currently Available.\n"; + return ""; + } util::Map currentServicesMap; - bool hasServices = false; int currentIndex = 1, choice; std::cout << std::left << std::setw(6) << "Index" @@ -51,23 +55,17 @@ inline std::string selectServicesToRemove(util::Map 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; } - std::cout << std::left - << std::setw(6) << currentIndex + std::cout << std::left + << std::setw(6) << currentIndex << std::setw(12) << currentService->getId() << std::setw(20) << currentService->getName() << std::setw(10) << currentService->getLaborCost() - << std::endl; - hasServices = true; + << std::endl; currentServicesMap.insert(currentIndex++, currentService); - } - if (!hasServices) - { - std::cout << "No services currently available." << std::endl; - return ""; } std::cout << "Enter your choice: "; util::read(choice); @@ -744,6 +742,28 @@ inline void displayAllActiveUsers(util::Map& 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 containing only active services. +*/ +inline util::Map filterActiveServices(util::Map serviceList) +{ + util::Map 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& services) { + if (services.getSize() == 0) + { + std::cout << "No active services available." << std::endl; + return nullptr; + } util::Map 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 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 Date: Tue, 26 May 2026 21:25:02 +0530 Subject: [PATCH 6/6] Implement review fixes --- .../Trenser.VehicleServiceSystem/files/README.md | 1 + .../Trenser.VehicleServiceSystem/views/MenuHelper.h | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/files/README.md diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/files/README.md b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/files/README.md new file mode 100644 index 0000000..6e6b93e --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/files/README.md @@ -0,0 +1 @@ +Place files here. \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index 18f500c..186c730 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -162,16 +162,16 @@ Returns: */ inline util::Map filterActiveServiceBookings(util::Map currentBookings) { - util::Map activeServcieBookings; + util::Map activeServiceBookings; for (int iterator = 0; iterator < currentBookings.getSize(); iterator++) { const ServiceBooking* currentServiceBooking = currentBookings.getValueAt(iterator); if (currentServiceBooking && currentServiceBooking->getStatus() == util::ServiceJobStatus::PENDING) { - activeServcieBookings.insert(currentServiceBooking->getId(), currentServiceBooking); + activeServiceBookings.insert(currentServiceBooking->getId(), currentServiceBooking); } } - return activeServcieBookings; + return activeServiceBookings; } /* @@ -479,10 +479,10 @@ inline void displayInvoices(util::Map currentUserIn else { throw std::runtime_error("Null invoice encountered while displaying invoices."); - util::pressEnter(); } } } + util::pressEnter(); } /*