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>
This commit is contained in:
@@ -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.getAllInvoice();
|
||||||
|
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(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(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);
|
||||||
|
|||||||
+50
-2
@@ -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;
|
||||||
@@ -385,3 +385,51 @@ 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::getAllInvoice()
|
||||||
|
{
|
||||||
|
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(std::string invoiceID)
|
||||||
|
{
|
||||||
|
std::string title, message;
|
||||||
|
auto& currentInvoices = m_dataStore.getInvoices();
|
||||||
|
int invoiceIndex = currentInvoices.find(invoiceID);
|
||||||
|
if (invoiceIndex != -1)
|
||||||
|
{
|
||||||
|
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
|
||||||
|
if (invoice && invoice->getStatus() != util::PaymentStatus::COMPLETED)
|
||||||
|
{
|
||||||
|
User* currentUser = invoice->getBooking()->getCustomer();
|
||||||
|
invoice->setPaymentDate(util::Timestamp());
|
||||||
|
invoice->setStatus(util::PaymentStatus::COMPLETED);
|
||||||
|
title = "Payment Confirmed";
|
||||||
|
message = "Payment Confirmed for Invoice ID " + invoiceID;
|
||||||
|
sendNotification(currentUser, title, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Payment failed: invalid invoice ID.");
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -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*>& getAllInvoice();
|
||||||
|
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;
|
||||||
|
|||||||
@@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
@@ -128,6 +129,9 @@ bool AdminMenu::handleOperation(int choice)
|
|||||||
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 PAID, 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 hasPaidInvoice = false;
|
||||||
|
for (int index = 0; index < invoiceList.getSize(); ++index)
|
||||||
|
{
|
||||||
|
const Invoice* invoice = invoiceList.getValueAt(index);
|
||||||
|
if (invoice && invoice->getStatus() == util::PaymentStatus::PAID)
|
||||||
|
{
|
||||||
|
hasPaidInvoice = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasPaidInvoice)
|
||||||
|
{
|
||||||
|
std::cout << "No pending invoices available for payment.\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";
|
||||||
|
|||||||
@@ -365,13 +365,17 @@ 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
|
||||||
|
|||||||
Reference in New Issue
Block a user