Compare commits

..

11 Commits

Author SHA1 Message Date
joelthomastrenser 8a3ec278ce Merged PR 1159: Vehicle Service System v1.1.0.0
**New Features**

**Payment Confirmation Workflow**
- Added support for payment confirmation by administrators.

- Introduced a new PAID payment status.

- Implemented invoice confirmation flow from PAID → COMPLETED.

- Added invoice filtering based on payment status.

- Added admin menu option to confirm customer payments.

**Technician Job Status Workflow**
- Enhanced technician job management with multi-stage status updates.

- Added support for job status transitions:

- STARTED → IN_PROGRESS

- IN_PROGRESS → COMPLETED

- Added invoice generation and customer notification upon booking completion.

- Improved job visibility by displaying current job status.

**UI Improvements**
- Improved formatting and wording in the Technician Job Status workflow.

- Standardized status labels using "In Progress".

- Improved prompts, headings, and job selection messages.

- Enhanced readability of job listings.

**Bug Fixes**
- Fixed duplicate customer notifications when an assigned technician is removed.

- Prevented creation of duplicate usernames across all user states.

- Fixed authentication conflicts caused by reuse of deleted/disabled usernames.

- Improved booking cancellation handling for customer and technician removal scenarios.

- Updated cancellation logic to correctly handle bookings in IN_PROGRESS state.

Related work items: #1797, #1798, #1807, #1808, #1809
2026-06-01 18:57:46 +05:30
Avinash Rajesh 602b538830 Merged PR 1157: Fix Duplicate Customer Notification Sent When Assigned Technician Is Removed
Fix Duplicate Customer Notification Sent When Assigned Technician Is Removed

- Refactored processBookingCancellation to simplify parameters and remove redundant notification arguments.
- Added util::UserType parameter to differentiate cancellation flows for CUSTOMER vs TECHNICIAN.
- Updated cancelCustomerServiceBookings to use processBookingCancellation with util::UserType::CUSTOMER.
- Updated cancelTechnicianJobs to use processBookingCancellation with util::UserType::TECHNICIAN.
- Enhanced booking status handling by including IN_PROGRESS status in cancellation checks.
- Ensured job cards are consistently marked CANCELLED and inventory restored.
- Fixed duplicate notification issue where customers received multiple alerts when technician was removed.

Fixes #1807

Related work items: #1807
2026-06-01 18:15:36 +05:30
Jissin Mathew 86873d2a21 Merged PR 1158: Fix Technician Job Status Update Screen UI and Formatting Issues
Fix Technician Job Status Update Screen UI and Formatting Issues

- Corrected inconsistent status label formatting: replaced "Inprogress" with "In Progress" in TechnicianMenu and MenuHelper.
- Updated headings in selectJobCardToUpdate to clearer phrasing:
  - "Select a job to mark as In Progress"
  - "Select a job to mark as Completed".
- Added spacing before and after the "No jobs available" message to improve readability and provide clear separation from headings.
- Replaced duplicated prompt "Select the Job Card to Update (Index):" with concise "Enter the job index to update:".
- Improved TechnicianMenu option display to show "In Progress" instead of "Inprogress".

Related work items: #1808
2026-06-01 18:13:34 +05:30
Avinash Rajesh c64f3cff72 Implemented Review Fixes 2026-06-01 18:13:11 +05:30
Jissin Mathew ce50467816 Fix Technician Job Status Update Screen UI and Formatting Issues
- Corrected inconsistent status label formatting: replaced "Inprogress" with "In Progress" in TechnicianMenu and MenuHelper.
- Updated headings in selectJobCardToUpdate to clearer phrasing:
  - "Select a job to mark as In Progress"
  - "Select a job to mark as Completed".
- Added spacing before and after the "No jobs available" message to improve readability and provide clear separation from headings.
- Replaced duplicated prompt "Select the Job Card to Update (Index):" with concise "Enter the job index to update:".
- Improved TechnicianMenu option display to show "In Progress" instead of "Inprogress".

Fixes #1808
2026-06-01 18:02:45 +05:30
Avinash Rajesh 20475ace73 Fix Duplicate Customer Notification Sent When Assigned Technician Is Removed
- Refactored processBookingCancellation to simplify parameters and remove redundant notification arguments.
- Added util::UserType parameter to differentiate cancellation flows for CUSTOMER vs TECHNICIAN.
- Updated cancelCustomerServiceBookings to use processBookingCancellation with util::UserType::CUSTOMER.
- Updated cancelTechnicianJobs to use processBookingCancellation with util::UserType::TECHNICIAN.
- Enhanced booking status handling by including IN_PROGRESS status in cancellation checks.
- Ensured job cards are consistently marked CANCELLED and inventory restored.
- Fixed duplicate notification issue where customers received multiple alerts when technician was removed.

Fixes #1807
2026-06-01 17:46:55 +05:30
joelthomastrenser 1e63b900ab Merged PR 1156: Fix: Prevent duplicate usernames across all user states
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

Related work items: #1809
2026-06-01 17:44:49 +05:30
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
12 changed files with 210 additions and 70 deletions
@@ -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.
@@ -64,6 +64,8 @@ public:
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;
@@ -543,50 +543,65 @@ static void restoreInventory(ServiceBooking* booking)
/* /*
Function: processBookingCancellation Function: processBookingCancellation
Description: Cancels jobs and updates the status of a given booking. Sends notifications to the Description: Handles cancellation or reassignment of a service booking based on user type.
specified user, resets technician assignment if needed, and restores inventory items. Cancels associated job cards, updates booking status, clears technician assignments,
Parameter: ServiceBooking* booking - Pointer to the booking being cancelled restores inventory, and sends appropriate notifications.
util::ServiceJobStatus newServiceBookingStatus - New status to assign to the booking Parameters:
const std::string& notificationTitle - Title of the booking cancellation notification ServiceBooking* booking - The booking to cancel or reset
const std::string& notificationMessage - Message body of the booking cancellation notification util::Map<std::string, JobCard*>& jobs - Collection of job cards to update
User* notifyUser - User to notify about the cancellation ServiceManagementService& currentService - Service layer for notifications
util::ServiceJobStatus jobCardStatus - New status to assign to associated job cards util::UserType userType - Type of user initiating cancellation (CUSTOMER or TECHNICIAN)
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
ServiceManagementService& currentService - Reference to the service for sending notifications
Return type: void Return type: void
*/ */
static void processBookingCancellation(ServiceBooking* booking, static void processBookingCancellation(ServiceBooking* booking,
util::ServiceJobStatus newServiceBookingStatus, util::Map<std::string, JobCard*>& jobs,
const std::string& notificationTitle, ServiceManagementService& currentService,
const std::string& notificationMessage, util::UserType userType)
User* notifyUser,
util::ServiceJobStatus jobCardStatus,
const std::string& jobNotificationTitle,
const std::string& jobNotificationMessage,
util::Map<std::string, JobCard*>& jobs, ServiceManagementService& currentService)
{ {
if (!booking || !notifyUser) if (!booking)
{ {
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()) if (!jobCard || jobCard->getBookingId() != booking->getId() || jobCard->getStatus() == util::ServiceJobStatus::CANCELLED)
{ {
jobCard->setStatus(jobCardStatus); continue;
currentService.sendNotification(notifyUser, jobNotificationTitle, jobNotificationMessage); }
jobCard->setStatus(util::ServiceJobStatus::CANCELLED);
if (userType == util::UserType::CUSTOMER)
{
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);
}
} }
} }
booking->setStatus(newServiceBookingStatus); if (userType == util::UserType::CUSTOMER)
currentService.sendNotification(notifyUser, notificationTitle, notificationMessage);
if (newServiceBookingStatus == util::ServiceJobStatus::PENDING)
{ {
booking->setAssignedTechnician(nullptr); booking->setStatus(util::ServiceJobStatus::CANCELLED);
booking->setAssignedTechnicianId(""); 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->setAssignedTechnicianId("");
restoreInventory(booking); restoreInventory(booking);
} }
@@ -624,21 +639,13 @@ void ServiceManagementService::cancelCustomerServiceBookings(const std::string&
{ {
continue; continue;
} }
if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED) if (booking->getStatus() != util::ServiceJobStatus::PENDING &&
booking->getStatus() != util::ServiceJobStatus::STARTED &&
booking->getStatus() != util::ServiceJobStatus::IN_PROGRESS)
{ {
continue; continue;
} }
User* assignedTechnician = booking->getAssignedTechnician(); processBookingCancellation(booking, jobs, *this, util::UserType::CUSTOMER);
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
);
} }
} }
@@ -676,7 +683,9 @@ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicia
{ {
continue; continue;
} }
if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED) if (booking->getStatus() != util::ServiceJobStatus::PENDING &&
booking->getStatus() != util::ServiceJobStatus::STARTED &&
booking->getStatus() != util::ServiceJobStatus::IN_PROGRESS)
{ {
continue; continue;
} }
@@ -685,14 +694,7 @@ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicia
{ {
continue; continue;
} }
std::string title = "Technician Unavailable"; processBookingCancellation(booking, jobs, *this, util::UserType::TECHNICIAN);
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
);
} }
} }
@@ -29,7 +29,8 @@ namespace util
enum class PaymentStatus enum class PaymentStatus
{ {
PENDING, PENDING,
COMPLETED COMPLETED,
PAID
}; };
enum class ServiceJobStatus enum class ServiceJobStatus
@@ -161,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");
} }
@@ -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
@@ -732,7 +736,7 @@ inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>&
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 << "\nNo jobs available.\n\n";
return ""; return "";
} }
int currentIndex = 1; int currentIndex = 1;
@@ -740,12 +744,12 @@ inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>&
if (selectedJobStatusType == util::ServiceJobStatus::STARTED) if (selectedJobStatusType == util::ServiceJobStatus::STARTED)
{ {
util::clear(); util::clear();
std::cout << "Select a job to update to Inprogress\n"; std::cout << "Select a job to mark as In Progress\n";
} }
else if (selectedJobStatusType == util::ServiceJobStatus::IN_PROGRESS) else if (selectedJobStatusType == util::ServiceJobStatus::IN_PROGRESS)
{ {
util::clear(); util::clear();
std::cout << "Select a job to update to Completed\n"; std::cout << "Select a job to mark as Completed\n";
} }
else else
{ {
@@ -776,7 +780,7 @@ inline std::string selectJobCardToUpdate(util::Map<std::string, const JobCard*>&
incompleteJobCards.insert(currentIndex++, currentJobCard); incompleteJobCards.insert(currentIndex++, currentJobCard);
} }
} }
std::cout << "Select the Job Card to Update (Index): "; std::cout << "Enter the job index to update: ";
util::read(choice); util::read(choice);
int selectedJobCardIndex = incompleteJobCards.find(choice); int selectedJobCardIndex = incompleteJobCards.find(choice);
if (selectedJobCardIndex != -1) if (selectedJobCardIndex != -1)
@@ -121,7 +121,7 @@ void TechnicianMenu::updateJobStatus()
std::string selectedJobID; std::string selectedJobID;
util::ServiceJobStatus selectedJobStatus = util::ServiceJobStatus::PENDING; 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: "; std::cout << "Select the type of job you want to update:\n1.Started\n2.In Progress\nChoice: ";
util::read(choice); util::read(choice);
if (choice == 1) if (choice == 1)
{ {