Implement Update Service Status
<UserStory> SER005: Update Service Status </UserStory>
<Changes>
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.
</Changes>
<Test>
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.
</Test>
<Review>
Sreeja Reghukumar, please review
</Review>
This commit is contained in:
+11
-1
@@ -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<std::string, const JobCard*> Controller::getJobCardsByUser()
|
||||
{
|
||||
return util::Map<std::string, const JobCard*>();
|
||||
const User* currentUser = getAuthenticatedUser();
|
||||
auto jobCardsAssignedToTechnician = m_serviceManagementService.getJobCards(currentUser->getId());
|
||||
util::Map<std::string, const JobCard*> 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)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Map.h"
|
||||
#include <string>
|
||||
#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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#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);
|
||||
};
|
||||
+88
@@ -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<std::string, JobCard*> ServiceManagementService::getJobCards(const std::string& technicianID)
|
||||
{
|
||||
util::Map<std::string, JobCard*> jobCards = m_dataStore.getJobCards();
|
||||
util::Map<std::string, JobCard*> 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<std::string, JobCard*>& 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<std::string, JobCard*> 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);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
#include <iomanip>
|
||||
#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<std::string, const JobCard*>& assignedJobCards, util::Map<int, const JobCard*>& 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<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
|
||||
util::Map<int, const JobCard*> 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()
|
||||
|
||||
Reference in New Issue
Block a user