From 9b7d9cf7c19798aa2bd26baebde4e416b27ad7c4 Mon Sep 17 00:00:00 2001 From: Jissin Sam Mathew Date: Tue, 19 May 2026 18:47:12 +0530 Subject: [PATCH 1/5] Implement Assign Job to Technician functionality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SER001: Assign job to technician 1. Added ServiceManagementService logic to retrieve service bookings and create job cards for assigned technicians. 2. Added UserManagementService support to retrieve technicians by user type and fetch technician details by ID. 3. Connected Controller methods with ServiceManagementService and UserManagementService for service booking retrieval, technician listing, and job card creation. 4. Updated JobCard model to use util::ServiceJobStatus consistently and simplified constructor initialization for assigned and completion timestamps. 5. Added PENDING status in ServiceJobStatus enum for identifying unassigned service bookings. 6. Implemented AdminMenu job assignment flow to list pending service bookings, display available technicians, allow technician selection, and assign jobs for services in the booking. 7. Added notification trigger during job card creation for assigned technicians. Job assignment functionality validation Precondition: 1. System is running. 2. Pending service bookings are available in the system. 3. Technician users are available in the system. 4. Admin user is logged in and admin menu is active. Steps: 1. Launch the application and log in as an admin. 2. Select the Assign Job option from the admin menu. 3. View the list of available pending service bookings. - Verify that pending bookings are displayed. 4. Select a valid service booking. 5. View the list of available technicians. - Verify that technicians are listed for selection. 6. Select a technician to assign the job. - Verify that job cards are created for services in the booking. - Verify that assigned jobs are visible in the technician’s menu. - Verify that a confirmation message is shown. - Verify that a confirmation notification is sent to the assigned technician. Sreeja Reghukumar, please review --- .../controllers/Controller.cpp | 17 ++- .../controllers/Controller.h | 5 + .../models/JobCard.cpp | 14 +- .../models/JobCard.h | 13 +- .../models/ServiceBooking.cpp | 6 +- .../models/ServiceBooking.h | 8 +- .../services/ServiceManagementService.cpp | 69 +++++++++ .../services/ServiceManagementService.h | 1 + .../services/UserManagementService.cpp | 30 ++++ .../utilities/Enums.h | 3 + .../views/AdminMenu.cpp | 143 ++++++++++++++++++ 11 files changed, 284 insertions(+), 25 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index d536e8a..7faa752 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp @@ -68,7 +68,13 @@ void Controller::removeInventoryItem(const std::string& inventoryItemID) util::Map Controller::getServiceBookings() { - return util::Map(); + auto serviceBookings = m_serviceManagementService.getServiceBookings(); + util::Map readOnlyServiceBookings; + for (int iterator = 0; iterator < serviceBookings.getSize(); iterator++) + { + readOnlyServiceBookings.insert(serviceBookings.getKeyAt(iterator), serviceBookings.getValueAt(iterator)); + } + return readOnlyServiceBookings; } util::Map Controller::getServiceBookingsByUser(const std::string userID) @@ -83,11 +89,18 @@ util::Map Controller::getUsers() util::Map Controller::getUsers(util::UserType userType) { - return util::Map(); + auto userMap = m_userManagementService.getUsers(userType); + util::Map readOnlyUserMap; + for (int iterator = 0; iterator < userMap.getSize(); iterator++) + { + readOnlyUserMap.insert(userMap.getKeyAt(iterator), userMap.getValueAt(iterator)); + } + return readOnlyUserMap; } void Controller::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID) { + m_serviceManagementService.createJobCard(bookingID, technicianID, serviceID); } void Controller::createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 3aabb58..b22a9b6 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 "ServiceManagementService.h" +#include "UserManagementService.h" class Service; class ComboPackage; @@ -14,6 +16,9 @@ class Notification; class Controller { +private: + ServiceManagementService m_serviceManagementService; + UserManagementService m_userManagementService; 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..0229352 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, @@ -15,9 +15,7 @@ JobCard::JobCard(const std::string& bookingId, const std::string& serviceId, const std::string& technicianId, User* technician, - const util::Timestamp& assignedDate, - ServiceJobStatus status, - const util::Timestamp& completionDate + util::ServiceJobStatus status ) : m_id("JC" + std::to_string(++m_uid)), m_bookingId(bookingId), @@ -26,9 +24,9 @@ JobCard::JobCard(const std::string& bookingId, m_serviceId(serviceId), m_technicianId(technicianId), m_technician(technician), - m_assignedDate(assignedDate), + m_assignedDate(util::Timestamp()), m_status(status), - m_completionDate(completionDate) {} + m_completionDate(util::Timestamp()) {} const std::string& JobCard::getId() const { @@ -70,7 +68,7 @@ const util::Timestamp& JobCard::getAssignedDate() const return m_assignedDate; } -ServiceJobStatus JobCard::getStatus() const +util::ServiceJobStatus JobCard::getStatus() const { return m_status; } @@ -120,7 +118,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..c501e93 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,7 +19,7 @@ private: std::string m_technicianId; User* m_technician; util::Timestamp m_assignedDate; - ServiceJobStatus m_status; + util::ServiceJobStatus m_status; util::Timestamp m_completionDate; public: @@ -31,9 +30,7 @@ public: const std::string& serviceId, const std::string& technicianId, User* technician, - const util::Timestamp& assignedDate, - ServiceJobStatus status, - const util::Timestamp& completionDate + util::ServiceJobStatus status ); const std::string& getId() const; const std::string& getBookingId() const; @@ -43,7 +40,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 +50,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..aeb7f4d 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, + const 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 +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(const 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..8996d36 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; + const 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, + const 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; + 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(const 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..0bc77b9 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -1 +1,70 @@ #include "ServiceManagementService.h" +#include "UserManagementService.h" +#include "ServiceBooking.h" +#include "Factory.h" +#include "JobCard.h" +#include "Timestamp.h" +#include "Service.h" +#include "InventoryItem.h" + +util::Map ServiceManagementService::getServiceBookings() +{ + return m_dataStore.getServiceBookings(); +} + +ServiceBooking* ServiceManagementService::getServiceBooking(const std::string& serviceID) +{ + auto currentServiceBookings = getServiceBookings(); + for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++) + { + if (currentServiceBookings.getValueAt(iterator)->getId() == serviceID) + { + return currentServiceBookings.getValueAt(iterator); + } + } + return nullptr; +} + +void ServiceManagementService::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID) +{ + UserManagementService m_userManagementService; + ServiceBooking* currentBooking = getServiceBooking(bookingID); + auto& currentJobCards = m_dataStore.getJobCards(); + if (currentBooking == nullptr) + { + throw std::runtime_error("Service Booking not available"); + } + auto& currentServices = currentBooking->getServices(); + if (currentServices.find(serviceID) == -1) + { + throw std::runtime_error("Invalid service Id"); + } + Service* currentService = currentServices.getValueAt(currentServices.find(serviceID)); + User* selectedTechnician = m_userManagementService.getUser(technicianID); + if (selectedTechnician == nullptr) + { + throw std::runtime_error("Technician not available"); + } + auto& inventoryItems = currentService->getRequiredInventoryItems(); + for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++) + { + InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator); + if (currentInventoryItem->getQuantity() == 0) + { + std::string errorMessage = "Failed to create job card, " + currentInventoryItem->getPartName() + " is out of stock."; + throw std::runtime_error(errorMessage); + } + else + { + int currentStockQuantity = currentInventoryItem->getQuantity(); + currentInventoryItem->setQuantity(currentStockQuantity - 1); + } + } + currentBooking->setAssignedTechnician(selectedTechnician); + currentBooking->setAssignedTechnicianId(selectedTechnician->getId()); + std::string title = "Job card created"; + std::string message = "Job card created for the service and you are assigned for that."; + JobCard* jobCard = Factory::getObject(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::ServiceJobStatus::STARTED); + currentJobCards.insert(jobCard->getId(), jobCard); + sendNotification(selectedTechnician,title, message); +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.h index 85e05ed..ab5723e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.h @@ -22,6 +22,7 @@ public: void purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel); util::Map getServiceBookings(); util::Map getServiceBookings(const std::string& customerID); + ServiceBooking* getServiceBooking(const std::string& serviceID); void createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID); void createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost); void removeService(const std::string& serviceID); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 2a5bd9e..4f8adb2 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -1 +1,31 @@ #include "UserManagementService.h" +#include "User.h" + +util::Map UserManagementService::getUsers(util::UserType type) +{ + util::Map& currentUsers = m_dataStore.getUsers(); + util::Map filteredUsersMap; + for (int iterator = 0; iterator < currentUsers.getSize(); iterator++) + { + User* currentUser = currentUsers.getValueAt(iterator); + if (currentUser->getUserType() == type) + { + filteredUsersMap.insert(currentUser->getId(), currentUser); + } + } + return filteredUsersMap; +} + +User* UserManagementService::getUser(const std::string& userID) +{ + util::Map& currentUsers = m_dataStore.getUsers(); + for (int iterator = 0; iterator < currentUsers.getSize(); iterator++) + { + User* currentUser = currentUsers.getValueAt(iterator); + if (currentUser->getId() == userID) + { + return currentUser; + } + } + return nullptr; +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h index 24bbdcd..5353467 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h @@ -24,6 +24,7 @@ namespace util enum class ServiceJobStatus { + PENDING, STARTED, COMPLETED }; @@ -125,6 +126,8 @@ namespace util return "STARTED"; case ServiceJobStatus::COMPLETED: return "COMPLETED"; + case ServiceJobStatus::PENDING: + return "STARTED"; } throw std::invalid_argument("Invalid ServiceJobStatus"); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 0432f3c..e0319ff 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -1,6 +1,10 @@ +#include #include "AdminMenu.h" #include "InputHelper.h" #include "OutputHelper.h" +#include "ServiceBooking.h" +#include "Enums.h" +#include "Service.h" void AdminMenu::showMenu() { @@ -56,8 +60,147 @@ void AdminMenu::checkStockAvailability() { } +static bool listServiceBookings(util::Map& currentBookings, int& bookingsSize, util::Map& serviceBookingsMap) +{ + int currentIndex = 1; + bool hasPendingService = false; + std::cout << std::left + << std::setw(10) << "Index" + << std::setw(10) << "ID" + << std::setw(12) << "Status" + << std::setw(12) << "CustID" + << std::setw(20) << "Customer" + << std::setw(15) << "VehicleNo" + << std::setw(15) << "Brand" + << std::setw(15) << "Model" + << std::setw(20) << "Technician" + << std::setw(15) << "TechID" + << std::endl; + for (int iterator = 0; iterator < bookingsSize; iterator++) + { + const ServiceBooking* currentBooking = currentBookings.getValueAt(iterator); + if (currentBooking && currentBooking->getStatus() == util::ServiceJobStatus::PENDING) + { + hasPendingService = true; + std::cout << std::left + << std::setw(10) << currentIndex + << std::setw(10) << currentBooking->getId() + << std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus()) + << std::setw(12) << currentBooking->getCustomerId() + << std::setw(20) << currentBooking->getCustomer()->getName() + << std::setw(15) << currentBooking->getVehicleNumber() + << std::setw(15) << currentBooking->getVehicleBrand() + << std::setw(15) << currentBooking->getVehicleModel() + << std::setw(20) << (currentBooking->getAssignedTechnician() == nullptr ? "Null" : currentBooking->getAssignedTechnician()->getName()) + << std::setw(15) << (currentBooking->getAssignedTechnicianId().empty() ? "Null" : currentBooking->getAssignedTechnicianId()) + << std::endl; + serviceBookingsMap.insert(currentIndex++, currentBooking); + } + } + if (!hasPendingService) + { + std::cout << "No pending service available." << std::endl; + return false; + } + return true; +} + +static const ServiceBooking* selectPendingServiceBookings(util::Map& serviceBookingsMap) +{ + int userInputIndex; + std::cout << "Enter a valid service index: "; + util::read(userInputIndex); + if (serviceBookingsMap.find(userInputIndex) != -1) + { + return serviceBookingsMap.getValueAt(userInputIndex); + } + else + { + std::cout << "Enter a valid index."; + return nullptr; + } +} + +static void listAvailableTechnicians( util::Map currentAvailableTechnicians, int numberOfTechnicians, util::Map& currentAvailableTechniciansMap) +{ + bool hasTechnicians = false; + int currentIndex = 1; + std::cout << std::left + << std::setw(6) << "Index" + << std::setw(15) << "Technician ID" + << std::setw(20) << "Name" + << std::endl; + for (int iterator = 0; iterator < numberOfTechnicians; iterator++) + { + const User* currentTechnician = currentAvailableTechnicians.getValueAt(iterator); + if (currentTechnician->getState() == util::State::INACTIVE) + { + continue; + } + hasTechnicians = true; + std::cout << std::left + << std::setw(6) << currentIndex + << std::setw(15) << currentTechnician->getId() + << std::setw(20) << currentTechnician->getName() + << std::endl; + currentAvailableTechniciansMap.insert(currentIndex++, currentTechnician); + } + if (!hasTechnicians) + { + std::cout << "No technicians currently available."; + } +} + +static const User* selectTechnician(util::Map& currentAvailableTechniciansMap) +{ + int userInputIndex; + util::read(userInputIndex); + if (currentAvailableTechniciansMap.find(userInputIndex) != -1) + { + return currentAvailableTechniciansMap.getValueAt(userInputIndex); + } + else + { + std::cout << "Enter a valid index."; + return nullptr; + } +} + 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."; + } + } + } + } void AdminMenu::createService() From e7f1b51d05e04b8e6d9b9e53502b2994653ac1a3 Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Tue, 19 May 2026 20:29:19 +0530 Subject: [PATCH 2/5] Implement Create Service for admin SER002: Create Service 1. Added integration between Controller and ServiceManagementService to support service creation. 2. Implemented ServiceManagementService::createService with validation for duplicate service IDs and insertion into datastore. 3. Enhanced AdminMenu with selectInventoryItems helper to display inventory in tabular format, allow selection, and handle exit condition. 4. Updated AdminMenu::createService to prompt for service name, allow inventory selection, capture labour cost, and create service via Controller. Acceptance Criteria: 1. Admin enters new service name. 2. Admin selects required parts for the services. 3. Service created and visible to customers. Precondition: 1. Admin is logged into the system. 2. Inventory contains at least one active item. 3. Datastore is available for storing services. Steps: 1. Navigate to Admin menu and choose "Create Service". - Verify that the system prompts for service name. 2. Select inventory items from the tabular list. - Verify that inactive items are skipped and active items can be added. 3. Enter labour cost and confirm creation. - Verify that the service is created successfully and stored in datastore. 4. Check customer view. - Verify that the newly created service is visible to customers. Sreeja Reghukumar, please review --- .../controllers/Controller.cpp | 3 +- .../controllers/Controller.h | 4 + .../services/ServiceManagementService.cpp | 17 ++++ .../views/AdminMenu.cpp | 79 +++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index d536e8a..15de314 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 "InventoryItem.h" bool Controller::login(const std::string& username, const std::string& password) { @@ -50,7 +51,6 @@ void Controller::purchaseComboPackage(const std::string& comboPackageID, const s util::Map Controller::getInventoryItems() { - return util::Map(); } const InventoryItem* Controller::getInventoryItem(const std::string& inventoryItemID) @@ -92,6 +92,7 @@ void Controller::createJobCard(const std::string& bookingID, const std::string& void Controller::createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost) { + m_serviceManagementService.createService(name, inventoryItemIDs, laborCost); } void Controller::removeService(const std::string& serviceID) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 3aabb58..050d65b 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 "InventoryManagementService.h" +#include "ServiceManagementService.h" class Service; class ComboPackage; @@ -14,6 +16,8 @@ class Notification; class Controller { +private: + ServiceManagementService m_serviceManagementService; public: bool login(const std::string& username, const std::string& password); void logout(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 156c12b..a29c200 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -1 +1,18 @@ #include "ServiceManagementService.h" +#include "Factory.h" +#include "Service.h" + +void ServiceManagementService::createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost) +{ + Service* newService = Factory::getObject(name, inventoryItemIDs, laborCost); + if (newService == nullptr) + { + throw std::runtime_error("Unable to create new service."); + } + util::Map& currentServices = m_dataStore.getServices(); + if (currentServices.find(newService->getId()) != -1) + { + throw std::runtime_error("Service with this ID Already exists."); + } + currentServices.insert(newService->getId(), newService); +} \ 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..eb0dc01 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 "InventoryItem.h" void AdminMenu::showMenu() { @@ -60,8 +62,85 @@ void AdminMenu::assignJob() { } +static void selectInventoryItems(util::Map& currentInventoryItems, util::Vector& selectedInventoryItems) +{ + bool doRun = true, hasInventoryItems = false; + util::Map currentInventoryMap; + int currentIndex = 1; + int choice; + if (currentInventoryItems.getSize() == 0) + { + std::cout << "Inventory empty."; + } + while (doRun) + { + bool hasInventoryItems = false; + int currentIndex = 1; + currentInventoryMap.clear(); + std::cout << std::left + << std::setw(6) << "Index" + << std::setw(12) << "Item ID" + << std::setw(20) << "Part Name" + << std::setw(10) << "Price" + << std::setw(10) << "Quantity" + << std::endl; + for (int iterator = 0; iterator < currentInventoryItems.getSize(); iterator++) + { + const InventoryItem* currentInventoryItem = currentInventoryItems.getValueAt(iterator); + if (currentInventoryItem->getState() == util::State::INACTIVE) + { + continue; + } + std::cout << std::left + << std::setw(6) << currentIndex + << std::setw(12) << currentInventoryItem->getId() + << std::setw(20) << currentInventoryItem->getPartName() + << std::setw(10) << currentInventoryItem->getPrice() + << std::setw(10) << currentInventoryItem->getQuantity() + << std::endl; + + hasInventoryItems = true; + currentInventoryMap.insert(currentIndex++, currentInventoryItem); + } + if (!hasInventoryItems) + { + std::cout << "No items present in the inventory." << std::endl; + doRun = false; + break; + } + std::cout << "Select the item (Index) or enter -1 to exit: "; + util::read(choice); + + if (choice == -1) + { + doRun = false; + } + else if (currentInventoryMap.find(choice) != -1) + { + selectedInventoryItems.push_back(currentInventoryMap.getValueAt(choice)->getId()); + std::cout << "Item added successfully." << std::endl; + } + else + { + std::cout << "Enter a valid integer." << std::endl; + } + } +} + 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"; } void AdminMenu::removeService() From 70e1ef66d47c9f36057e004f190846f5f1a56caf Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Tue, 19 May 2026 21:36:14 +0530 Subject: [PATCH 3/5] Implement Remove Service for admin SER003: Remove Service 1. Added integration between Controller and ServiceManagementService to support service removal. 2. Implemented ServiceManagementService::removeService with validation for service existence and marking as INACTIVE. 3. Enhanced Controller::getServices to return a read-only map of services for safe UI access. 4. Added AdminMenu::selectServicesToRemove helper to list active services in tabular format and capture user choice. 5. Updated AdminMenu::removeService to prompt for service selection, delegate removal to Controller, and display success/failure messages. Acceptance Criteria: 1. Admin selects service ID. 2. System confirms deletion. 3. Service removed from customer menu. Precondition: 1. Admin is logged into the system. 2. At least one active service exists in the datastore. 3. Customer menu displays available services. Steps: 1. Navigate to Admin menu and choose "Remove Service". - Verify that the system lists active services in tabular format. 2. Select a service ID from the list. - Verify that the system confirms deletion. 3. Check customer menu. - Verify that the removed service no longer appears. Sreeja Reghukumar, please review --- .../controllers/Controller.cpp | 10 +++- .../controllers/Controller.h | 3 + .../services/ServiceManagementService.cpp | 20 +++++++ .../views/AdminMenu.cpp | 60 +++++++++++++++++++ 4 files changed, 92 insertions(+), 1 deletion(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index d536e8a..eafd451 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 "Service.h" bool Controller::login(const std::string& username, const std::string& password) { @@ -32,7 +33,13 @@ void Controller::updateUserDetails(const std::string& email, const std::string& util::Map Controller::getServices() { - return util::Map(); + util::Map currentServices = m_serviceManagementService.getServices(); + util::Map readOnlyServices; + for (int iterator = 0; iterator < currentServices.getSize(); iterator++) + { + readOnlyServices.insert(currentServices.getValueAt(iterator)->getId(), currentServices.getValueAt(iterator)); + } + return readOnlyServices; } util::Map Controller::getComboPackages() @@ -96,6 +103,7 @@ void Controller::createService(const std::string& name, const util::Vector Controller::getJobCardsByUser() diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 3aabb58..8512598 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h @@ -2,6 +2,7 @@ #include "Map.h" #include #include "Enums.h" +#include "ServiceManagementService.h" class Service; class ComboPackage; @@ -14,6 +15,8 @@ class Notification; class Controller { +private: + ServiceManagementService m_serviceManagementService; public: bool login(const std::string& username, const std::string& password); void logout(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 156c12b..084d81b 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -1 +1,21 @@ #include "ServiceManagementService.h" +#include "Service.h" +#include "Enums.h" + +util::Map ServiceManagementService::getServices() +{ + return m_dataStore.getServices(); +} + +void ServiceManagementService::removeService(const std::string& serviceID) +{ + util::Map currentServices = getServices(); + if (currentServices.find(serviceID) != -1) + { + currentServices.getValueAt(currentServices.find(serviceID))->setState(util::State::INACTIVE); + } + else + { + throw std::runtime_error("Service not found."); + } +} \ 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..5567e49 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -1,4 +1,6 @@ +#include #include "AdminMenu.h" +#include "Service.h" #include "InputHelper.h" #include "OutputHelper.h" @@ -64,8 +66,66 @@ void AdminMenu::createService() { } +static std::string selectServicesToRemove(util::Map currentServices) +{ + util::Map currentServicesMap; + bool hasServices = false; + int currentIndex = 1, choice; + std::cout << std::left + << std::setw(6) << "Index" + << std::setw(12) << "Service ID" + << std::setw(20) << "Name" + << std::setw(10) << "Labor Cost" + << std::endl; + for (int iterator = 0; iterator < currentServices.getSize(); iterator++) + { + const Service* currentService = currentServices.getValueAt(iterator); + if (currentService->getState() == util::State::INACTIVE) + { + continue; + } + std::cout << std::left + << std::setw(6) << currentIndex + << std::setw(12) << currentService->getId() + << std::setw(20) << currentService->getName() + << std::setw(10) << currentService->getLaborCost() + << std::endl; + hasServices = true; + currentServicesMap.insert(currentIndex++, currentService); + } + if (!hasServices) + { + std::cout << "No services currently available." << std::endl; + return ""; + } + std::cout << "Enter your choice: "; + util::read(choice); + if (currentServicesMap.find(choice) != -1) + { + return currentServicesMap.getValueAt(currentServicesMap.find(choice))->getId(); + } + else + { + std::cout << "Invalid choice." << std::endl; + return ""; + } +} + 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."; + } } void AdminMenu::addTechnician() From fc7bb2569b9bdaa84473d4a1cb1e8e68c802f989 Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Tue, 19 May 2026 22:54:55 +0530 Subject: [PATCH 4/5] Implement View Service History SER004: View Service History 1. Added integration between Controller and ServiceManagementService to fetch service bookings by customer ID. 2. Enhanced ServiceBooking model to store technician as a User* instead of a string for richer details. 3. Implemented Controller::getServiceBookingsByUser to return a read-only map of bookings for safe access. 4. Updated CustomerMenu::viewServiceHistory to display bookings in tabular format with aligned columns. 5. Added condition check to show technician name if assigned, otherwise display "Not Assigned". 6. Included booking status and discount percentage in the service history output. Acceptance Criteria: 1. System should fetch real-time status. 2. Status should update automatically when technician changes it. 3. Customer should be able to view history. Precondition: 1. Customer is logged into the console application. 2. At least one active service booking exists for the customer. 3. Technician has permission to update booking status. Steps: 1. Navigate to Customer menu and choose "View Service History". - Verify that the console displays current booking status along with technician assignment. 2. Technician updates the status of a booking. - Verify that the console view reflects the updated status automatically. 3. Customer views service history again. - Verify that the history shows the latest status changes. Sreeja Reghukumar, please review --- .../controllers/Controller.cpp | 9 +++- .../controllers/Controller.h | 3 ++ .../models/ServiceBooking.cpp | 6 +-- .../models/ServiceBooking.h | 8 ++-- .../services/ServiceManagementService.cpp | 24 +++++++++++ .../views/CustomerMenu.cpp | 42 +++++++++++++++++++ 6 files changed, 84 insertions(+), 8 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index d536e8a..e711591 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 "ServiceBooking.h" bool Controller::login(const std::string& username, const std::string& password) { @@ -73,7 +74,13 @@ util::Map Controller::getServiceBookings() util::Map Controller::getServiceBookingsByUser(const std::string userID) { - return util::Map(); + util::Map readOnlyServiceBookingsByUserMap; + util::Map currentServiceBookingsByUser = m_serviceManagementService.getServiceBookings(userID); + for (int iterator = 0; iterator < currentServiceBookingsByUser.getSize(); iterator++) + { + readOnlyServiceBookingsByUserMap.insert(currentServiceBookingsByUser.getValueAt(iterator)->getId(), currentServiceBookingsByUser.getValueAt(iterator)); + } + return readOnlyServiceBookingsByUserMap; } util::Map Controller::getUsers() diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 3aabb58..8512598 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h @@ -2,6 +2,7 @@ #include "Map.h" #include #include "Enums.h" +#include "ServiceManagementService.h" class Service; class ComboPackage; @@ -14,6 +15,8 @@ class Notification; class Controller { +private: + ServiceManagementService m_serviceManagementService; public: bool login(const std::string& username, const std::string& password); void logout(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp index 1fdfaf0..aeb7f4d 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, + const 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 +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(const 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..79d909f 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; + const 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, + const 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; + 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(const User*); 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..cfc28c5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -1 +1,25 @@ #include "ServiceManagementService.h" +#include "ServiceBooking.h" + +util::Map ServiceManagementService::getServiceBookings() +{ + return m_dataStore.getServiceBookings(); +} + +util::Map ServiceManagementService::getServiceBookings(const std::string& customerID) +{ + util::Map currentServiceBookings = getServiceBookings(); + util::Map currentUserServiceBookings; + if (currentServiceBookings.getSize() != 0) + { + for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++) + { + auto currentServiceBooking = currentServiceBookings.getValueAt(iterator); + if (currentServiceBooking->getCustomerId() == customerID) + { + currentUserServiceBookings.insert(currentServiceBooking->getId(), currentServiceBooking); + } + } + } + return currentUserServiceBookings; +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index 047f471..f2444b1 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -1,6 +1,10 @@ +#include #include "CustomerMenu.h" #include "InputHelper.h" #include "OutputHelper.h" +#include "User.h" +#include "ServiceBooking.h" +#include "Enums.h" void CustomerMenu::showMenu() { @@ -53,6 +57,44 @@ void CustomerMenu::selectComboPackage() void CustomerMenu::viewServiceHistory() { + util::clear(); + bool hasServiceHistory = false; + const User* currentUser = m_controller.getAuthenticatedUser(); + std::string currentUserID = currentUser->getId(); + util::Map serviceBookingsByCurrentUser = m_controller.getServiceBookingsByUser(currentUserID); + if (serviceBookingsByCurrentUser.getSize() != 0) + { + std::cout << std::left + << std::setw(12) << "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::endl; + for (int iterator = 0; iterator < serviceBookingsByCurrentUser.getSize(); iterator++) + { + const ServiceBooking* currentBooking = serviceBookingsByCurrentUser.getValueAt(iterator); + std::string technicianName = currentBooking->getAssignedTechnician() == nullptr + ? "Not Assigned" + : currentBooking->getAssignedTechnician()->getName(); + std::cout << std::left + << std::setw(12) << 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::endl; + hasServiceHistory = true; + } + } + if (!hasServiceHistory) + { + std::cout << "No history available." << std::endl; + } } void CustomerMenu::completePayments() From 8162a2fe3d5a9f76a6fa9de14fc6964d0c17bf8d Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Wed, 20 May 2026 12:05:39 +0530 Subject: [PATCH 5/5] Implement Update Service Status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SER005: Update Service Status 1. Integrated Controller with ServiceManagementService to support job completion workflow. 2. Implemented ServiceManagementService::completeJob with validation for technician assignment, job existence, and status transition. 3. Enhanced TechnicianMenu with job selection helper to display assigned jobs, allow index-based selection, and handle invalid choices. 4. Updated TechnicianMenu::completeJob to mark job as completed via Controller and provide user feedback. 5. Added logic to check if all jobs in a booking are completed, triggering invoice generation and customer notification. Acceptance Criteria: 1. Status updates are visible to customers immediately after technician marks job as completed. Precondition: 1. Technician is logged into the system. 2. At least one active job card is assigned to the technician. 3. Datastore contains valid service bookings linked to jobs. Steps: 1. Navigate to Technician menu and choose "Complete Job". - Verify that the system lists active jobs with index-based selection. 2. Select a job card by index. - Verify that the job status changes from STARTED to COMPLETED. 3. Check customer view. - Verify that the updated status is reflected in the customer’s booking history. 4. If all jobs in the booking are completed: - Verify that an invoice is generated and a notification is sent to the customer. Sreeja Reghukumar, please review --- .../controllers/Controller.cpp | 12 ++- .../controllers/Controller.h | 3 + .../models/JobCard.cpp | 8 +- .../models/JobCard.h | 11 ++- .../services/ServiceManagementService.cpp | 88 +++++++++++++++++++ .../views/TechnicianMenu.cpp | 64 ++++++++++++++ 6 files changed, 175 insertions(+), 11 deletions(-) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index d536e8a..0465e4b 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 "JobCard.h" bool Controller::login(const std::string& username, const std::string& password) { @@ -100,11 +101,20 @@ void Controller::removeService(const std::string& serviceID) util::Map Controller::getJobCardsByUser() { - return util::Map(); + const User* currentUser = getAuthenticatedUser(); + auto jobCardsAssignedToTechnician = m_serviceManagementService.getJobCards(currentUser->getId()); + util::Map readOnlyJobCardMap; + for (int iterator = 0; iterator < jobCardsAssignedToTechnician.getSize(); iterator++) + { + JobCard* currentJobCard = jobCardsAssignedToTechnician.getValueAt(iterator); + readOnlyJobCardMap.insert(currentJobCard->getId(), currentJobCard); + } + return readOnlyJobCardMap; } void Controller::completeJob(const std::string& jobID) { + m_serviceManagementService.completeJob(jobID); } void Controller::removeUser(const std::string& userID) diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 3aabb58..8512598 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h @@ -2,6 +2,7 @@ #include "Map.h" #include #include "Enums.h" +#include "ServiceManagementService.h" class Service; class ComboPackage; @@ -14,6 +15,8 @@ class Notification; class Controller { +private: + 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..9bd78aa 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,7 +19,7 @@ private: std::string m_technicianId; User* m_technician; util::Timestamp m_assignedDate; - ServiceJobStatus m_status; + util::ServiceJobStatus m_status; util::Timestamp m_completionDate; public: @@ -32,7 +31,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 +42,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 +52,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/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 156c12b..dfa4d3b 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -1 +1,89 @@ #include "ServiceManagementService.h" +#include "AuthenticationManagementService.h" +#include "PaymentManagementService.h" +#include "NotificationManagementService.h" +#include "JobCard.h" +#include "User.h" +#include "Enums.h" +#include "ServiceBooking.h" +#include "Service.h" + +util::Map ServiceManagementService::getJobCards(const std::string& technicianID) +{ + util::Map jobCards = m_dataStore.getJobCards(); + util::Map technicianJobCards; + for (int iterator = 0; iterator < jobCards.getSize();iterator++) + { + JobCard* currentJobCard = jobCards.getValueAt(iterator); + if (currentJobCard->getTechnicianId() == technicianID) + { + technicianJobCards.insert(currentJobCard->getId(), currentJobCard); + } + } + return technicianJobCards; +} + +static bool hasAllJobCardsinServiceBookingCompleted(std::string bookingId, util::Map& currentAssignedJobs) +{ + for (int iterator = 0; iterator < currentAssignedJobs.getSize(); iterator++) + { + JobCard* currentJob = currentAssignedJobs.getValueAt(iterator); + if (currentJob->getBookingId() == bookingId) + { + if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) + { + return false; + } + } + } + return true; +} + +void ServiceManagementService::completeJob(const std::string& jobID) +{ + AuthenticationManagementService authenticationManagementService; + PaymentManagementService paymentManagementService; + bool jobStatusUpdated = false, serviceBookingCompleted; + JobCard* currentJob; + User* currentTechnician = authenticationManagementService.getAuthenticatedUser(); + if (currentTechnician == nullptr) + { + throw std::runtime_error("Unable to fetch current technician."); + } + util::Map currentAssignedJobs = getJobCards(currentTechnician->getId()); + if (currentAssignedJobs.getSize() == 0) + { + throw std::runtime_error("No job cards assigned to the technician."); + } + if(currentAssignedJobs.find(jobID) != -1) + { + currentJob = currentAssignedJobs.getValueAt(currentAssignedJobs.find(jobID)); + if (currentJob == nullptr) + { + throw std::runtime_error("Unable to fetch current job."); + } + if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) + { + currentJob->setStatus(util::ServiceJobStatus::COMPLETED); + jobStatusUpdated = true; + } + } + else + { + throw std::runtime_error("Failed to complete the job, some error occured or job already completed."); + } + if (!jobStatusUpdated) + { + throw std::runtime_error("Failed to complete the job, some error occured or job already completed."); + } + + serviceBookingCompleted = hasAllJobCardsinServiceBookingCompleted(currentJob->getBookingId(), currentAssignedJobs); + if (serviceBookingCompleted) + { + currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED); + paymentManagementService.generateInvoice(currentJob->getBooking()); + std::string title = "Service Booking completed,Invoice Generated.\n"; + std::string message = "Services completed for the booking and invoice generated.\n"; + sendNotification(currentJob->getBooking()->getCustomer(), title, message); + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp index d6c4d57..2b94fe3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp @@ -1,6 +1,10 @@ +#include #include "TechnicianMenu.h" #include "InputHelper.h" #include "OutputHelper.h" +#include "JobCard.h" +#include "Enums.h" +#include "Service.h" void TechnicianMenu::showMenu() { @@ -31,8 +35,68 @@ bool TechnicianMenu::handleOperation(int choice) return false; } +static std::string selectJobCardToComplete(util::Map& assignedJobCards, util::Map& incompleteJobCards) +{ + int currentIndex = 1; + int choice; + bool hasIncompleteJobCard = false; + std::cout << std::left + << std::setw(6) << "Index" + << std::setw(12) << "BookingID" + << std::setw(12) << "JobID" + << std::setw(20) << "ServiceName" + << std::setw(12) << "ServiceID" + << std::endl; + for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++) + { + const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator); + if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED)) + { + std::cout << std::left << std::setw(6) << currentIndex + << std::setw(12) << currentJobCard->getBookingId() + << std::setw(12) << currentJobCard->getId() + << std::setw(20) << currentJobCard->getService()->getName() + << std::setw(12) << currentJobCard->getServiceId() + << std::endl; + hasIncompleteJobCard = true; + incompleteJobCards.insert(currentIndex++, currentJobCard); + } + } + if (!hasIncompleteJobCard) + { + std::cout << "No pending jobs are present.\n"; + return ""; + } + std::cout << "Select the Job Card to complete (Index): "; + util::read(choice); + int selectedJobCardIndex = incompleteJobCards.find(choice); + if (selectedJobCardIndex != -1) + { + const JobCard* selectedJobCard = incompleteJobCards.getValueAt(selectedJobCardIndex); + return selectedJobCard->getId(); + } + else + { + std::cout << "Invalid choice.\n"; + return ""; + } +} + void TechnicianMenu::completeJob() { + util::Map assignedJobCards = m_controller.getJobCardsByUser(); + util::Map incompleteJobCards; + std::cout << "Jobs to be completed.\n"; + std::string selectedJobID = selectJobCardToComplete(assignedJobCards, incompleteJobCards); + if (selectedJobID == "") + { + std::cout << "Failed to complete the job.\n"; + } + else + { + m_controller.completeJob(selectedJobID); + std::cout << "Job marked as completed.\n"; + } } void TechnicianMenu::viewNotifications()