From ae488f5670046c931d3cecbb9236d6b3b638db14 Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Tue, 26 May 2026 12:24:00 +0530 Subject: [PATCH] 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); +}