From 8162a2fe3d5a9f76a6fa9de14fc6964d0c17bf8d Mon Sep 17 00:00:00 2001 From: Jissin Mathew Date: Wed, 20 May 2026 12:05:39 +0530 Subject: [PATCH] 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()