Compare commits

..

1 Commits

Author SHA1 Message Date
joelthomastrenser 972e353832 Merged PR 1152: Vehicle Service System v1.0.0.0
Features Included:

Secure access and session management with role-based authentication
Customer and technician account management
Service booking and technician assignment
Service and combo package management
Job card tracking and completion workflow
Inventory management and stock monitoring
Invoice generation and payment processing
Notification management with configurable preferences
Observer pattern based alerts for inventory, payments, and service updates
2026-06-01 16:48:25 +05:30
9 changed files with 41 additions and 120 deletions
@@ -392,9 +392,9 @@ Parameters:
Returns: Returns:
- void - void
*/ */
void Controller::updateJobStatus(const std::string& jobID) void Controller::completeJob(const std::string& jobID)
{ {
m_serviceManagementService.updateJobStatus(jobID); m_serviceManagementService.completeJob(jobID);
} }
/* /*
@@ -59,7 +59,7 @@ public:
void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost); void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID); void removeService(const std::string& serviceID);
util::Map<std::string, const JobCard*> getJobCardsByUser(); util::Map<std::string, const JobCard*> getJobCardsByUser();
void updateJobStatus(const std::string& jobID); void completeJob(const std::string& jobID);
void removeUser(const std::string& userID); void removeUser(const std::string& userID);
void createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage); void createComboPackage(const std::string& name, const util::Vector<std::string>& serviceIDs, double discountPercentage);
void removeComboPackage(const std::string& comboPackageID); void removeComboPackage(const std::string& comboPackageID);
@@ -1080,7 +1080,7 @@ static bool hasCompletedAllJobs(std::string bookingId, util::Map<std::string, Jo
JobCard* currentJob = currentAssignedJobs.getValueAt(iterator); JobCard* currentJob = currentAssignedJobs.getValueAt(iterator);
if (currentJob->getBookingId() == bookingId) if (currentJob->getBookingId() == bookingId)
{ {
if (currentJob->getStatus() == util::ServiceJobStatus::STARTED || currentJob->getStatus() == util::ServiceJobStatus::INPROGRESS) if (currentJob->getStatus() == util::ServiceJobStatus::STARTED)
{ {
return false; return false;
} }
@@ -1101,7 +1101,7 @@ Returns:
Throws: Throws:
- std::runtime_error if technician is not authenticated, job card not found, or job already completed - std::runtime_error if technician is not authenticated, job card not found, or job already completed
*/ */
void ServiceManagementService::updateJobStatus(const std::string& jobID) void ServiceManagementService::completeJob(const std::string& jobID)
{ {
AuthenticationManagementService authenticationManagementService; AuthenticationManagementService authenticationManagementService;
PaymentManagementService paymentManagementService; PaymentManagementService paymentManagementService;
@@ -1126,32 +1126,26 @@ void ServiceManagementService::updateJobStatus(const std::string& jobID)
} }
if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) if (currentJob->getStatus() == util::ServiceJobStatus::STARTED)
{ {
currentJob->setStatus(util::ServiceJobStatus::INPROGRESS); currentJob->setStatus(util::ServiceJobStatus::COMPLETED);
jobStatusUpdated = true; jobStatusUpdated = true;
} }
else if (currentJob->getStatus() == util::ServiceJobStatus::INPROGRESS)
{
currentJob->setStatus(util::ServiceJobStatus::COMPLETED);
jobStatusUpdated = true;
serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs);
if (serviceBookingCompleted)
{
currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED);
paymentManagementService.generateInvoice(currentJob->getBooking());
std::string title = "Service Booking completed. Invoice Generated.";
std::string message = "Services completed for the booking and invoice generated.";
sendNotification(currentJob->getBooking()->getCustomer(), title, message);
}
}
} }
else else
{ {
throw std::runtime_error("Failed to update the job."); throw std::runtime_error("Failed to complete the job, some error occurred or job already completed.");
} }
if (!jobStatusUpdated) if (!jobStatusUpdated)
{ {
throw std::runtime_error("Failed to update the job"); throw std::runtime_error("Failed to complete the job, some error occurred or job already completed.");
} }
serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs);
if (serviceBookingCompleted)
{
currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED);
paymentManagementService.generateInvoice(currentJob->getBooking());
std::string title = "Service Booking completed. Invoice Generated.";
std::string message = "Services completed for the booking and invoice generated.";
sendNotification(currentJob->getBooking()->getCustomer(), title, message);
}
} }
@@ -37,7 +37,7 @@ public:
void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost); void createService(const std::string& name, const util::Vector<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID); void removeService(const std::string& serviceID);
util::Map<std::string, JobCard*> getJobCards(const std::string& technicianID); util::Map<std::string, JobCard*> getJobCards(const std::string& technicianID);
void updateJobStatus(const std::string& jobID); void completeJob(const std::string& jobID);
void cancelCustomerServiceBookings(const std::string& customerID); void cancelCustomerServiceBookings(const std::string& customerID);
void cancelTechnicianJobs(const std::string& technicianID); void cancelTechnicianJobs(const std::string& technicianID);
void createComboPackage(const std::string& packageName, const util::Vector<std::string>& serviceIDs, double discountPercentage); void createComboPackage(const std::string& packageName, const util::Vector<std::string>& serviceIDs, double discountPercentage);
@@ -37,7 +37,6 @@ namespace util
PENDING, PENDING,
STARTED, STARTED,
COMPLETED, COMPLETED,
INPROGRESS,
CANCELLED CANCELLED
}; };
@@ -210,8 +209,6 @@ namespace util
return "COMPLETED"; return "COMPLETED";
case ServiceJobStatus::CANCELLED: case ServiceJobStatus::CANCELLED:
return "CANCELLED"; return "CANCELLED";
case ServiceJobStatus::INPROGRESS:
return "INPROGRESS";
} }
throw std::invalid_argument("Invalid ServiceJobStatus"); throw std::invalid_argument("Invalid ServiceJobStatus");
} }
@@ -244,10 +241,6 @@ namespace util
{ {
return ServiceJobStatus::CANCELLED; return ServiceJobStatus::CANCELLED;
} }
if (value == "INPROGRESS")
{
return ServiceJobStatus::INPROGRESS;
}
throw std::invalid_argument("Invalid ServiceJobStatus string"); throw std::invalid_argument("Invalid ServiceJobStatus string");
} }
@@ -646,37 +646,7 @@ inline util::Map<std::string, const JobCard*> filterStartedJobCards(util::Map<st
for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++) for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++)
{ {
const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator); const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator);
if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED || currentJobCard->getStatus() == util::ServiceJobStatus::INPROGRESS)) if (currentJobCard && currentJobCard->getStatus() == util::ServiceJobStatus::STARTED)
{
startedJobCards.insert(currentJobCard->getId(), currentJobCard);
}
}
return startedJobCards;
}
/*
Function: filterJobCards
Description:
Filters the given list of job cards and returns only those
whose status matches the specified ServiceJobStatus.
Parameters:
- assignedJobCards: util::Map<std::string, const JobCard*>&
Map of job card IDs to JobCard pointers assigned to the technician.
- selectedJobStatus: util::ServiceJobStatus
The status type to filter job cards by.
Returns:
- util::Map<std::string, const JobCard*>
A map containing only job cards with the specified status.
*/
inline util::Map<std::string, const JobCard*> filterJobCards(util::Map<std::string, const JobCard*>& assignedJobCards, util::ServiceJobStatus selectedJobStatus)
{
util::Map<std::string, const JobCard*> startedJobCards;
for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++)
{
const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator);
if (currentJobCard && currentJobCard->getStatus() == selectedJobStatus)
{ {
startedJobCards.insert(currentJobCard->getId(), currentJobCard); startedJobCards.insert(currentJobCard->getId(), currentJobCard);
} }
@@ -705,18 +675,16 @@ inline void displayAllJobs(util::Map<std::string, const JobCard*>& assignedJobCa
<< std::setw(12) << "JobID" << std::setw(12) << "JobID"
<< std::setw(20) << "ServiceName" << std::setw(20) << "ServiceName"
<< std::setw(12) << "ServiceID" << std::setw(12) << "ServiceID"
<< std::setw(12) << "Status"
<< std::endl; << std::endl;
for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++) for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++)
{ {
const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator); const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator);
if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED || currentJobCard->getStatus() == util::ServiceJobStatus::INPROGRESS)) if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED))
{ {
std::cout << std::left << std::setw(12) << currentJobCard->getBookingId() std::cout << std::left << std::setw(12) << currentJobCard->getBookingId()
<< std::setw(12) << currentJobCard->getId() << std::setw(12) << currentJobCard->getId()
<< std::setw(20) << util::truncateString(currentJobCard->getService()->getName(), 15) << std::setw(20) << currentJobCard->getService()->getName()
<< std::setw(12) << currentJobCard->getServiceId() << std::setw(12) << currentJobCard->getServiceId()
<< std::setw(12) << util::getServiceJobStatusString(currentJobCard->getStatus())
<< std::endl; << std::endl;
} }
} }
@@ -730,31 +698,16 @@ Parameters:
Returns: Returns:
- std::string: ID of the selected job card, or empty string if none selected - std::string: ID of the selected job card, or empty string if none selected
*/ */
inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>& assignedJobCards, util::ServiceJobStatus selectedJobStatusType) inline std::string selectJobCardToComplete(util::Map<std::string, const JobCard*>& assignedJobCards)
{ {
util::Map<int, const JobCard* > incompleteJobCards; util::Map<int, const JobCard* > incompleteJobCards;
if (assignedJobCards.getSize() == 0) if (assignedJobCards.getSize() == 0)
{ {
std::cout << "No jobs available.\n\n"; std::cout << "No started jobs available to complete.\n";
return ""; return "";
} }
int currentIndex = 1; int currentIndex = 1;
int choice; int choice;
if (selectedJobStatusType == util::ServiceJobStatus::STARTED)
{
util::clear();
std::cout << "Select a job to update to Inprogress\n";
}
else if (selectedJobStatusType == util::ServiceJobStatus::INPROGRESS)
{
util::clear();
std::cout << "Select a job to update to Completed\n";
}
else
{
std::cout << "Unable to update completed or pending jobs.\n\n";
return "";
}
std::cout << std::endl; std::cout << std::endl;
std::cout << std::left std::cout << std::left
<< std::setw(6) << "Index" << std::setw(6) << "Index"
@@ -762,24 +715,22 @@ inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>&
<< std::setw(12) << "JobID" << std::setw(12) << "JobID"
<< std::setw(20) << "ServiceName" << std::setw(20) << "ServiceName"
<< std::setw(12) << "ServiceID" << std::setw(12) << "ServiceID"
<< std::setw(12) << "JobStatus"
<< std::endl; << std::endl;
for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++) for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++)
{ {
const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator); const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator);
if (currentJobCard && (currentJobCard->getStatus() == selectedJobStatusType)) if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED))
{ {
std::cout << std::left << std::setw(6) << currentIndex std::cout << std::left << std::setw(6) << currentIndex
<< std::setw(12) << currentJobCard->getBookingId() << std::setw(12) << currentJobCard->getBookingId()
<< std::setw(12) << currentJobCard->getId() << std::setw(12) << currentJobCard->getId()
<< std::setw(20) << util::truncateString(currentJobCard->getService()->getName(), 15) << std::setw(20) << currentJobCard->getService()->getName()
<< std::setw(12) << currentJobCard->getServiceId() << std::setw(12) << currentJobCard->getServiceId()
<< std::setw(12) << util::getServiceJobStatusString(currentJobCard->getStatus())
<< std::endl; << std::endl;
incompleteJobCards.insert(currentIndex++, currentJobCard); incompleteJobCards.insert(currentIndex++, currentJobCard);
} }
} }
std::cout << "Select the Job Card to Update (Index): "; std::cout << "Select the Job Card to complete (Index): ";
util::read(choice); util::read(choice);
int selectedJobCardIndex = incompleteJobCards.find(choice); int selectedJobCardIndex = incompleteJobCards.find(choice);
if (selectedJobCardIndex != -1) if (selectedJobCardIndex != -1)
@@ -790,7 +741,7 @@ inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>&
else else
{ {
std::cout << "Invalid index.\n"; std::cout << "Invalid index.\n";
std::cout << "Failed to update job.\n\n"; std::cout << "Failed to complete jobs.\n\n";
return ""; return "";
} }
} }
@@ -35,7 +35,7 @@ void TechnicianMenu::showMenu()
util::clear(); util::clear();
std::cout << "Technician Menu" std::cout << "Technician Menu"
<< "\n1. Display My Jobs" << "\n1. Display My Jobs"
<< "\n2. Update Job Status" << "\n2. Mark Job as Completed"
<< "\n3. View Notifications" << "\n3. View Notifications"
<< "\n4. Change Password" << "\n4. Change Password"
<< "\n5. Logout" << "\n5. Logout"
@@ -68,7 +68,7 @@ bool TechnicianMenu::handleOperation(int choice)
displayJobs(); displayJobs();
break; break;
case 2: case 2:
updateJobStatus(); completeJob();
break; break;
case 3: case 3:
viewNotifications(); viewNotifications();
@@ -99,48 +99,31 @@ void TechnicianMenu::displayJobs()
util::clear(); util::clear();
std::cout << "My Jobs\n"; std::cout << "My Jobs\n";
util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser(); util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
util::Map<std::string, const JobCard*> jobCards = filterStartedJobCards(assignedJobCards); util::Map<std::string, const JobCard*> startedJobCards = filterStartedJobCards(assignedJobCards);
displayAllJobs(jobCards); displayAllJobs(startedJobCards);
util::pressEnter(); util::pressEnter();
} }
/* /*
Function: updateJobStatus Function: completeJob
Description: Allows the technician to update a selected job card. Description: Allows the technician to mark a selected job card as completed.
Validates selection and updates job status through the controller. Validates selection and updates job status through the controller.
Parameters: Parameters:
- None - None
Returns: Returns:
- void - void
*/ */
void TechnicianMenu::updateJobStatus() void TechnicianMenu::completeJob()
{ {
util::clear(); util::clear();
std::cout << "Update Job Status\n"; std::cout << "Complete Job\n";
int choice;
std::string selectedJobID;
util::ServiceJobStatus selectedJobStatus;
util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser(); util::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
std::cout << "Select the type of job you want to update\n1.Started\n2.Inprogress\nChoice: "; util::Map<std::string, const JobCard*> startedJobCards = filterStartedJobCards(assignedJobCards);
util::read(choice); std::string selectedJobID = selectJobCardToComplete(startedJobCards);
if (choice == 1)
{
selectedJobStatus = util::ServiceJobStatus::STARTED;
}
else if (choice == 2)
{
selectedJobStatus = util::ServiceJobStatus::INPROGRESS;
}
else
{
throw std::runtime_error("Invalid Index");
}
util::Map<std::string, const JobCard*> selectedTypeJobCard = filterJobCards(assignedJobCards, selectedJobStatus);
selectedJobID = selectJobCardToUpdate(selectedTypeJobCard, selectedJobStatus);
if (!selectedJobID.empty()) if (!selectedJobID.empty())
{ {
m_controller.updateJobStatus(selectedJobID); m_controller.completeJob(selectedJobID);
std::cout << "\nJob status updated.\n\n"; std::cout << "\nJob marked as completed.\n\n";
} }
util::pressEnter(); util::pressEnter();
} }
@@ -18,7 +18,7 @@ private:
public: public:
void showMenu(); void showMenu();
void displayJobs(); void displayJobs();
void updateJobStatus(); void completeJob();
void viewNotifications(); void viewNotifications();
void logout(); void logout();
void changePassword(); void changePassword();