Compare commits

...

6 Commits

Author SHA1 Message Date
joelthomastrenser dd29c7324f Fix: Prevent duplicate usernames across all user states
Changes:
- Updated username duplicate validation to consider all existing users.
- Prevented reuse of usernames belonging to deleted/disabled accounts.
- Fixed authentication conflicts caused by duplicate usernames.

Fixes #1809
2026-06-01 17:40:27 +05:30
joelthomastrenser 17f24b7733 Merged PR 1155: Implement Confirm Payment Functionality
- Added Controller::getAllInvoices – retrieves all invoices from PaymentManagementService and returns them as a read-only map
- Implemented Controller::confirmPayment – delegates payment confirmation for a given invoice ID to PaymentManagementService
- Introduced PaymentManagementService::getAllInvoice – provides access to all invoices stored in the datastore
- Added PaymentManagementService::confirmPayment – confirms payment for a specific invoice, updates payment date and status, and sends notification
- Extended util::PaymentStatus enum – added PAID status and updated string conversion
- Integrated AdminMenu::confirmPayment – validates invoice list, filters by status, allows selection, and confirms payment
- Updated CustomerMenu::completePayments – uses parameterized status filtering for invoice selection
- Enhanced MenuHelper::selectInvoiceFromUserForPayment – accepts requiredStatus parameter for flexible filtering
- Adjusted AdminMenu options – added "Confirm Payment" before Logout

Related work items: #1797
2026-06-01 17:34:41 +05:30
Avinash Rajesh 1032fc64bd Commit aee6356e: 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-06-01 17:30:27 +05:30
joelthomastrenser cfd1a2b675 Merged PR 1154: Implement Update Job Status for technician
- Renamed Controller and ServiceManagementService methods from completeJob to updateJobStatus for clarity and flexibility.
- Enhanced ServiceManagementService::updateJobStatus to support transitions:
- STARTED → INPROGRESS
- INPROGRESS → COMPLETED (with invoice generation and customer notification).
- Added INPROGRESS state to ServiceJobStatus enum and updated string conversion utilities.
- Introduced filterJobCards helper to generalize job filtering by status.
- Updated TechnicianMenu to allow technicians to select job type (Started/Inprogress) and update status accordingly.
- Improved job display to show current status and truncated service names for readability.

Related work items: #1798
2026-06-01 17:25:28 +05:30
Jissin Mathew 70ec47df04 Fix review comments 2026-06-01 16:49:57 +05:30
Jissin Mathew 2ea77bf9b6 Implement Update Job Status for technician
<UserStory> SER1798: Update Job Status </UserStory>

<Changes>
    1. Renamed Controller and ServiceManagementService methods from completeJob to updateJobStatus for clarity and flexibility.
    2. Enhanced ServiceManagementService::updateJobStatus to support transitions:
       - STARTED → INPROGRESS
       - INPROGRESS → COMPLETED (with invoice generation and customer notification).
    3. Added INPROGRESS state to ServiceJobStatus enum and updated string conversion utilities.
    4. Introduced filterJobCards helper to generalize job filtering by status.
    5. Updated TechnicianMenu to allow technicians to select job type (Started/Inprogress) and update status accordingly.
    6. Improved job display to show current status and truncated service names for readability.
</Changes>

<Test>

 Acceptance Criteria:
 1. Technician can select a job with status STARTED and update it to INPROGRESS.
 2. Technician can select a job with status INPROGRESS and update it to COMPLETED.
 3. Completed bookings automatically generate invoices and send notifications to customers.
 4. Job status updates are reflected in the technician’s job list and customer view.

 Precondition:
 1. Technician is logged into the system.
 2. Assigned job cards exist with valid statuses (STARTED or INPROGRESS).
 3. Datastore and payment service are available.

 Steps:
 1. Navigate to Technician menu and choose "Update Job Status".
    - Verify that the system prompts for job type selection (Started/Inprogress).
 2. Select a job card from the filtered list.
    - Verify that the job card details are displayed with status.
 3. Confirm update.
    - Verify that the job status changes correctly.
 4. For jobs updated to COMPLETED:
    - Verify that the booking status is updated, invoice is generated, and notification is sent.
</Test>

<Review>
Sreeja Reghukumar, please review
</Review>

#1798
2026-06-01 16:49:56 +05:30
15 changed files with 281 additions and 66 deletions
@@ -392,9 +392,9 @@ Parameters:
Returns: Returns:
- void - void
*/ */
void Controller::completeJob(const std::string& jobID) void Controller::updateJobStatus(const std::string& jobID)
{ {
m_serviceManagementService.completeJob(jobID); m_serviceManagementService.updateJobStatus(jobID);
} }
/* /*
@@ -462,6 +462,38 @@ util::Map<std::string, const Invoice*> Controller::getInvoicesByUser()
return userInvoicesReadOnly; return userInvoicesReadOnly;
} }
/*
Function: getAllInvoices
Description: Retrieves all invoices from the PaymentManagementService and returns them as a read-only map.
Parameters:
- none
Returns:
- util::Map<std::string, const Invoice*>: Map of invoice IDs to invoice objects
*/
util::Map<std::string, const Invoice*> Controller::getAllInvoices()
{
auto invoices = m_paymentManagementService.getAllInvoices();
util::Map<std::string, const Invoice*> readOnlyInvoice;
for (int iterator = 0; iterator < invoices.getSize(); iterator++)
{
readOnlyInvoice.insert(invoices.getKeyAt(iterator), invoices.getValueAt(iterator));
}
return readOnlyInvoice;
}
/*
Function: confirmPayment
Description: Delegates payment confirmation for a given invoice ID to the PaymentManagementService.
Parameters:
- invoiceID: std::string, ID of the invoice to confirm
Returns:
- void
*/
void Controller::confirmPayment(const std::string& invoiceID)
{
m_paymentManagementService.confirmPayment(invoiceID);
}
/* /*
Function: completePayment Function: completePayment
Description: Completes payment for a specific invoice using the given payment mode. Description: Completes payment for a specific invoice using the given payment mode.
@@ -59,11 +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 completeJob(const std::string& jobID); void updateJobStatus(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();
void confirmPayment(const 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);
@@ -368,12 +368,12 @@ void PaymentManagementService::completePayment(const std::string& invoiceID, uti
if (invoiceIndex != -1) if (invoiceIndex != -1)
{ {
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex); Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
if (invoice && invoice->getStatus() != util::PaymentStatus::COMPLETED) if (invoice && invoice->getStatus() != util::PaymentStatus::PAID)
{ {
User* currentUser = invoice->getBooking()->getCustomer(); User* currentUser = invoice->getBooking()->getCustomer();
invoice->setPaymentMethod(paymentMode); invoice->setPaymentMethod(paymentMode);
invoice->setPaymentDate(util::Timestamp()); invoice->setPaymentDate(util::Timestamp());
invoice->setStatus(util::PaymentStatus::COMPLETED); invoice->setStatus(util::PaymentStatus::PAID);
std::string title, message; std::string title, message;
title = "Payment successful"; title = "Payment successful";
message = "Payment successful for Invoice ID " + invoiceID; message = "Payment successful for Invoice ID " + invoiceID;
@@ -384,4 +384,48 @@ void PaymentManagementService::completePayment(const std::string& invoiceID, uti
{ {
throw std::runtime_error("Payment failed: invalid invoice ID."); throw std::runtime_error("Payment failed: invalid invoice ID.");
} }
}
/*
Function: getAllInvoice
Description: Provides access to all invoices stored in the data store.
Parameters:
- none
Returns:
- util::Map<std::string, Invoice*>&: Map of invoice IDs to invoice objects
*/
util::Map<std::string, Invoice*>& PaymentManagementService::getAllInvoices()
{
return m_dataStore.getInvoices();
}
/*
Function: confirmPayment
Description: Confirms payment for a specific invoice. Updates payment date and status,
then sends a notification to the customer.
Parameters:
- invoiceID: std::string, ID of the invoice to confirm
Returns:
- void
Throws:
- std::runtime_error if the invoice ID is invalid
*/
void PaymentManagementService::confirmPayment(const std::string& invoiceID)
{
auto& currentInvoices = m_dataStore.getInvoices();
int invoiceIndex = currentInvoices.find(invoiceID);
if (invoiceIndex == -1)
{
throw std::runtime_error("Payment confirmation failed: invalid invoice ID.");
}
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
if (!invoice || invoice->getStatus() != util::PaymentStatus::PAID)
{
throw std::runtime_error("Payment confirmation failed: invoice is not awaiting confirmation.");
}
User* currentUser = invoice->getBooking()->getCustomer();
invoice->setStatus(util::PaymentStatus::COMPLETED);
std::string title = "Payment Confirmed";
std::string message = "Payment Confirmed for Invoice ID " + invoiceID;
sendNotification(currentUser, title, message);
} }
@@ -28,6 +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();
void confirmPayment(const 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;
@@ -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) if (currentJob->getStatus() != util::ServiceJobStatus::COMPLETED && currentJob->getStatus() != util::ServiceJobStatus::CANCELLED)
{ {
return false; return false;
} }
@@ -1090,18 +1090,19 @@ static bool hasCompletedAllJobs(std::string bookingId, util::Map<std::string, Jo
} }
/* /*
Function: completeJob Function: updateJobStatus
Description: Marks a job card as completed for the authenticated technician. Description:
If all job cards in the booking are completed, marks the booking as completed Updates the status of a job card assigned to the currently authenticated technician.
and generates an invoice. - If the job is STARTED, it moves to IN_PROGRESS.
- 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: std::string, ID of the job card - jobID: const std::string&, unique identifier of the job card to update.
Returns: Returns:
- void - void
Throws:
- std::runtime_error if technician is not authenticated, job card not found, or job already completed
*/ */
void ServiceManagementService::completeJob(const std::string& jobID) void ServiceManagementService::updateJobStatus(const std::string& jobID)
{ {
AuthenticationManagementService authenticationManagementService; AuthenticationManagementService authenticationManagementService;
PaymentManagementService paymentManagementService; PaymentManagementService paymentManagementService;
@@ -1126,26 +1127,30 @@ void ServiceManagementService::completeJob(const std::string& jobID)
} }
if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) if (currentJob->getStatus() == util::ServiceJobStatus::STARTED)
{ {
currentJob->setStatus(util::ServiceJobStatus::COMPLETED); currentJob->setStatus(util::ServiceJobStatus::IN_PROGRESS);
jobStatusUpdated = true; jobStatusUpdated = true;
} }
else if (currentJob->getStatus() == util::ServiceJobStatus::IN_PROGRESS)
{
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 complete the job, some error occurred or job already completed."); throw std::runtime_error("Failed to update job status. Job may already be completed.");
} }
if (!jobStatusUpdated) if (!jobStatusUpdated)
{ {
throw std::runtime_error("Failed to complete the job, some error occurred or job already completed."); throw std::runtime_error("Failed to update job status. Job may already be 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 completeJob(const std::string& jobID); void updateJobStatus(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);
@@ -29,7 +29,8 @@ namespace util
enum class PaymentStatus enum class PaymentStatus
{ {
PENDING, PENDING,
COMPLETED COMPLETED,
PAID
}; };
enum class ServiceJobStatus enum class ServiceJobStatus
@@ -37,6 +38,7 @@ namespace util
PENDING, PENDING,
STARTED, STARTED,
COMPLETED, COMPLETED,
IN_PROGRESS,
CANCELLED CANCELLED
}; };
@@ -160,6 +162,8 @@ namespace util
return "PENDING"; return "PENDING";
case PaymentStatus::COMPLETED: case PaymentStatus::COMPLETED:
return "COMPLETED"; return "COMPLETED";
case PaymentStatus::PAID:
return "PAID";
} }
throw std::invalid_argument("Invalid PaymentStatus"); throw std::invalid_argument("Invalid PaymentStatus");
} }
@@ -209,6 +213,8 @@ 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");
} }
@@ -241,6 +247,10 @@ 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");
} }
@@ -116,15 +116,13 @@ bool util::isPasswordValid(const std::string& password)
* usersMap - map of user objects keyed by identifier * usersMap - map of user objects keyed by identifier
* Returns: * Returns:
* bool - true if the username is already in use by an active user, false otherwise * bool - true if the username is already in use by an active user, false otherwise
* Notes:
* - Only considers users with state util::State::ACTIVE
*/ */
bool util::isUsernameDuplicate(const std::string& username, const util::Map<std::string, User*>& usersMap) bool util::isUsernameDuplicate(const std::string& username, const util::Map<std::string, User*>& usersMap)
{ {
int index = usersMap.findIf( int index = usersMap.findIf(
[&](const std::string&, User* user) [&](const std::string&, User* user)
{ {
return (user->getUserName() == username && user->getState() == util::State::ACTIVE); return (user->getUserName() == username);
} }
); );
return index != -1; return index != -1;
@@ -53,7 +53,8 @@ void AdminMenu::showMenu()
<< "\n14. Remove Combo Package" << "\n14. Remove Combo Package"
<< "\n15. View Notifications" << "\n15. View Notifications"
<< "\n16. Change Password" << "\n16. Change Password"
<< "\n17. Logout" << "\n17. Confirm Payment"
<< "\n18. Logout"
<< "\nEnter a choice: "; << "\nEnter a choice: ";
util::read(choice); util::read(choice);
if (!handleOperation(choice)) if (!handleOperation(choice))
@@ -127,7 +128,10 @@ bool AdminMenu::handleOperation(int choice)
case 16: case 16:
changePassword(); changePassword();
break; break;
case 17: case 17:
confirmPayment();
break;
case 18:
logout(); logout();
return false; return false;
default: default:
@@ -496,6 +500,54 @@ void AdminMenu::displayUsers()
util::pressEnter(); util::pressEnter();
} }
/*
Function: confirmPayment
Description: Confirms payment for a selected invoice. Validates invoice status, updates payment date,
sets status to COMPLETED, and sends a notification to the customer.
Parameters:
- invoiceID: std::string, ID of the invoice to confirm
Returns:
- void
*/
void AdminMenu::confirmPayment()
{
util::clear();
std::cout << "Confirm Payment\n";
auto invoiceList = m_controller.getAllInvoices();
if (invoiceList.isEmpty())
{
std::cout << "No pending invoices available for confirmation.";
util::pressEnter();
return;
}
bool hasConfirmableInvoice = false;
for (int index = 0; index < invoiceList.getSize(); ++index)
{
const Invoice* invoice = invoiceList.getValueAt(index);
if (invoice && invoice->getStatus() == util::PaymentStatus::PAID)
{
hasConfirmableInvoice = true;
break;
}
}
if (!hasConfirmableInvoice)
{
std::cout << "No invoices awaiting confirmation.\n";
util::pressEnter();
return;
}
std::string selectedID = selectInvoiceFromUserForPayment(invoiceList, util::PaymentStatus::PAID);
if (selectedID == "")
{
std::cout << "Payment failed.\n";
util::pressEnter();
return;
}
m_controller.confirmPayment(selectedID);
std::cout << "Payment Confirmed successfully.\n";
util::pressEnter();
}
/* /*
Function: addTechnician Function: addTechnician
Description: Adds a new technician after validating username, password, email, and phone number. Description: Adds a new technician after validating username, password, email, and phone number.
@@ -28,6 +28,7 @@ public:
void createService(); void createService();
void removeService(); void removeService();
void displayUsers(); void displayUsers();
void confirmPayment();
void addTechnician(); void addTechnician();
void removeUser(); void removeUser();
void displayComboPackages(); void displayComboPackages();
@@ -338,7 +338,7 @@ void CustomerMenu::completePayments()
util::pressEnter(); util::pressEnter();
return; return;
} }
std::string selectedID = selectInvoiceFromUserForPayment(currentInvoices); std::string selectedID = selectInvoiceFromUserForPayment(currentInvoices, util::PaymentStatus::PENDING);
if (selectedID == "") if (selectedID == "")
{ {
std::cout << "Payment failed.\n"; std::cout << "Payment failed.\n";
@@ -364,14 +364,18 @@ inline const User* selectTechnician(util::Map<int, const User*>& currentAvailabl
} }
/* /*
Function: selectInvoiceFromUserForPayment Function: selectInvoiceFromUserForPayment
Description: Lists all pending invoices for the customer and allows selection by index. Description: Displays a list of invoices filtered by the required payment status.
Allows the user to select an invoice by index and returns the corresponding invoice ID.
Parameters: Parameters:
- currentInvoices: util::Map<std::string, const Invoice*>&, map of customer invoices - currentInvoices: const util::Map<std::string, const Invoice*>&,
map of all invoices keyed by invoice ID
- requiredStatus: util::PaymentStatus,
the status to filter invoices (e.g., PENDING, PAID, COMPLETED)
Returns: Returns:
- std::string: ID of the selected invoice, or empty string if none selected - std::string: ID of the selected invoice, or empty string if none selected or invalid index
*/ */
inline std::string selectInvoiceFromUserForPayment(const util::Map<std::string, const Invoice*>& currentInvoices) inline std::string selectInvoiceFromUserForPayment(const util::Map<std::string, const Invoice*>& currentInvoices, util::PaymentStatus requiredStatus)
{ {
int currentIndex = 1, choice; int currentIndex = 1, choice;
util::Map<int, const Invoice*> pendingInvoicesForPayment; util::Map<int, const Invoice*> pendingInvoicesForPayment;
@@ -389,7 +393,7 @@ inline std::string selectInvoiceFromUserForPayment(const util::Map<std::string,
for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++) for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
{ {
const Invoice* currentInvoice = currentInvoices.getValueAt(iterator); const Invoice* currentInvoice = currentInvoices.getValueAt(iterator);
if (currentInvoice && currentInvoice->getStatus() == util::PaymentStatus::PENDING) if (currentInvoice && currentInvoice->getStatus() == requiredStatus)
{ {
const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician(); const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician();
std::cout << std::left std::cout << std::left
@@ -627,7 +631,6 @@ 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);
} }
} }
@@ -646,7 +649,35 @@ 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) if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED || currentJobCard->getStatus() == util::ServiceJobStatus::IN_PROGRESS))
{
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);
} }
@@ -675,16 +706,18 @@ 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)) if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED || currentJobCard->getStatus() == util::ServiceJobStatus::IN_PROGRESS))
{ {
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) << currentJobCard->getService()->getName() << std::setw(20) << util::truncateString(currentJobCard->getService()->getName(), 15)
<< std::setw(12) << currentJobCard->getServiceId() << std::setw(12) << currentJobCard->getServiceId()
<< std::setw(12) << util::getServiceJobStatusString(currentJobCard->getStatus())
<< std::endl; << std::endl;
} }
} }
@@ -698,16 +731,31 @@ 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 selectJobCardToComplete(util::Map<std::string, const JobCard*>& assignedJobCards) inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>& assignedJobCards, util::ServiceJobStatus selectedJobStatusType)
{ {
util::Map<int, const JobCard* > incompleteJobCards; util::Map<int, const JobCard* > incompleteJobCards;
if (assignedJobCards.getSize() == 0) if (assignedJobCards.getSize() == 0)
{ {
std::cout << "No started jobs available to complete.\n"; std::cout << "No jobs available.\n\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"
@@ -715,22 +763,24 @@ inline std::string selectJobCardToComplete(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() == util::ServiceJobStatus::STARTED)) if (currentJobCard && (currentJobCard->getStatus() == selectedJobStatusType))
{ {
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) << currentJobCard->getService()->getName() << std::setw(20) << util::truncateString(currentJobCard->getService()->getName(), 15)
<< 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 complete (Index): "; std::cout << "Select the Job Card to Update (Index): ";
util::read(choice); util::read(choice);
int selectedJobCardIndex = incompleteJobCards.find(choice); int selectedJobCardIndex = incompleteJobCards.find(choice);
if (selectedJobCardIndex != -1) if (selectedJobCardIndex != -1)
@@ -741,7 +791,7 @@ inline std::string selectJobCardToComplete(util::Map<std::string, const JobCard*
else else
{ {
std::cout << "Invalid index.\n"; std::cout << "Invalid index.\n";
std::cout << "Failed to complete jobs.\n\n"; std::cout << "Failed to update job.\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. Mark Job as Completed" << "\n2. Update Job Status"
<< "\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:
completeJob(); updateJobStatus();
break; break;
case 3: case 3:
viewNotifications(); viewNotifications();
@@ -99,31 +99,50 @@ 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*> startedJobCards = filterStartedJobCards(assignedJobCards); util::Map<std::string, const JobCard*> jobCards = filterStartedJobCards(assignedJobCards);
displayAllJobs(startedJobCards); displayAllJobs(jobCards);
util::pressEnter(); util::pressEnter();
} }
/* /*
Function: completeJob Function: updateJobStatus
Description: Allows the technician to mark a selected job card as completed. Description: Allows the technician to update a selected job card.
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::completeJob() void TechnicianMenu::updateJobStatus()
{ {
util::clear(); util::clear();
std::cout << "Complete Job\n"; std::cout << "Update Job Status\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();
util::Map<std::string, const JobCard*> startedJobCards = filterStartedJobCards(assignedJobCards); std::cout << "Select the type of job you want to update\n1.Started\n2.Inprogress\nChoice: ";
std::string selectedJobID = selectJobCardToComplete(startedJobCards); util::read(choice);
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.completeJob(selectedJobID); m_controller.updateJobStatus(selectedJobID);
std::cout << "\nJob marked as completed.\n\n"; std::cout << "\nJob status updated.\n\n";
} }
util::pressEnter(); util::pressEnter();
} }
@@ -18,7 +18,7 @@ private:
public: public:
void showMenu(); void showMenu();
void displayJobs(); void displayJobs();
void completeJob(); void updateJobStatus();
void viewNotifications(); void viewNotifications();
void logout(); void logout();
void changePassword(); void changePassword();
@@ -27,4 +27,4 @@ public:
void run(); void run();
void login(); void login();
void registerCustomer(); void registerCustomer();
}; };