Compare commits

..

1 Commits

Author SHA1 Message Date
Avinash Rajesh 931aa4c406 Implement Confirm Payment Functionality
<User Story> Complete Payments - 1797</User Story>

<Changes>
1. Added Controller::getAllInvoices
   - Retrieves all invoices from PaymentManagementService and returns them as a read-only map.
2. Implemented Controller::confirmPayment
   - Delegates payment confirmation for a given invoice ID to PaymentManagementService.
3. Introduced PaymentManagementService::getAllInvoice
   - Provides access to all invoices stored in the datastore.
4. Added PaymentManagementService::confirmPayment
   - Confirms payment for a specific invoice, updates payment date and status, and sends notification.
5. Extended util::PaymentStatus enum
   - Added PAID status and updated string conversion.
6. Integrated AdminMenu::confirmPayment
   - Validates invoice list, filters by status, allows selection, and confirms payment.
7. Updated CustomerMenu::completePayments
   - Uses parameterized status filtering for invoice selection.
8. Enhanced MenuHelper::selectInvoiceFromUserForPayment
   - Accepts requiredStatus parameter for flexible filtering.
9. Adjusted AdminMenu options
   - Added "Confirm Payment" before Logout.
</Changes>

<Test>
Acceptance Criteria:
1. Admin selects "Confirm Payment" from menu.
   - Verify system prompts and displays invoices filtered by status.
2. Admin selects invoice with status = PAID.
   - Verify payment confirmation updates date, sets status, and sends notification.
3. Admin attempts confirmation with empty invoice list.
   - Verify error message: "No pending invoices available for confirmation."
4. Customer completes payment.
   - Verify selection uses util::PaymentStatus::PENDING and payment flow works correctly.
5. Invalid invoice ID entered.
   - Verify system throws runtime_error with "Payment failed: invalid invoice ID."

Precondition:
1. Admin logged into system.
2. At least one invoice exists in datastore.
3. Notification system available.

Steps:
1. Navigate to Admin menu → Confirm Payment.
2. Select invoice with PAID status.
3. Confirm payment and check notification.
4. Attempt with empty invoice list.
5. Attempt with invalid invoice ID.
</Test>

<Review>
Sreeja Reghukumar
</Review>
2026-05-29 13:24:34 +05:30
12 changed files with 127 additions and 202 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);
} }
/* /*
@@ -472,7 +472,7 @@ Returns:
*/ */
util::Map<std::string, const Invoice*> Controller::getAllInvoices() util::Map<std::string, const Invoice*> Controller::getAllInvoices()
{ {
auto invoices = m_paymentManagementService.getAllInvoices(); auto invoices = m_paymentManagementService.getAllInvoice();
util::Map<std::string, const Invoice*> readOnlyInvoice; util::Map<std::string, const Invoice*> readOnlyInvoice;
for (int iterator = 0; iterator < invoices.getSize(); iterator++) for (int iterator = 0; iterator < invoices.getSize(); iterator++)
{ {
@@ -489,7 +489,7 @@ Parameters:
Returns: Returns:
- void - void
*/ */
void Controller::confirmPayment(const std::string& invoiceID) void Controller::confirmPayment(std::string invoiceID)
{ {
m_paymentManagementService.confirmPayment(invoiceID); m_paymentManagementService.confirmPayment(invoiceID);
} }
@@ -59,13 +59,13 @@ 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);
util::Map<std::string, const Invoice*> getInvoicesByUser(); util::Map<std::string, const Invoice*> getInvoicesByUser();
util::Map<std::string, const Invoice*> getAllInvoices(); util::Map<std::string, const Invoice*> getAllInvoices();
void confirmPayment(const std::string& invoiceID); void confirmPayment(std::string invoiceID);
void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode); void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode);
util::Vector<const Notification*> getNotifications(); util::Vector<const Notification*> getNotifications();
void deleteNotification(const std::string& notificationID); void deleteNotification(const std::string& notificationID);
@@ -394,7 +394,7 @@ Parameters:
Returns: Returns:
- util::Map<std::string, Invoice*>&: Map of invoice IDs to invoice objects - util::Map<std::string, Invoice*>&: Map of invoice IDs to invoice objects
*/ */
util::Map<std::string, Invoice*>& PaymentManagementService::getAllInvoices() util::Map<std::string, Invoice*>& PaymentManagementService::getAllInvoice()
{ {
return m_dataStore.getInvoices(); return m_dataStore.getInvoices();
} }
@@ -410,22 +410,26 @@ Returns:
Throws: Throws:
- std::runtime_error if the invoice ID is invalid - std::runtime_error if the invoice ID is invalid
*/ */
void PaymentManagementService::confirmPayment(const std::string& invoiceID) void PaymentManagementService::confirmPayment(std::string invoiceID)
{ {
std::string title, message;
auto& currentInvoices = m_dataStore.getInvoices(); auto& currentInvoices = m_dataStore.getInvoices();
int invoiceIndex = currentInvoices.find(invoiceID); int invoiceIndex = currentInvoices.find(invoiceID);
if (invoiceIndex == -1) if (invoiceIndex != -1)
{ {
throw std::runtime_error("Payment confirmation failed: invalid invoice ID.");
}
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex); Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
if (!invoice || invoice->getStatus() != util::PaymentStatus::PAID) if (invoice && invoice->getStatus() != util::PaymentStatus::COMPLETED)
{ {
throw std::runtime_error("Payment confirmation failed: invoice is not awaiting confirmation.");
}
User* currentUser = invoice->getBooking()->getCustomer(); User* currentUser = invoice->getBooking()->getCustomer();
invoice->setPaymentDate(util::Timestamp());
invoice->setStatus(util::PaymentStatus::COMPLETED); invoice->setStatus(util::PaymentStatus::COMPLETED);
std::string title = "Payment Confirmed"; title = "Payment Confirmed";
std::string message = "Payment Confirmed for Invoice ID " + invoiceID; message = "Payment Confirmed for Invoice ID " + invoiceID;
sendNotification(currentUser, title, message); sendNotification(currentUser, title, message);
}
}
else
{
throw std::runtime_error("Payment failed: invalid invoice ID.");
}
} }
@@ -28,8 +28,8 @@ public:
void generateInvoice(ServiceBooking* booking); void generateInvoice(ServiceBooking* booking);
util::Map<std::string, Invoice*> getInvoices(const std::string& customerID); util::Map<std::string, Invoice*> getInvoices(const std::string& customerID);
void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode); void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode);
util::Map<std::string, Invoice*>& getAllInvoices(); util::Map<std::string, Invoice*>& getAllInvoice();
void confirmPayment(const std::string& invoiceID); void confirmPayment(std::string invoiceID);
void sendPaymentReminders(); void sendPaymentReminders();
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
@@ -543,65 +543,50 @@ static void restoreInventory(ServiceBooking* booking)
/* /*
Function: processBookingCancellation Function: processBookingCancellation
Description: Handles cancellation or reassignment of a service booking based on user type. Description: Cancels jobs and updates the status of a given booking. Sends notifications to the
Cancels associated job cards, updates booking status, clears technician assignments, specified user, resets technician assignment if needed, and restores inventory items.
restores inventory, and sends appropriate notifications. Parameter: ServiceBooking* booking - Pointer to the booking being cancelled
Parameters: util::ServiceJobStatus newServiceBookingStatus - New status to assign to the booking
ServiceBooking* booking - The booking to cancel or reset const std::string& notificationTitle - Title of the booking cancellation notification
const std::string& notificationMessage - Message body of the booking cancellation notification
User* notifyUser - User to notify about the cancellation
util::ServiceJobStatus jobCardStatus - New status to assign to associated job cards
const std::string& jobNotificationTitle - Title of the job cancellation notification
const std::string& jobNotificationMessage - Message body of the job cancellation notification
util::Map<std::string, JobCard*>& jobs - Collection of job cards to update util::Map<std::string, JobCard*>& jobs - Collection of job cards to update
ServiceManagementService& currentService - Service layer for notifications ServiceManagementService& currentService - Reference to the service for sending notifications
util::UserType userType - Type of user initiating cancellation (CUSTOMER or TECHNICIAN)
Return type: void Return type: void
*/ */
static void processBookingCancellation(ServiceBooking* booking, static void processBookingCancellation(ServiceBooking* booking,
util::Map<std::string, JobCard*>& jobs, util::ServiceJobStatus newServiceBookingStatus,
ServiceManagementService& currentService, const std::string& notificationTitle,
util::UserType userType) const std::string& notificationMessage,
User* notifyUser,
util::ServiceJobStatus jobCardStatus,
const std::string& jobNotificationTitle,
const std::string& jobNotificationMessage,
util::Map<std::string, JobCard*>& jobs, ServiceManagementService& currentService)
{ {
if (!booking) if (!booking || !notifyUser)
{ {
return; return;
} }
for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator) for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator)
{ {
JobCard* jobCard = jobs.getValueAt(jobIterator); JobCard* jobCard = jobs.getValueAt(jobIterator);
if (!jobCard || jobCard->getBookingId() != booking->getId() || jobCard->getStatus() == util::ServiceJobStatus::CANCELLED) if (jobCard && jobCard->getBookingId() == booking->getId())
{ {
continue; jobCard->setStatus(jobCardStatus);
currentService.sendNotification(notifyUser, jobNotificationTitle, jobNotificationMessage);
} }
jobCard->setStatus(util::ServiceJobStatus::CANCELLED); }
if (userType == util::UserType::CUSTOMER) booking->setStatus(newServiceBookingStatus);
currentService.sendNotification(notifyUser, notificationTitle, notificationMessage);
if (newServiceBookingStatus == util::ServiceJobStatus::PENDING)
{ {
if (User* technician = booking->getAssignedTechnician())
{
const std::string jobTitle = "Job Cancelled";
const std::string jobMessage = "Your job card has been cancelled and the inventory has been restocked.";
currentService.sendNotification(technician, jobTitle, jobMessage);
}
}
}
if (userType == util::UserType::CUSTOMER)
{
booking->setStatus(util::ServiceJobStatus::CANCELLED);
if (User* technician = booking->getAssignedTechnician())
{
const std::string title = "Customer Service Cancelled";
const std::string message = "Your assigned job card has been cancelled and the inventory has been restocked.";
currentService.sendNotification(technician, title, message);
}
}
else if (userType == util::UserType::TECHNICIAN)
{
booking->setStatus(util::ServiceJobStatus::PENDING);
if (User* customer = booking->getCustomer())
{
const std::string title = "Technician Unavailable";
const std::string message = "Your booking has been reset to pending and we will reassign a new technician shortly.";
currentService.sendNotification(customer, title, message);
}
}
booking->setAssignedTechnician(nullptr); booking->setAssignedTechnician(nullptr);
booking->setAssignedTechnicianId(""); booking->setAssignedTechnicianId("");
}
restoreInventory(booking); restoreInventory(booking);
} }
@@ -639,13 +624,21 @@ void ServiceManagementService::cancelCustomerServiceBookings(const std::string&
{ {
continue; continue;
} }
if (booking->getStatus() != util::ServiceJobStatus::PENDING && if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED)
booking->getStatus() != util::ServiceJobStatus::STARTED &&
booking->getStatus() != util::ServiceJobStatus::IN_PROGRESS)
{ {
continue; continue;
} }
processBookingCancellation(booking, jobs, *this, util::UserType::CUSTOMER); User* assignedTechnician = booking->getAssignedTechnician();
std::string titleToTechnician = "Customer Service Cancelled";
std::string messageToTechnician = "The customer has cancelled their service booking. Your assigned job card has been cancelled and the inventory has been restocked.";
std::string jobTitle = "Job Cancelled";
std::string jobMessage = "The job has been cancelled. Your job card has been cancelled and the inventory has been restocked.";
processBookingCancellation(booking,
util::ServiceJobStatus::CANCELLED,
titleToTechnician, messageToTechnician, assignedTechnician,
util::ServiceJobStatus::CANCELLED,
jobTitle, jobMessage, jobs, *this
);
} }
} }
@@ -683,9 +676,7 @@ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicia
{ {
continue; continue;
} }
if (booking->getStatus() != util::ServiceJobStatus::PENDING && if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED)
booking->getStatus() != util::ServiceJobStatus::STARTED &&
booking->getStatus() != util::ServiceJobStatus::IN_PROGRESS)
{ {
continue; continue;
} }
@@ -694,7 +685,14 @@ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicia
{ {
continue; continue;
} }
processBookingCancellation(booking, jobs, *this, util::UserType::TECHNICIAN); std::string title = "Technician Unavailable";
std::string message = "Your assigned technician is no longer available. Your booking has been reset to pending and we will reassign a new technician shortly.";
processBookingCancellation(booking,
util::ServiceJobStatus::PENDING,
title, message, customer,
util::ServiceJobStatus::CANCELLED,
title, message, jobs, *this
);
} }
} }
@@ -1082,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::COMPLETED && currentJob->getStatus() != util::ServiceJobStatus::CANCELLED) if (currentJob->getStatus() == util::ServiceJobStatus::STARTED)
{ {
return false; return false;
} }
@@ -1092,19 +1090,18 @@ static bool hasCompletedAllJobs(std::string bookingId, util::Map<std::string, Jo
} }
/* /*
Function: updateJobStatus Function: completeJob
Description: Description: Marks a job card as completed for the authenticated technician.
Updates the status of a job card assigned to the currently authenticated technician. If all job cards in the booking are completed, marks the booking as completed
- If the job is STARTED, it moves to IN_PROGRESS. and generates an invoice.
- If the job is IN_PROGRESS, it moves to COMPLETED.
When all jobs in a service booking are completed, the booking status is updated,
an invoice is generated, and a notification is sent to the customer.
Parameters: Parameters:
- jobID: const std::string&, unique identifier of the job card to update. - jobID: std::string, ID of the job card
Returns: Returns:
- void - void
Throws:
- 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;
@@ -1128,14 +1125,20 @@ void ServiceManagementService::updateJobStatus(const std::string& jobID)
throw std::runtime_error("Unable to fetch current job."); throw std::runtime_error("Unable to fetch current job.");
} }
if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) if (currentJob->getStatus() == util::ServiceJobStatus::STARTED)
{
currentJob->setStatus(util::ServiceJobStatus::IN_PROGRESS);
jobStatusUpdated = true;
}
else if (currentJob->getStatus() == util::ServiceJobStatus::IN_PROGRESS)
{ {
currentJob->setStatus(util::ServiceJobStatus::COMPLETED); currentJob->setStatus(util::ServiceJobStatus::COMPLETED);
jobStatusUpdated = true; jobStatusUpdated = true;
}
}
else
{
throw std::runtime_error("Failed to complete the job, some error occurred or job already completed.");
}
if (!jobStatusUpdated)
{
throw std::runtime_error("Failed to complete the job, some error occurred or job already completed.");
}
serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs); serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs);
if (serviceBookingCompleted) if (serviceBookingCompleted)
{ {
@@ -1145,14 +1148,4 @@ void ServiceManagementService::updateJobStatus(const std::string& jobID)
std::string message = "Services completed for the booking and invoice generated."; std::string message = "Services completed for the booking and invoice generated.";
sendNotification(currentJob->getBooking()->getCustomer(), title, message); sendNotification(currentJob->getBooking()->getCustomer(), title, message);
} }
}
}
else
{
throw std::runtime_error("Failed to update job status. Job may already be completed.");
}
if (!jobStatusUpdated)
{
throw std::runtime_error("Failed to update job status. Job may already be completed.");
}
} }
@@ -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);
@@ -38,7 +38,6 @@ namespace util
PENDING, PENDING,
STARTED, STARTED,
COMPLETED, COMPLETED,
IN_PROGRESS,
CANCELLED CANCELLED
}; };
@@ -213,8 +212,6 @@ namespace util
return "COMPLETED"; return "COMPLETED";
case ServiceJobStatus::CANCELLED: case ServiceJobStatus::CANCELLED:
return "CANCELLED"; return "CANCELLED";
case ServiceJobStatus::IN_PROGRESS:
return "IN_PROGRESS";
} }
throw std::invalid_argument("Invalid ServiceJobStatus"); throw std::invalid_argument("Invalid ServiceJobStatus");
} }
@@ -247,10 +244,6 @@ namespace util
{ {
return ServiceJobStatus::CANCELLED; return ServiceJobStatus::CANCELLED;
} }
if (value == "IN_PROGRESS")
{
return ServiceJobStatus::IN_PROGRESS;
}
throw std::invalid_argument("Invalid ServiceJobStatus string"); throw std::invalid_argument("Invalid ServiceJobStatus string");
} }
@@ -503,7 +503,7 @@ void AdminMenu::displayUsers()
/* /*
Function: confirmPayment Function: confirmPayment
Description: Confirms payment for a selected invoice. Validates invoice status, updates payment date, Description: Confirms payment for a selected invoice. Validates invoice status, updates payment date,
sets status to COMPLETED, and sends a notification to the customer. sets status to PAID, and sends a notification to the customer.
Parameters: Parameters:
- invoiceID: std::string, ID of the invoice to confirm - invoiceID: std::string, ID of the invoice to confirm
Returns: Returns:
@@ -520,19 +520,19 @@ void AdminMenu::confirmPayment()
util::pressEnter(); util::pressEnter();
return; return;
} }
bool hasConfirmableInvoice = false; bool hasPaidInvoice = false;
for (int index = 0; index < invoiceList.getSize(); ++index) for (int index = 0; index < invoiceList.getSize(); ++index)
{ {
const Invoice* invoice = invoiceList.getValueAt(index); const Invoice* invoice = invoiceList.getValueAt(index);
if (invoice && invoice->getStatus() == util::PaymentStatus::PAID) if (invoice && invoice->getStatus() == util::PaymentStatus::PAID)
{ {
hasConfirmableInvoice = true; hasPaidInvoice = true;
break; break;
} }
} }
if (!hasConfirmableInvoice) if (!hasPaidInvoice)
{ {
std::cout << "No invoices awaiting confirmation.\n"; std::cout << "No pending invoices available for payment.\n";
util::pressEnter(); util::pressEnter();
return; return;
} }
@@ -631,6 +631,7 @@ inline void displayInvoices(util::Map<std::string, const Invoice*> currentUserIn
std::cout << "Unable to fetch the selected invoice\n"; std::cout << "Unable to fetch the selected invoice\n";
doRun = false; doRun = false;
} }
} while (doRun); } while (doRun);
} }
} }
@@ -649,35 +650,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::IN_PROGRESS)) 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);
} }
@@ -706,18 +679,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::IN_PROGRESS)) 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;
} }
} }
@@ -731,31 +702,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::IN_PROGRESS)
{
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"
@@ -763,24 +719,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)
@@ -791,7 +745,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,50 +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::ServiceJobStatus::PENDING;
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::IN_PROGRESS;
}
else
{
std::cout << "Invalid choice. Please try again.\n";
util::pressEnter();
return;
}
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();