From b230e3062c6dac231cd9a7f5f2c4f0be30394ab3 Mon Sep 17 00:00:00 2001 From: Avinash Rajesh Date: Wed, 20 May 2026 19:25:24 +0530 Subject: [PATCH] Implement Remove Customer or Technician Functionality ADM002: Remove Technician or Customer 1. Integrated UserManagementService and ServiceManagementService into Controller for user removal operations. 2. Added Controller::removeUser to validate user existence, cancel related service bookings and technician jobs, and mark user inactive. 3. Updated JobCard and ServiceBooking models to use util::ServiceJobStatus consistently and store technician references as User* instead of strings. 4. Extended util::ServiceJobStatus enum with PENDING and CANCELLED states, including string conversion support. 5. Implemented ServiceManagementService methods to cancel customer service bookings and technician jobs, with inventory restocking and notifications. 6. Enhanced AdminMenu::removeUser to list active users, validate index input, confirm deletion, and invoke Controller::removeUser. 7. Added helper functions in AdminMenu to filter active users and display them with formatted output including user type. Precondition: 1. Admin is logged into the system. 2. Technician accounts exist in the system. 3. Technician has active job assignments. Steps: 1. Navigate to Admin Menu and select "Remove User". 2. System displays list of active users with IDs, usernames, and user types. - Verify that inactive users are excluded from the list. 3. Admin selects technician ID for removal. - Verify that system confirms deletion before proceeding. 4. Technician is removed from job assignment list. - Verify that associated jobs are cancelled, inventory is restocked, and notifications are sent. Sreeja Reghukumar --- .../Trenser.VehicleServiceSystem.vcxproj | 1 + ...enser.VehicleServiceSystem.vcxproj.filters | 3 + .../controllers/Controller.cpp | 17 +++- .../controllers/Controller.h | 5 + .../models/JobCard.cpp | 8 +- .../models/JobCard.h | 12 +-- .../models/ServiceBooking.cpp | 6 +- .../models/ServiceBooking.h | 8 +- .../services/ServiceManagementService.cpp | 99 +++++++++++++++++++ .../services/UserManagementService.cpp | 29 ++++++ .../utilities/Enums.h | 16 ++- .../utilities/Utility.h | 15 +++ .../views/AdminMenu.cpp | 73 ++++++++++++++ 13 files changed, 272 insertions(+), 20 deletions(-) create mode 100644 Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj index a65c46d..819264c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj @@ -176,6 +176,7 @@ + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters index 77d0509..7c17f4e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters @@ -233,5 +233,8 @@ Header Files\Models + + Header Files\Utilities + \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index d536e8a..3d71d7c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp @@ -1,4 +1,5 @@ #include "Controller.h" +#include "User.h" bool Controller::login(const std::string& username, const std::string& password) { @@ -78,7 +79,13 @@ util::Map Controller::getServiceBookingsByUs util::Map Controller::getUsers() { - return util::Map(); + auto listOfUsers = m_userManagementService.getUsers(); + util::Map readOnlyUserList; + for (int iterator = 0; iterator < listOfUsers.getSize(); iterator++) + { + readOnlyUserList.insert(listOfUsers.getKeyAt(iterator), listOfUsers.getValueAt(iterator)); + } + return readOnlyUserList; } util::Map Controller::getUsers(util::UserType userType) @@ -109,6 +116,14 @@ void Controller::completeJob(const std::string& jobID) void Controller::removeUser(const std::string& userID) { + User* user = m_userManagementService.getUser(userID); + if (!user) + { + throw std::runtime_error("Error User not Found.\n"); + } + m_serviceManagementService.cancelCustomerServiceBookings(userID); + m_serviceManagementService.cancelTechnicianJobs(userID); + m_userManagementService.removeUser(userID); } void Controller::createComboPackage(const std::string& name, const util::Vector& serviceIDs, double discountPercentage) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 3aabb58..7d4ff6a 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h @@ -2,6 +2,8 @@ #include "Map.h" #include #include "Enums.h" +#include "UserManagementService.h" +#include "ServiceManagementService.h" class Service; class ComboPackage; @@ -14,6 +16,9 @@ class Notification; class Controller { +private: + UserManagementService m_userManagementService; + ServiceManagementService m_serviceManagementService; public: bool login(const std::string& username, const std::string& password); void logout(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp index 04e9195..b9f1eee 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp @@ -7,7 +7,7 @@ JobCard::JobCard() m_booking(nullptr), m_service(nullptr), m_technician(nullptr), - m_status(ServiceJobStatus()) {} + m_status(util::ServiceJobStatus()) {} JobCard::JobCard(const std::string& bookingId, ServiceBooking* booking, @@ -16,7 +16,7 @@ JobCard::JobCard(const std::string& bookingId, const std::string& technicianId, User* technician, const util::Timestamp& assignedDate, - ServiceJobStatus status, + util::ServiceJobStatus status, const util::Timestamp& completionDate ) : m_id("JC" + std::to_string(++m_uid)), @@ -70,7 +70,7 @@ const util::Timestamp& JobCard::getAssignedDate() const return m_assignedDate; } -ServiceJobStatus JobCard::getStatus() const +util::ServiceJobStatus JobCard::getStatus() const { return m_status; } @@ -120,7 +120,7 @@ void JobCard::setAssignedDate(const util::Timestamp& assignedDate) m_assignedDate = assignedDate; } -void JobCard::setStatus(ServiceJobStatus status) +void JobCard::setStatus(util::ServiceJobStatus status) { m_status = status; } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h index 15a8a5d..b266d40 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h @@ -1,13 +1,12 @@ #pragma once #include #include "Timestamp.h" +#include "Enums.h" class ServiceBooking; class Service; class User; -enum class ServiceJobStatus : int; - class JobCard { private: @@ -20,9 +19,8 @@ private: std::string m_technicianId; User* m_technician; util::Timestamp m_assignedDate; - ServiceJobStatus m_status; + util::ServiceJobStatus m_status; util::Timestamp m_completionDate; - public: JobCard(); JobCard(const std::string& bookingId, @@ -32,7 +30,7 @@ public: const std::string& technicianId, User* technician, const util::Timestamp& assignedDate, - ServiceJobStatus status, + util::ServiceJobStatus status, const util::Timestamp& completionDate ); const std::string& getId() const; @@ -43,7 +41,7 @@ public: const std::string& getTechnicianId() const; User* getTechnician() const; const util::Timestamp& getAssignedDate() const; - ServiceJobStatus getStatus() const; + util::ServiceJobStatus getStatus() const; const util::Timestamp& getCompletionDate() const; void setId(const std::string& id); void setBookingId(const std::string& bookingId); @@ -53,6 +51,6 @@ public: void setTechnicianId(const std::string& technicianId); void setTechnician(User* technician); void setAssignedDate(const util::Timestamp& assignedDate); - void setStatus(ServiceJobStatus status); + void setStatus(util::ServiceJobStatus status); void setCompletionDate(const util::Timestamp& completionDate); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp index 1fdfaf0..1985e7b 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp @@ -18,7 +18,7 @@ ServiceBooking::ServiceBooking( const std::string& vehicleBrand, const std::string& vehicleModel, const std::string& assignedTechnicianId, - const std::string& assignedTechnician, + User* assignedTechnician, double discountPercentage ) : m_id("SRV" + std::to_string(++m_uid)), @@ -80,7 +80,7 @@ const std::string& ServiceBooking::getAssignedTechnicianId() const return m_assignedTechnicianId; } -const std::string& ServiceBooking::getAssignedTechnician() const +User* ServiceBooking::getAssignedTechnician() const { return m_assignedTechnician; } @@ -135,7 +135,7 @@ void ServiceBooking::setAssignedTechnicianId(const std::string& assignedTechnici m_assignedTechnicianId = assignedTechnicianId; } -void ServiceBooking::setAssignedTechnician(const std::string& assignedTechnician) +void ServiceBooking::setAssignedTechnician(User* assignedTechnician) { m_assignedTechnician = assignedTechnician; } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.h index 5ecc1b0..f5b96cd 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.h @@ -19,7 +19,7 @@ private: std::string m_vehicleBrand; std::string m_vehicleModel; std::string m_assignedTechnicianId; - std::string m_assignedTechnician; + User* m_assignedTechnician; double m_discountPercentage; public: ServiceBooking(); @@ -34,7 +34,7 @@ public: const std::string& vehicleBrand, const std::string& vehicleModel, const std::string& assignedTechnicianId, - const std::string& assignedTechnician, + User* assignedTechnician, double discountPercentage ); const std::string& getId() const; @@ -46,7 +46,7 @@ public: const std::string& getVehicleBrand() const; const std::string& getVehicleModel() const; const std::string& getAssignedTechnicianId() const; - const std::string& getAssignedTechnician() const; + User* getAssignedTechnician() const; double getDiscountPercentage() const; void setId(const std::string& id); void setStatus(const util::ServiceJobStatus& status); @@ -57,6 +57,6 @@ public: void setVehicleBrand(const std::string& vehicleBrand); void setVehicleModel(const std::string& vehicleModel); void setAssignedTechnicianId(const std::string& assignedTechnicianId); - void setAssignedTechnician(const std::string& assignedTechnician); + void setAssignedTechnician(User* assignedTechnician); void setDiscountPercentage(double discountPercentage); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 156c12b..6f15664 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -1 +1,100 @@ #include "ServiceManagementService.h" +#include "DataStore.h" +#include "ServiceBooking.h" +#include "JobCard.h" +#include "Service.h" +#include "InventoryItem.h" + +void ServiceManagementService::cancelCustomerServiceBookings(const std::string& userID) +{ + const int INCREMENT_VALUE = 1; + auto& users = m_dataStore.getUsers(); + int userIndex = users.find(userID); + if (userIndex == -1) + { + throw std::runtime_error("User not found: " + userID); + } + User* user = users.getValueAt(userIndex); + if (user == nullptr) + { + throw std::runtime_error("User not found: " + userID); + } + util::UserType type = user->getUserType(); + auto& bookings = DataStore::getInstance().getServiceBookings(); + for (int bookingIterator = 0; bookingIterator < bookings.getSize(); bookingIterator++) + { + ServiceBooking* booking = bookings.getValueAt(bookingIterator); + if (booking != nullptr && + (booking->getCustomerId() == userID || booking->getAssignedTechnicianId() == userID)) + { + if (booking->getStatus() == util::ServiceJobStatus::PENDING || + booking->getStatus() == util::ServiceJobStatus::STARTED) + { + if (type == util::UserType::CUSTOMER) + { + booking->setStatus(util::ServiceJobStatus::CANCELLED); + booking->setCustomer(nullptr); + booking->setCustomerId(""); + User* assignedTechnician = booking->getAssignedTechnician(); + sendNotification(assignedTechnician, "Customer Service Cancelled", "Uh?Oh. The customer has cancelled their service booking. Your assigned job card has been cancelled and the inventory has been restocked."); + } + else if (type == util::UserType::TECHNICIAN) + { + booking->setStatus(util::ServiceJobStatus::PENDING); + sendNotification(booking->getCustomer(), "Technician Unavailable", "Your assigned technician is no longer available. Your booking has been reset to pending, and we will reassign a new technician shortly."); + } + booking->setAssignedTechnician(nullptr); + booking->setAssignedTechnicianId(""); + const auto& ListOfServices = booking->getServices(); + for (int serviceIterator = 0; serviceIterator < ListOfServices.getSize(); serviceIterator++) + { + Service* service = ListOfServices.getValueAt(serviceIterator); + if (service != nullptr) + { + const auto& items = service->getRequiredInventoryItems(); + for (int itemIterator = 0; itemIterator < items.getSize(); itemIterator++) + { + InventoryItem* item = items.getValueAt(itemIterator); + if (item != nullptr) + { + item->setQuantity(item->getQuantity() + INCREMENT_VALUE); + } + } + } + } + } + } + } +} + + +void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID) +{ + const int INCREMENT_VALUE = 1; + auto& jobs = m_dataStore.getJobCards(); + for (int jobIterator = 0; jobIterator < jobs.getSize(); jobIterator++) + { + JobCard* job = jobs.getValueAt(jobIterator); + if (job != nullptr && job->getTechnicianId() == technicianID) + { + if (job->getStatus() == util::ServiceJobStatus::PENDING || job->getStatus() == util::ServiceJobStatus::STARTED) + { + job->setStatus(util::ServiceJobStatus::CANCELLED); + sendNotification(job->getTechnician(), "Job Cancelled", "The Job has cancelled. Your job card has been cancelled and the inventory has been restocked."); + Service* service = job->getService(); + if (service != nullptr) + { + const auto& items = service->getRequiredInventoryItems(); + for (int itemIterator = 0; itemIterator < items.getSize(); itemIterator++) + { + InventoryItem* item = items.getValueAt(itemIterator); + if (item != nullptr) + { + item->setQuantity(item->getQuantity() + INCREMENT_VALUE); + } + } + } + } + } + } +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 2a5bd9e..4e26942 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -1 +1,30 @@ #include "UserManagementService.h" +#include "User.h" + +util::Map UserManagementService::getUsers() +{ + return m_dataStore.getUsers(); +} + +User* UserManagementService::getUser(const std::string& userID) +{ + int index = m_dataStore.getUsers().find(userID); + if (index != -1) + { + return m_dataStore.getUsers().getValueAt(index); + } + return nullptr; +} + +void UserManagementService::removeUser(const std::string& userID) +{ + int index = m_dataStore.getUsers().find(userID); + if (index != -1) + { + User* user = m_dataStore.getUsers().getValueAt(index); + if (user != nullptr) + { + user->setState(util::State::INACTIVE); + } + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h index 24bbdcd..efaa387 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h @@ -24,8 +24,10 @@ namespace util enum class ServiceJobStatus { + PENDING, STARTED, - COMPLETED + COMPLETED, + CANCELLED }; enum class State @@ -121,10 +123,14 @@ namespace util { switch (status) { + case ServiceJobStatus::PENDING: + return "PENDING"; case ServiceJobStatus::STARTED: return "STARTED"; case ServiceJobStatus::COMPLETED: return "COMPLETED"; + case ServiceJobStatus::CANCELLED: + return "CANCELLED"; } throw std::invalid_argument("Invalid ServiceJobStatus"); } @@ -139,6 +145,14 @@ namespace util { return ServiceJobStatus::COMPLETED; } + if (value == "PENDING") + { + return ServiceJobStatus::PENDING; + } + if (value == "CANCELLED") + { + return ServiceJobStatus::CANCELLED; + } throw std::invalid_argument("Invalid ServiceJobStatus string"); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h new file mode 100644 index 0000000..cb9b990 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h @@ -0,0 +1,15 @@ +#pragma once +#include "Service.h" +#include "InventoryItem.h" + +inline double calculatePartsCost(const Service* service) +{ + double cost = 0; + auto& requiredInventoryItems = service->getRequiredInventoryItems(); + int requiredInventoryItemsSize = requiredInventoryItems.getSize(); + for (int index = 0; index < requiredInventoryItemsSize; index++) + { + cost += requiredInventoryItems.getValueAt(index)->getPrice(); + } + return cost; +} \ 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 0432f3c..39caee5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -1,6 +1,8 @@ +#include #include "AdminMenu.h" #include "InputHelper.h" #include "OutputHelper.h" +#include "User.h" void AdminMenu::showMenu() { @@ -72,8 +74,79 @@ void AdminMenu::addTechnician() { } +static util::Map +filterActiveUsers(const util::Map& listOfUsers) +{ + util::Map activeUsers; + int inventorySize = listOfUsers.getSize(); + for (int index = 0; index < inventorySize; index++) + { + const User* user = listOfUsers.getValueAt(index); + if (user != nullptr && user->getState() != util::State::INACTIVE) + { + activeUsers.insert(user->getId(), user); + } + } + return activeUsers; +} + +static void displayAllActiveUsers(util::Map& activeUsers, int activeUserCount) +{ + std::cout << std::left << std::setw(10) << "Index" + << std::setw(15) << "User ID" + << std::setw(25) << "Username" + << std::setw(25) << "User Type" + << std::endl; + for (int iterator = 0; iterator < activeUserCount; iterator++) + { + const User* user = activeUsers.getValueAt(iterator); + if (user != nullptr) + { + std::cout << std::left << std::setw(10) << (iterator + 1) + << std::setw(15) << user->getId() + << std::setw(25) << user->getUserName() + << std::setw(25) << util::getUserTypeString(user->getUserType()) + << std::endl; + } + else + { + std::cout << "No users found.\n"; + util::pressEnter(); + return; + } + } +} + 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(); } void AdminMenu::createComboPackages()