From ae488f5670046c931d3cecbb9236d6b3b638db14 Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Tue, 26 May 2026 12:24:00 +0530 Subject: [PATCH 1/7] Fix View Stock Level and improve error messages - Added validation in AdminMenu::viewStockLevels to check for empty inventory before displaying. - Added validation in AdminMenu::viewStockLevels to ensure only active items are shown. - Added "View Stock Level" header for clarity. - Adjusted column widths for Quantity and Price to 15 for better alignment. - Added final newline and util::pressEnter() prompt after displaying stock levels. Fixes #1739 --- .../views/AdminMenu.cpp | 33 +- .../AdminMenu.cpp | 589 ++++++++++++++++++ 2 files changed, 618 insertions(+), 4 deletions(-) create mode 100644 Trenser.VehicleServiceSystem/enc_temp_folder/db9dce6e29546bb6deca646799ab58e7/AdminMenu.cpp diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 74500e8..4d457a9 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -158,10 +158,33 @@ void AdminMenu::viewStockLevels() { util::clear(); auto inventoryItems = m_controller.getInventoryItems(); + bool hasActiveItems = false; + std::cout << "View Stock Level" << std::endl; + if (inventoryItems.isEmpty()) + { + std::cout << "No items found in Inventory.\n"; + util::pressEnter(); + return; + } + for (int index = 0; index < inventoryItems.getSize(); index++) + { + const InventoryItem* item = inventoryItems.getValueAt(index); + if (item->getState() == util::State::ACTIVE) + { + hasActiveItems = true; + break; + } + } + if (!hasActiveItems) + { + std::cout << "No active Inventory Item found.\n"; + util::pressEnter(); + return; + } std::cout << std::left << std::setw(15) << "Item ID" << std::setw(25) << "Part Name" - << std::setw(10) << "Quantity" - << std::setw(10) << "Price" + << std::setw(15) << "Quantity" + << std::setw(15) << "Price" << std::endl; for (int iterator = 0; iterator < inventoryItems.getSize(); ++iterator) { @@ -172,12 +195,14 @@ void AdminMenu::viewStockLevels() { std::cout << std::left << std::setw(15) << item->getId() << std::setw(25) << item->getPartName() - << std::setw(10) << item->getQuantity() - << std::setw(10) << item->getPrice() + << std::setw(15) << item->getQuantity() + << std::setw(15) << item->getPrice() << std::endl; } } } + std::cout << "\n"; + util::pressEnter(); } /* diff --git a/Trenser.VehicleServiceSystem/enc_temp_folder/db9dce6e29546bb6deca646799ab58e7/AdminMenu.cpp b/Trenser.VehicleServiceSystem/enc_temp_folder/db9dce6e29546bb6deca646799ab58e7/AdminMenu.cpp new file mode 100644 index 0000000..5505f11 --- /dev/null +++ b/Trenser.VehicleServiceSystem/enc_temp_folder/db9dce6e29546bb6deca646799ab58e7/AdminMenu.cpp @@ -0,0 +1,589 @@ +/* +File: AdminMenu.cpp +Description: Implements the AdminMenu class which provides the administrator’s console interface + in the Vehicle Service Management System. Handles menu display, user input, and + admin-specific operations such as inventory management, technician management, + service creation, combo package management, job assignment, and notifications. +Author: Trenser +Date: 19-May-2026 +*/ + +#include +#include +#include "AdminMenu.h" +#include "Enums.h" +#include "InputHelper.h" +#include "InventoryItem.h" +#include "MenuHelper.h" +#include "OutputHelper.h" +#include "Service.h" +#include "ServiceBooking.h" +#include "User.h" +#include "Utility.h" +#include "Validator.h" + +/* +Function: showMenu +Description: Displays the admin menu and handles user input until logout is selected. +Parameter: None +Return type: void +*/ +void AdminMenu::showMenu() +{ + while (true) + { + try + { + int choice; + util::clear(); + std::cout << "Admin Menu" + << "\n1. View Stock Levels" + << "\n2. Add Inventory Item" + << "\n3. Remove Inventory Item" + << "\n4. Check Stock Availability" + << "\n5. Assign Job to Technician" + << "\n6. Add Technician" + << "\n7. Remove Customer/Technician" + << "\n8. Create Service" + << "\n9. Remove Service" + << "\n10. Create Combo Package" + << "\n11. Remove Combo Package" + << "\n12. View Notifications" + << "\n13. Change Password" + << "\n14. Logout" + << "\nEnter a choice: "; + util::read(choice); + if (!handleOperation(choice)) + { + break; + } + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << std::endl; + util::pressEnter(); + } + } +} + +/* +Function: handleOperation +Description: Executes the corresponding admin operation based on the selected menu choice. +Parameter: int choice - selected menu option +Return type: bool - true if menu continues, false if logout +*/ +bool AdminMenu::handleOperation(int choice) +{ + switch (choice) + { + case 1: + viewStockLevels(); + break; + case 2: + addInventoryItem(); + break; + case 3: + removeInventoryItem(); + break; + case 4: + checkStockAvailability(); + break; + case 5: + assignJob(); + break; + case 6: + addTechnician(); + break; + case 7: + removeUser(); + break; + case 8: + createService(); + break; + case 9: + removeService(); + break; + case 10: + createComboPackages(); + break; + case 11: + removeComboPackage(); + break; + case 12: + viewNotifications(); + break; + case 13: + changePassword(); + break; + case 14: + logout(); + return false; + default: + std::cout << "Enter a valid choice!" << std::endl; + util::pressEnter(); + } + return true; +} + +/* +Function: logout +Description: Logs out the currently authenticated admin user. +Parameter: None +Return type: void +*/ +void AdminMenu::logout() +{ + m_controller.logout(); +} + +/* +Function: changePassword +Description: Allows the admin to change their password after validation. +Parameter: None +Return type: void +*/ +void AdminMenu::changePassword() +{ + changePasswordHelper(m_controller); +} + +/* +Function: viewStockLevels +Description: Displays all active inventory items with their details + including ID, part name, quantity, and price. +Parameter: None +Return type: void +*/ +void AdminMenu::viewStockLevels() +{ + util::clear(); + auto inventoryItems = m_controller.getInventoryItems(); + bool hasActiveItems = false; + if (inventoryItems.isEmpty()) + { + std::cout << "No items found in Inventory.\n"; + util::pressEnter(); + return; + } + for (int index = 0; index < inventoryItems.getSize(); index++) + { + const InventoryItem* item = inventoryItems.getValueAt(index); + if (item->getState() == util::State::ACTIVE) + { + hasActiveItems = true; + break; + } + } + if (!hasActiveItems) + { + std::cout << "No active Inventory Item found.\n"; + util::pressEnter(); + return; + } + std::cout << std::left << std::setw(15) << "Item ID" + << std::setw(25) << "Part Name" + << std::setw(15) << "Quantity" + << std::setw(15) << "Price" + << std::endl; + for (int iterator = 0; iterator < inventoryItems.getSize(); ++iterator) + { + const InventoryItem* item = inventoryItems.getValueAt(iterator); + if (item != nullptr) + { + if (item->getState() != util::State::INACTIVE) + { + std::cout << std::left << std::setw(15) << item->getId() + << std::setw(25) << item->getPartName() + << std::setw(15) << item->getQuantity() + << std::setw(15) << item->getPrice() + << std::endl; + } + } + } + std::cout << "\n"; + util::pressEnter(); +} + +/* +Function: addInventoryItem +Description: Allows the admin to either add a new inventory item + or increase the quantity of an existing item. +Parameter: None +Return type: void +*/ +void AdminMenu::addInventoryItem() +{ + util::clear(); + int choice, quantity; + double price; + std::string partName; + std::cout << "1. Add new item \n2. Add Quantity\nEnter your choice : "; + util::read(choice); + switch (choice) + { + case 1: + { + std::cout << "--------Enter Item Details----------\n"; + std::cout << "Part Name : "; + util::read(partName); + std::cout << "Quantity : "; + util::read(quantity); + std::cout << "Price : "; + util::read(price); + m_controller.addInventoryItem(partName, quantity, price); + std::cout << "New Item " << partName << " added to the Inventory.\n"; + break; + } + case 2: + { + auto inventoryItems = m_controller.getInventoryItems(); + addQuantityToItem(inventoryItems, m_controller); + break; + } + } + util::pressEnter(); +} + +/* +Function: removeInventoryItem +Description: Removes an active inventory item by marking it inactive + after user selection. +Parameter: None +Return type: void +*/ +void AdminMenu::removeInventoryItem() +{ + util::clear(); + auto inventoryItems = m_controller.getInventoryItems(); + auto activeItems = filterActiveItems(inventoryItems); + int activeItemsSize = activeItems.getSize(); + if (activeItemsSize == 0) + { + std::cout << "No items available in Inventory." << std::endl; + util::pressEnter(); + return; + } + displayInventoryWithItems(activeItems); + int itemIndex; + std::cout << "Enter the index of the item to remove: "; + util::read(itemIndex); + if (itemIndex < 1 || itemIndex > activeItemsSize) + { + std::cout << "Invalid index selected." << std::endl; + util::pressEnter(); + return; + } + const InventoryItem* selectedItem = activeItems.getValueAt(itemIndex - 1); + if (selectedItem != nullptr) + { + if(selectedItem->getState() != util::State::INACTIVE) + { + std::string selectedItemId = selectedItem->getId(); + m_controller.removeInventoryItem(selectedItemId); + std::cout << "Item " << selectedItem->getPartName() << " removed successfully." << std::endl; + } + } + util::pressEnter(); +} + +/* +Function: checkStockAvailability +Description: Checks if a specific inventory item is available + and displays its details if active. +Parameter: None +Return type: void +*/ +void AdminMenu::checkStockAvailability() +{ + util::clear(); + std::string itemId; + std::cout << "Enter the Item Id : "; + util::read(itemId); + const InventoryItem* selectedItem = m_controller.getInventoryItem(itemId); + if (selectedItem != nullptr) + { + if (selectedItem->getState() != util::State::INACTIVE) + { + std::cout << "Item Details\n"; + std::cout << "---------------------------------------------\n"; + std::cout << "Item ID : " << selectedItem->getId() << "\n"; + std::cout << "Part Name : " << selectedItem->getPartName() << "\n"; + std::cout << "Quantity : " << selectedItem->getQuantity() << "\n"; + } + } + util::pressEnter(); +} + +/* +Function: assignJob +Description: Allows the admin to assign pending service bookings to available technicians. + Creates job cards for selected services. +Parameters: + - None +Returns: + - void +*/ +void AdminMenu::assignJob() +{ + util::clear(); + std::string selectedService; + bool hasPendingService = false; + auto currentBookings = m_controller.getServiceBookings(); + auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN); + int bookingsSize = currentBookings.getSize(); + util::Map serviceBookingsMap; + util::Map currentAvailableTechniciansMap; + if (listServiceBookings(currentBookings, bookingsSize, serviceBookingsMap)) + { + const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap); + if (selectedService) + { + if (availableTechnicians.getSize() != 0) + { + listAvailableTechnicians(availableTechnicians, availableTechnicians.getSize(), currentAvailableTechniciansMap); + const User* selectedTechnician = selectTechnician(currentAvailableTechniciansMap); + if (selectedTechnician) + { + auto& servicesInBooking = selectedService->getServices(); + for (int iterator = 0; iterator < servicesInBooking.getSize(); iterator++) + { + m_controller.createJobCard(selectedService->getId(), selectedTechnician->getId(), servicesInBooking.getValueAt(iterator)->getId()); + } + } + } + else + { + std::cout << "No technicians are currently available."; + } + } + } + util::pressEnter(); +} + +/* +Function: createService +Description: Allows the admin to create a new service by selecting inventory items and specifying labor cost. +Parameters: + - None +Returns: + - void +*/ +void AdminMenu::createService() +{ + util::clear(); + std::string serviceName; + double labourCost; + std::cout << "Enter the service name: "; + util::read(serviceName); + util::Map currentInventoryItems = m_controller.getInventoryItems(); + util::Vector selectedInventoryItems; + selectInventoryItems(currentInventoryItems,selectedInventoryItems); + std::cout << "Enter the labour cost: "; + util::read(labourCost); + m_controller.createService(serviceName, selectedInventoryItems, labourCost); + std::cout << "Service created sucessfully.\n"; + util::pressEnter(); +} + +/* +Function: removeService +Description: Allows the admin to remove an existing service by selecting from available services. +Parameters: + - None +Returns: + - void +*/ +void AdminMenu::removeService() +{ + util::clear(); + std::string selectedServiceID; + util::Map currentServices = m_controller.getServices(); + selectedServiceID = selectServicesToRemove(currentServices); + if (selectedServiceID != "") + { + m_controller.removeService(selectedServiceID); + std::cout << "Service removed sucessfully."; + } + else + { + std::cout << "Failed to remove service."; + } + util::pressEnter(); +} + +/* +Function: addTechnician +Description: Adds a new technician after validating username, password, email, and phone number. +Parameter: None +Return type: void +*/ +void AdminMenu::addTechnician() +{ + util::clear(); + std::string username, name, password, email, phoneNumber; + std::cout << std::left << std::setw(25) << "Enter Technician Username: "; + util::read(username); + std::cout << std::left << std::setw(25) << "Enter Technician Name: "; + util::read(name); + std::cout << std::setw(25) << "Enter Technician Password: "; + util::read(password); + if(!util::isPasswordValid(password)) + { + std::cout << "Error: Password is invalid!"; + util::pressEnter(); + return; + } + std::cout << std::setw(25) << "Enter Technician Email: "; + util::read(email); + if(!util::isEmailValid(email)) + { + std::cout << "Error: Email is invalid!"; + util::pressEnter(); + return; + } + std::cout << std::setw(25) << "Enter Technician Phone: "; + util::read(phoneNumber); + if(!util::isPhoneNumberValid(phoneNumber)) + { + std::cout << "Error: Phone Number is invalid!"; + util::pressEnter(); + return; + } + m_controller.createTechnician(username, name, password, email, phoneNumber); + std::cout << "\nTechnician Added Successfully.\n"; + util::pressEnter(); +} + +/* +Function: removeUser +Description: Removes a selected active user (customer or technician) from the system. +Parameter: None +Return type: void +*/ +void AdminMenu::removeUser() +{ + util::clear(); + int indexChoice; + auto listOfUsers = m_controller.getUsers(); + auto listOfActiveUsers = filterActiveUsers(listOfUsers); + int activeUserCount = listOfActiveUsers.getSize(); + if (activeUserCount < 1) + { + std::cout << "No Active users." << std::endl; + util::pressEnter(); + return; + } + displayAllActiveUsers(listOfActiveUsers, activeUserCount); + std::cout << "Enter the index of the user to delete : "; + util::read(indexChoice); + if (indexChoice < 1 || indexChoice > activeUserCount) + { + std::cout << "Error Invaild index.\n" << std::endl; + util::pressEnter(); + return; + } + const User* userToRemove = listOfActiveUsers.getValueAt(indexChoice - 1); + if (userToRemove != nullptr) + { + std::string userIdToRemove = userToRemove->getId(); + m_controller.removeUser(userIdToRemove); + std::cout << userToRemove->getUserName() << " removed Successfully.\n"; + } + util::pressEnter(); +} + +/* +Function: createComboPackages +Description: Creates a new combo package by selecting two active services and applying a discount. +Parameter: None +Return type: void +*/ +void AdminMenu::createComboPackages() +{ + util::clear(); + auto serviceList = m_controller.getServices(); + const int NUMBER_OF_SERVICE_PER_PACKAGE = 2; + util::Vector selectedServiceID; + for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++) + { + const Service* chosenService = nullptr; + while (true) + { + chosenService = selectServiceFromServices(serviceList); + if (chosenService == nullptr) + { + std::cout << "Failed to create combo package!"; + util::pressEnter(); + return; + } + bool alreadyChosen = false; + for (int iteratorOne = 0; iteratorOne < selectedServiceID.getSize(); iteratorOne++) + { + if (selectedServiceID[iteratorOne] == chosenService->getId()) + { + alreadyChosen = true; + break; + } + } + if (alreadyChosen) + { + std::cout << "Service already selected. Please choose a different one." << std::endl; + continue; + } + selectedServiceID.push_back(chosenService->getId()); + util::clear(); + break; + } + } + 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(); +} + +/* +Function: removeComboPackage +Description: Removes a selected combo package from the system. +Parameter: None +Return type: void +*/ +void AdminMenu::removeComboPackage() +{ + util::clear(); + util::Map currentComboPackages = m_controller.getComboPackages(); + std::string selectedComboPackageID = selectComboPackage(currentComboPackages); + if (selectedComboPackageID != "") + { + m_controller.removeComboPackage(selectedComboPackageID); + std::cout << "Combo Package removed successfully.\n"; + } + else + { + std::cout << "Combo package removal failed.\n"; + } + util::pressEnter(); +} + +/* +Function: viewNotifications +Description: Displays notifications for the admin and allows deletion of notifications. +Parameters: + - None +Returns: + - void +*/ +void AdminMenu::viewNotifications() +{ + viewAndDeleteNotification(m_controller); +} From d55bbb634912e7ab2f642067f664ecf973a89ead Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Tue, 26 May 2026 13:02:01 +0530 Subject: [PATCH 2/7] Fix Check stock availability Issue and Add error message - Added "Check Stock Availability" header in AdminMenu::checkStockAvailability for clarity. - Updated prompt text to "Enter the Item ID" for consistency. - Added util::clear() after reading Item ID to refresh the screen before displaying results. - Implemented validation to show "Item not Found" message when the entered ID does not exist in inventory. Fix #1741 --- .../Trenser.VehicleServiceSystem/views/AdminMenu.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 4d457a9..e9e0452 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -298,8 +298,10 @@ void AdminMenu::checkStockAvailability() { util::clear(); std::string itemId; - std::cout << "Enter the Item Id : "; + std::cout << "Check Stock Availability \n"; + std::cout << "Enter the Item ID : "; util::read(itemId); + util::clear(); const InventoryItem* selectedItem = m_controller.getInventoryItem(itemId); if (selectedItem != nullptr) { @@ -312,6 +314,10 @@ void AdminMenu::checkStockAvailability() std::cout << "Quantity : " << selectedItem->getQuantity() << "\n"; } } + else + { + std::cout << "Item not Found" << std::endl; + } util::pressEnter(); } From f1ca8c2a586159513919fcd284950a296e7d09d4 Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Tue, 26 May 2026 16:35:17 +0530 Subject: [PATCH 3/7] Fix Remove User Issue - Added "Remove User" header in AdminMenu::removeUser for clarity. - Updated filterActiveUsers in MenuHelper.h to exclude ADMIN users from the active user list. Fixes #1742 --- .../Trenser.VehicleServiceSystem/views/AdminMenu.cpp | 1 + .../Trenser.VehicleServiceSystem/views/MenuHelper.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index e9e0452..3b28e51 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -474,6 +474,7 @@ void AdminMenu::removeUser() auto listOfUsers = m_controller.getUsers(); auto listOfActiveUsers = filterActiveUsers(listOfUsers); int activeUserCount = listOfActiveUsers.getSize(); + std::cout << "Remove User \n"; if (activeUserCount < 1) { std::cout << "No Active users." << std::endl; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index 09c4ecc..279c3b2 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -675,7 +675,7 @@ inline util::Map filterActiveUsers(const util::MapgetState() != util::State::INACTIVE) + if (user != nullptr && user->getState() != util::State::INACTIVE && user->getUserType() != util::UserType::ADMIN) { activeUsers.insert(user->getId(), user); } From a87af89a8ad90c008e6347bdfee89af5a25851a7 Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Tue, 26 May 2026 17:27:57 +0530 Subject: [PATCH 4/7] Fix Complete Payment Issue - Added "Complete Payments" header in CustomerMenu::completePayments for clarity. - Implemented validation to check if invoices list is empty and display appropriate message. - Added logic to verify presence of pending invoices before proceeding with payment. - Enhanced error handling to show "Payment failed" with pressEnter prompt when no invoice is selected. - Updated selectInvoiceFromUserForPayment in MenuHelper.h: - Changed function to inline and added util::clear() at start. - Updated column headers to "Technician ID" and "Technician Name" for clarity. - Removed temporary AdminMenu.cpp file from enc_temp_folder. Fixes #1750 --- .../views/CustomerMenu.cpp | 24 + .../views/MenuHelper.h | 5 +- .../AdminMenu.cpp | 589 ------------------ 3 files changed, 27 insertions(+), 591 deletions(-) delete mode 100644 Trenser.VehicleServiceSystem/enc_temp_folder/db9dce6e29546bb6deca646799ab58e7/AdminMenu.cpp diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index 2f3a0f9..85e7021 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -308,11 +308,35 @@ Returns: void CustomerMenu::completePayments() { util::clear(); + std::cout << "Complete Payments\n"; util::Map currentInvoices = m_controller.getInvoicesByUser(); + if (currentInvoices.isEmpty()) + { + std::cout << "No pending invoices available for payment.\n"; + util::pressEnter(); + return; + } + bool hasPending = false; + for (int index = 0; index < currentInvoices.getSize(); ++index) + { + const Invoice* invoice = currentInvoices.getValueAt(index); + if (invoice && invoice->getStatus() == util::PaymentStatus::PENDING) + { + hasPending = true; + break; + } + } + if (!hasPending) + { + std::cout << "No pending invoices available for payment.\n"; + util::pressEnter(); + return; + } std::string selectedID = selectInvoiceFromUserForPayment(currentInvoices); if (selectedID == "") { std::cout << "Payment failed.\n"; + util::pressEnter(); return; } util::PaymentMode paymentMode = selectPaymentMode(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index 279c3b2..17b9bc5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -309,6 +309,7 @@ Returns: */ inline std::string selectInvoiceFromUserForPayment(const util::Map& currentInvoices) { + util::clear(); int currentIndex = 1, choice; util::Map pendingInvoicesForPayment; std::cout << std::left @@ -316,8 +317,8 @@ inline std::string selectInvoiceFromUserForPayment(const util::Map -#include -#include "AdminMenu.h" -#include "Enums.h" -#include "InputHelper.h" -#include "InventoryItem.h" -#include "MenuHelper.h" -#include "OutputHelper.h" -#include "Service.h" -#include "ServiceBooking.h" -#include "User.h" -#include "Utility.h" -#include "Validator.h" - -/* -Function: showMenu -Description: Displays the admin menu and handles user input until logout is selected. -Parameter: None -Return type: void -*/ -void AdminMenu::showMenu() -{ - while (true) - { - try - { - int choice; - util::clear(); - std::cout << "Admin Menu" - << "\n1. View Stock Levels" - << "\n2. Add Inventory Item" - << "\n3. Remove Inventory Item" - << "\n4. Check Stock Availability" - << "\n5. Assign Job to Technician" - << "\n6. Add Technician" - << "\n7. Remove Customer/Technician" - << "\n8. Create Service" - << "\n9. Remove Service" - << "\n10. Create Combo Package" - << "\n11. Remove Combo Package" - << "\n12. View Notifications" - << "\n13. Change Password" - << "\n14. Logout" - << "\nEnter a choice: "; - util::read(choice); - if (!handleOperation(choice)) - { - break; - } - } - catch (const std::exception& e) - { - std::cout << "Exception: " << e.what() << std::endl; - util::pressEnter(); - } - } -} - -/* -Function: handleOperation -Description: Executes the corresponding admin operation based on the selected menu choice. -Parameter: int choice - selected menu option -Return type: bool - true if menu continues, false if logout -*/ -bool AdminMenu::handleOperation(int choice) -{ - switch (choice) - { - case 1: - viewStockLevels(); - break; - case 2: - addInventoryItem(); - break; - case 3: - removeInventoryItem(); - break; - case 4: - checkStockAvailability(); - break; - case 5: - assignJob(); - break; - case 6: - addTechnician(); - break; - case 7: - removeUser(); - break; - case 8: - createService(); - break; - case 9: - removeService(); - break; - case 10: - createComboPackages(); - break; - case 11: - removeComboPackage(); - break; - case 12: - viewNotifications(); - break; - case 13: - changePassword(); - break; - case 14: - logout(); - return false; - default: - std::cout << "Enter a valid choice!" << std::endl; - util::pressEnter(); - } - return true; -} - -/* -Function: logout -Description: Logs out the currently authenticated admin user. -Parameter: None -Return type: void -*/ -void AdminMenu::logout() -{ - m_controller.logout(); -} - -/* -Function: changePassword -Description: Allows the admin to change their password after validation. -Parameter: None -Return type: void -*/ -void AdminMenu::changePassword() -{ - changePasswordHelper(m_controller); -} - -/* -Function: viewStockLevels -Description: Displays all active inventory items with their details - including ID, part name, quantity, and price. -Parameter: None -Return type: void -*/ -void AdminMenu::viewStockLevels() -{ - util::clear(); - auto inventoryItems = m_controller.getInventoryItems(); - bool hasActiveItems = false; - if (inventoryItems.isEmpty()) - { - std::cout << "No items found in Inventory.\n"; - util::pressEnter(); - return; - } - for (int index = 0; index < inventoryItems.getSize(); index++) - { - const InventoryItem* item = inventoryItems.getValueAt(index); - if (item->getState() == util::State::ACTIVE) - { - hasActiveItems = true; - break; - } - } - if (!hasActiveItems) - { - std::cout << "No active Inventory Item found.\n"; - util::pressEnter(); - return; - } - std::cout << std::left << std::setw(15) << "Item ID" - << std::setw(25) << "Part Name" - << std::setw(15) << "Quantity" - << std::setw(15) << "Price" - << std::endl; - for (int iterator = 0; iterator < inventoryItems.getSize(); ++iterator) - { - const InventoryItem* item = inventoryItems.getValueAt(iterator); - if (item != nullptr) - { - if (item->getState() != util::State::INACTIVE) - { - std::cout << std::left << std::setw(15) << item->getId() - << std::setw(25) << item->getPartName() - << std::setw(15) << item->getQuantity() - << std::setw(15) << item->getPrice() - << std::endl; - } - } - } - std::cout << "\n"; - util::pressEnter(); -} - -/* -Function: addInventoryItem -Description: Allows the admin to either add a new inventory item - or increase the quantity of an existing item. -Parameter: None -Return type: void -*/ -void AdminMenu::addInventoryItem() -{ - util::clear(); - int choice, quantity; - double price; - std::string partName; - std::cout << "1. Add new item \n2. Add Quantity\nEnter your choice : "; - util::read(choice); - switch (choice) - { - case 1: - { - std::cout << "--------Enter Item Details----------\n"; - std::cout << "Part Name : "; - util::read(partName); - std::cout << "Quantity : "; - util::read(quantity); - std::cout << "Price : "; - util::read(price); - m_controller.addInventoryItem(partName, quantity, price); - std::cout << "New Item " << partName << " added to the Inventory.\n"; - break; - } - case 2: - { - auto inventoryItems = m_controller.getInventoryItems(); - addQuantityToItem(inventoryItems, m_controller); - break; - } - } - util::pressEnter(); -} - -/* -Function: removeInventoryItem -Description: Removes an active inventory item by marking it inactive - after user selection. -Parameter: None -Return type: void -*/ -void AdminMenu::removeInventoryItem() -{ - util::clear(); - auto inventoryItems = m_controller.getInventoryItems(); - auto activeItems = filterActiveItems(inventoryItems); - int activeItemsSize = activeItems.getSize(); - if (activeItemsSize == 0) - { - std::cout << "No items available in Inventory." << std::endl; - util::pressEnter(); - return; - } - displayInventoryWithItems(activeItems); - int itemIndex; - std::cout << "Enter the index of the item to remove: "; - util::read(itemIndex); - if (itemIndex < 1 || itemIndex > activeItemsSize) - { - std::cout << "Invalid index selected." << std::endl; - util::pressEnter(); - return; - } - const InventoryItem* selectedItem = activeItems.getValueAt(itemIndex - 1); - if (selectedItem != nullptr) - { - if(selectedItem->getState() != util::State::INACTIVE) - { - std::string selectedItemId = selectedItem->getId(); - m_controller.removeInventoryItem(selectedItemId); - std::cout << "Item " << selectedItem->getPartName() << " removed successfully." << std::endl; - } - } - util::pressEnter(); -} - -/* -Function: checkStockAvailability -Description: Checks if a specific inventory item is available - and displays its details if active. -Parameter: None -Return type: void -*/ -void AdminMenu::checkStockAvailability() -{ - util::clear(); - std::string itemId; - std::cout << "Enter the Item Id : "; - util::read(itemId); - const InventoryItem* selectedItem = m_controller.getInventoryItem(itemId); - if (selectedItem != nullptr) - { - if (selectedItem->getState() != util::State::INACTIVE) - { - std::cout << "Item Details\n"; - std::cout << "---------------------------------------------\n"; - std::cout << "Item ID : " << selectedItem->getId() << "\n"; - std::cout << "Part Name : " << selectedItem->getPartName() << "\n"; - std::cout << "Quantity : " << selectedItem->getQuantity() << "\n"; - } - } - util::pressEnter(); -} - -/* -Function: assignJob -Description: Allows the admin to assign pending service bookings to available technicians. - Creates job cards for selected services. -Parameters: - - None -Returns: - - void -*/ -void AdminMenu::assignJob() -{ - util::clear(); - std::string selectedService; - bool hasPendingService = false; - auto currentBookings = m_controller.getServiceBookings(); - auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN); - int bookingsSize = currentBookings.getSize(); - util::Map serviceBookingsMap; - util::Map currentAvailableTechniciansMap; - if (listServiceBookings(currentBookings, bookingsSize, serviceBookingsMap)) - { - const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap); - if (selectedService) - { - if (availableTechnicians.getSize() != 0) - { - listAvailableTechnicians(availableTechnicians, availableTechnicians.getSize(), currentAvailableTechniciansMap); - const User* selectedTechnician = selectTechnician(currentAvailableTechniciansMap); - if (selectedTechnician) - { - auto& servicesInBooking = selectedService->getServices(); - for (int iterator = 0; iterator < servicesInBooking.getSize(); iterator++) - { - m_controller.createJobCard(selectedService->getId(), selectedTechnician->getId(), servicesInBooking.getValueAt(iterator)->getId()); - } - } - } - else - { - std::cout << "No technicians are currently available."; - } - } - } - util::pressEnter(); -} - -/* -Function: createService -Description: Allows the admin to create a new service by selecting inventory items and specifying labor cost. -Parameters: - - None -Returns: - - void -*/ -void AdminMenu::createService() -{ - util::clear(); - std::string serviceName; - double labourCost; - std::cout << "Enter the service name: "; - util::read(serviceName); - util::Map currentInventoryItems = m_controller.getInventoryItems(); - util::Vector selectedInventoryItems; - selectInventoryItems(currentInventoryItems,selectedInventoryItems); - std::cout << "Enter the labour cost: "; - util::read(labourCost); - m_controller.createService(serviceName, selectedInventoryItems, labourCost); - std::cout << "Service created sucessfully.\n"; - util::pressEnter(); -} - -/* -Function: removeService -Description: Allows the admin to remove an existing service by selecting from available services. -Parameters: - - None -Returns: - - void -*/ -void AdminMenu::removeService() -{ - util::clear(); - std::string selectedServiceID; - util::Map currentServices = m_controller.getServices(); - selectedServiceID = selectServicesToRemove(currentServices); - if (selectedServiceID != "") - { - m_controller.removeService(selectedServiceID); - std::cout << "Service removed sucessfully."; - } - else - { - std::cout << "Failed to remove service."; - } - util::pressEnter(); -} - -/* -Function: addTechnician -Description: Adds a new technician after validating username, password, email, and phone number. -Parameter: None -Return type: void -*/ -void AdminMenu::addTechnician() -{ - util::clear(); - std::string username, name, password, email, phoneNumber; - std::cout << std::left << std::setw(25) << "Enter Technician Username: "; - util::read(username); - std::cout << std::left << std::setw(25) << "Enter Technician Name: "; - util::read(name); - std::cout << std::setw(25) << "Enter Technician Password: "; - util::read(password); - if(!util::isPasswordValid(password)) - { - std::cout << "Error: Password is invalid!"; - util::pressEnter(); - return; - } - std::cout << std::setw(25) << "Enter Technician Email: "; - util::read(email); - if(!util::isEmailValid(email)) - { - std::cout << "Error: Email is invalid!"; - util::pressEnter(); - return; - } - std::cout << std::setw(25) << "Enter Technician Phone: "; - util::read(phoneNumber); - if(!util::isPhoneNumberValid(phoneNumber)) - { - std::cout << "Error: Phone Number is invalid!"; - util::pressEnter(); - return; - } - m_controller.createTechnician(username, name, password, email, phoneNumber); - std::cout << "\nTechnician Added Successfully.\n"; - util::pressEnter(); -} - -/* -Function: removeUser -Description: Removes a selected active user (customer or technician) from the system. -Parameter: None -Return type: void -*/ -void AdminMenu::removeUser() -{ - util::clear(); - int indexChoice; - auto listOfUsers = m_controller.getUsers(); - auto listOfActiveUsers = filterActiveUsers(listOfUsers); - int activeUserCount = listOfActiveUsers.getSize(); - if (activeUserCount < 1) - { - std::cout << "No Active users." << std::endl; - util::pressEnter(); - return; - } - displayAllActiveUsers(listOfActiveUsers, activeUserCount); - std::cout << "Enter the index of the user to delete : "; - util::read(indexChoice); - if (indexChoice < 1 || indexChoice > activeUserCount) - { - std::cout << "Error Invaild index.\n" << std::endl; - util::pressEnter(); - return; - } - const User* userToRemove = listOfActiveUsers.getValueAt(indexChoice - 1); - if (userToRemove != nullptr) - { - std::string userIdToRemove = userToRemove->getId(); - m_controller.removeUser(userIdToRemove); - std::cout << userToRemove->getUserName() << " removed Successfully.\n"; - } - util::pressEnter(); -} - -/* -Function: createComboPackages -Description: Creates a new combo package by selecting two active services and applying a discount. -Parameter: None -Return type: void -*/ -void AdminMenu::createComboPackages() -{ - util::clear(); - auto serviceList = m_controller.getServices(); - const int NUMBER_OF_SERVICE_PER_PACKAGE = 2; - util::Vector selectedServiceID; - for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++) - { - const Service* chosenService = nullptr; - while (true) - { - chosenService = selectServiceFromServices(serviceList); - if (chosenService == nullptr) - { - std::cout << "Failed to create combo package!"; - util::pressEnter(); - return; - } - bool alreadyChosen = false; - for (int iteratorOne = 0; iteratorOne < selectedServiceID.getSize(); iteratorOne++) - { - if (selectedServiceID[iteratorOne] == chosenService->getId()) - { - alreadyChosen = true; - break; - } - } - if (alreadyChosen) - { - std::cout << "Service already selected. Please choose a different one." << std::endl; - continue; - } - selectedServiceID.push_back(chosenService->getId()); - util::clear(); - break; - } - } - 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(); -} - -/* -Function: removeComboPackage -Description: Removes a selected combo package from the system. -Parameter: None -Return type: void -*/ -void AdminMenu::removeComboPackage() -{ - util::clear(); - util::Map currentComboPackages = m_controller.getComboPackages(); - std::string selectedComboPackageID = selectComboPackage(currentComboPackages); - if (selectedComboPackageID != "") - { - m_controller.removeComboPackage(selectedComboPackageID); - std::cout << "Combo Package removed successfully.\n"; - } - else - { - std::cout << "Combo package removal failed.\n"; - } - util::pressEnter(); -} - -/* -Function: viewNotifications -Description: Displays notifications for the admin and allows deletion of notifications. -Parameters: - - None -Returns: - - void -*/ -void AdminMenu::viewNotifications() -{ - viewAndDeleteNotification(m_controller); -} From 80b91f3f1bb4573bdcd98a9825487f10745f1160 Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Tue, 26 May 2026 18:48:23 +0530 Subject: [PATCH 5/7] Fix View Service History and View Notification Issue - Updated sendNotification in InventoryManagementService, PaymentManagementService, and ServiceManagementService to use only the provided title instead of prefixing with service name. - Added "View Service History" header in CustomerMenu::viewServiceHistory for clarity. - Adjusted column widths in service history table for better alignment: - Booking ID column widened to 15. - Vehicle Brand, Vehicle Number, Vehicle Model, Discount %, and Status columns widened to 20. - Updated output formatting in CustomerMenu::viewServiceHistory to match new widths. - Added "View and Delete Notification" header in MenuHelper::viewAndDeleteNotification for clarity. - Moved empty notification validation from selectNotification to viewAndDeleteNotification: - Displays "No notifications available." message. - Added util::pressEnter() prompt before returning when no notifications exist. - Increased Notification title column width from 30 to 35 in selectNotification for improved readability. Fixes #1748 --- .../services/InventoryManagementService.cpp | 2 +- .../services/PaymentManagementService.cpp | 2 +- .../services/ServiceManagementService.cpp | 2 +- .../views/CustomerMenu.cpp | 25 ++++++++++--------- .../views/MenuHelper.h | 14 ++++++----- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp index 5c3327a..d08d957 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp @@ -323,7 +323,7 @@ void InventoryManagementService::sendNotification(User* user, const std::string& Factory::getObject( user->getId(), user, - "InventoryManagementService: " + title, + title, message, util::Timestamp() ); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp index ba3282a..80e167d 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp @@ -86,7 +86,7 @@ void PaymentManagementService::sendNotification(User* user, const std::string& t Factory::getObject( user->getId(), user, - "PaymentManagementService: " + title, + title, message, util::Timestamp() ); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 799d701..45c6fe4 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -175,7 +175,7 @@ void ServiceManagementService::sendNotification(User* user, const std::string& t Factory::getObject( user->getId(), user, - "ServiceManagementService: " + title, + title, message, util::Timestamp() ); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index 85e7021..c8d334d 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -260,16 +260,17 @@ void CustomerMenu::viewServiceHistory() const User* currentUser = m_controller.getAuthenticatedUser(); std::string currentUserID = currentUser->getId(); util::Map serviceBookingsByCurrentUser = m_controller.getServiceBookingsByUser(currentUserID); + std::cout << "View Service History" << std::endl; if (serviceBookingsByCurrentUser.getSize() != 0) { std::cout << std::left - << std::setw(12) << "Booking ID" + << std::setw(15) << "Booking ID" << std::setw(20) << "Technician" - << std::setw(15) << "Vehicle Brand" - << std::setw(15) << "Vehicle Number" - << std::setw(15) << "Vehicle Model" - << std::setw(10) << "Discount %" - << std::setw(12) << "Status" + << std::setw(20) << "Vehicle Brand" + << std::setw(20) << "Vehicle Number" + << std::setw(20) << "Vehicle Model" + << std::setw(20) << "Discount %" + << std::setw(20) << "Status" << std::endl; for (int iterator = 0; iterator < serviceBookingsByCurrentUser.getSize(); iterator++) { @@ -278,13 +279,13 @@ void CustomerMenu::viewServiceHistory() ? "Not Assigned" : currentBooking->getAssignedTechnician()->getName(); std::cout << std::left - << std::setw(12) << currentBooking->getId() + << std::setw(15) << currentBooking->getId() << std::setw(20) << technicianName - << std::setw(15) << currentBooking->getVehicleBrand() - << std::setw(15) << currentBooking->getVehicleNumber() - << std::setw(15) << currentBooking->getVehicleModel() - << std::setw(10) << currentBooking->getDiscountPercentage() - << std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus()) + << std::setw(20) << currentBooking->getVehicleBrand() + << std::setw(20) << currentBooking->getVehicleNumber() + << std::setw(20) << currentBooking->getVehicleModel() + << std::setw(20) << currentBooking->getDiscountPercentage() + << std::setw(20) << util::getServiceJobStatusString(currentBooking->getStatus()) << std::endl; hasServiceHistory = true; } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index 17b9bc5..462391b 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -529,11 +529,6 @@ Return type: const Notification* - pointer to the selected notification */ inline const Notification* selectNotification(const util::Vector& notifications) { - if (notifications.getSize() == 0) - { - std::cout << "No notifications available." << std::endl; - return nullptr; - } util::Map indexedNotifications; std::cout << std::left << std::setw(6) << "Index" @@ -550,7 +545,7 @@ inline const Notification* selectNotification(const util::VectorgetId() - << std::setw(30) << currentNotification->getTitle() + << std::setw(35) << currentNotification->getTitle() << std::setw(25) << currentNotification->getCreatedAt().toString() << std::endl; indexedNotifications.insert(currentIndex, currentNotification); @@ -603,6 +598,13 @@ inline void viewAndDeleteNotification(Controller& controller) { util::clear(); auto notifications = controller.getNotifications(); + std::cout << "View and Delete Notification" << std::endl; + if (notifications.getSize() == 0) + { + std::cout << "No notifications available." << std::endl; + util::pressEnter(); + return; + } const Notification* selectedNotification = selectNotification(notifications); if (!selectedNotification) { From 33cbb1dac3fc3aeff912e367f06cb17b60fae0ae Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Tue, 26 May 2026 20:03:02 +0530 Subject: [PATCH 6/7] Fix Update Profile and User Validation Issues - Included Validator.h in UserManagementService.cpp for duplicate checks. - Enhanced updateUserDetails in UserManagementService to validate: - Throw error if user does not exist. - Throw error if email already exists among active users. - Throw error if phone number already exists among active users. - Implemented new duplicate validation functions in Validator.cpp: - isUsernameDuplicate - isPhoneDuplicate - isEmailDuplicate - Declared new duplicate validation functions in Validator.h. - Updated CustomerMenu::updateDetails: - Added "Update Details" header for clarity. - Improved error messages with newline formatting. - Added success message with newline formatting. Fixes #1746 --- .../services/UserManagementService.cpp | 10 +++++- .../utilities/Validator.cpp | 35 ++++++++++++++++++- .../views/CustomerMenu.cpp | 8 +++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 613a3d2..28263e8 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -111,7 +111,15 @@ void UserManagementService::updateUserDetails(const std::string& userID, const s int index = usersMap.find(userID); if (index == -1) { - throw std::runtime_error("User does not exist!"); + throw std::runtime_error("User does not exist!\n"); + } + if (util::isEmailDuplicate(email, usersMap)) + { + throw std::runtime_error("Email already exists!\n"); + } + if (util::isPhoneDuplicate(phone, usersMap)) + { + throw std::runtime_error("Phone number already exists!\n"); } User* user = usersMap.getValueAt(index); user->setEmail(email); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.cpp index cdba432..f56d660 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.cpp @@ -108,6 +108,17 @@ bool util::isPasswordValid(const std::string& password) return hasUpper && hasLower && hasDigit && hasSpecial; } +/* + * Function: isUsernameDuplicate + * Description: Checks if the given username already exists among active users. + * Parameters: + * username - string containing the username to validate + * usersMap - map of user objects keyed by identifier + * Returns: + * bool - true if the username is already in use by an active user, false otherwise + * Notes: + * - Only considers users with state util::State::ACTIVE + */ bool util::isUsernameDuplicate(const std::string& username, const util::Map& usersMap) { int index = usersMap.findIf( @@ -119,6 +130,17 @@ bool util::isUsernameDuplicate(const std::string& username, const util::Map& usersMap) { int index = usersMap.findIf( @@ -130,6 +152,17 @@ bool util::isPhoneDuplicate(const std::string& phone, const util::Map& usersMap) { int index = usersMap.findIf( @@ -139,4 +172,4 @@ bool util::isEmailDuplicate(const std::string& email, const util::Map userList = m_controller.getUsers(); util::clear(); + std::cout << "Update Details\n"; std::cout << "Enter new email: "; util::read(email); if (!util::isEmailValid(email)) { - std::cout << "Error: Email is invalid!"; + std::cout << "Error: Email is invalid!\n"; util::pressEnter(); return; } @@ -156,12 +158,12 @@ void CustomerMenu::updateDetails() util::read(phone); if (!util::isPhoneNumberValid(phone)) { - std::cout << "Error: Phone number is invalid!"; + std::cout << "Error: Phone number is invalid!\n"; util::pressEnter(); return; } m_controller.updateUserDetails(email, phone); - std::cout << "Profile details updated successfully"; + std::cout << "Profile details updated successfully\n"; util::pressEnter(); } From febfa45e4a8d6bddceee86f3d7401f8220edaa48 Mon Sep 17 00:00:00 2001 From: Joel Thomas Date: Tue, 26 May 2026 21:03:22 +0530 Subject: [PATCH 7/7] Implement review fixes Changes: - Strengthened UserManagementService::updateUserDetails by checking duplicates only when email/phone are changed, preventing false errors - Updated AdminMenu::viewStockLevels header text from "View Stock Level" to "View Stock Levels" for consistency - Cleaned up CustomerMenu::updateDetails by removing unused user list retrieval and improving header/message formatting --- .../services/UserManagementService.cpp | 22 ++++++++++++------- .../views/AdminMenu.cpp | 2 +- .../views/CustomerMenu.cpp | 1 - 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 28263e8..39f9148 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -113,15 +113,21 @@ void UserManagementService::updateUserDetails(const std::string& userID, const s { throw std::runtime_error("User does not exist!\n"); } - if (util::isEmailDuplicate(email, usersMap)) - { - throw std::runtime_error("Email already exists!\n"); - } - if (util::isPhoneDuplicate(phone, usersMap)) - { - throw std::runtime_error("Phone number already exists!\n"); - } User* user = usersMap.getValueAt(index); + if (email != user->getEmail()) + { + if (util::isEmailDuplicate(email, usersMap)) + { + throw std::runtime_error("Email already exists!\n"); + } + } + if (phone != user->getPhone()) + { + if (util::isPhoneDuplicate(phone, usersMap)) + { + throw std::runtime_error("Phone number already exists!\n"); + } + } user->setEmail(email); user->setPhone(phone); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 3b28e51..660decf 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -159,7 +159,7 @@ void AdminMenu::viewStockLevels() util::clear(); auto inventoryItems = m_controller.getInventoryItems(); bool hasActiveItems = false; - std::cout << "View Stock Level" << std::endl; + std::cout << "View Stock Levels" << std::endl; if (inventoryItems.isEmpty()) { std::cout << "No items found in Inventory.\n"; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index efb8d1c..d354a3c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -143,7 +143,6 @@ Return type: void void CustomerMenu::updateDetails() { std::string email, phone; - util::Map userList = m_controller.getUsers(); util::clear(); std::cout << "Update Details\n"; std::cout << "Enter new email: ";