Merge branch 'feature-payment-management' into feature-1553-1598

This commit is contained in:
Jissin Mathew
2026-05-25 12:11:20 +05:30
11 changed files with 395 additions and 16 deletions
@@ -176,6 +176,7 @@
<ClInclude Include="utilities\Map.h" />
<ClInclude Include="utilities\OutputHelper.h" />
<ClInclude Include="utilities\Timestamp.h" />
<ClInclude Include="utilities\Utility.h" />
<ClInclude Include="utilities\Validator.h" />
<ClInclude Include="utilities\Vector.h" />
<ClInclude Include="views\AdminMenu.h" />
@@ -233,5 +233,8 @@
<ClInclude Include="models\ComboPackage.h">
<Filter>Header Files\Models</Filter>
</ClInclude>
<ClInclude Include="utilities\Utility.h">
<Filter>Header Files\Utilities</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -3,6 +3,8 @@
#include "Service.h"
#include "ServiceBooking.h"
#include "JobCard.h"
#include "User.h"
#include "Invoice.h"
bool Controller::login(const std::string& username, const std::string& password)
{
@@ -236,13 +238,40 @@ void Controller::removeComboPackage(const std::string& comboPackageID)
{
}
/*
Function: getInvoicesByUser
Description: Retrieves all invoices associated with the currently authenticated user.
Converts them into a read-only map before returning.
Parameters:
- None
Returns:
- util::Map<std::string, const Invoice*> containing the users invoices
*/
util::Map<std::string, const Invoice*> Controller::getInvoicesByUser()
{
return util::Map<std::string, const Invoice*>();
User* currentUser = m_authenticationManagementService.getAuthenticatedUser();
util::Map<std::string, Invoice*> currentUserInvoices = m_paymentManagementService.getInvoices(currentUser->getId());
util::Map<std::string, const Invoice*> userInvoicesReadOnly;
for (int iterator = 0; iterator < currentUserInvoices.getSize(); iterator++)
{
Invoice* currentInvoice = currentUserInvoices.getValueAt(iterator);
userInvoicesReadOnly.insert(currentInvoice->getId(), currentInvoice);
}
return userInvoicesReadOnly;
}
/*
Function: completePayment
Description: Completes payment for a specific invoice using the given payment mode.
Parameters:
- invoiceID: std::string, ID of the invoice to be paid
- paymentMode: util::PaymentMode, mode of payment (e.g., ONLINE, OFFLINE)
Returns:
- void
*/
void Controller::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode)
{
m_paymentManagementService.completePayment(invoiceID, paymentMode);
}
util::Vector<const Notification*> Controller::getNotifications()
@@ -260,5 +289,4 @@ void Controller::configureNotifications(const std::string& userID, bool paymentN
void Controller::runSystemChecks()
{
}
}
@@ -2,6 +2,8 @@
#include "Map.h"
#include <string>
#include "Enums.h"
#include "PaymentManagementService.h"
#include "AuthenticationManagementService.h"
#include "ServiceManagementService.h"
#include "UserManagementService.h"
#include "InventoryManagementService.h"
@@ -18,6 +20,8 @@ class Notification;
class Controller
{
private:
AuthenticationManagementService m_authenticationManagementService;
PaymentManagementService m_paymentManagementService;
ServiceManagementService m_serviceManagementService;
UserManagementService m_userManagementService;
public:
@@ -16,7 +16,8 @@ Invoice::Invoice(
const std::string& bookingId,
ServiceBooking* booking,
const util::Timestamp& invoiceDate,
double laborCost, const util::Map<int,
double laborCost,
const util::Map<std::string,
InventoryItem*>& parts,
double partsCost,
double discountPercentage,
@@ -63,7 +64,7 @@ double Invoice::getLaborCost() const
return m_laborCost;
}
const util::Map<int, InventoryItem*>& Invoice::getParts() const
const util::Map<std::string, InventoryItem*>& Invoice::getParts() const
{
return m_parts;
}
@@ -123,7 +124,7 @@ void Invoice::setLaborCost(double laborCost)
m_laborCost = laborCost;
}
void Invoice::setParts(const util::Map<int, InventoryItem*>& parts)
void Invoice::setParts(const util::Map<std::string, InventoryItem*>& parts)
{
m_parts = parts;
}
@@ -16,7 +16,7 @@ private:
ServiceBooking* m_booking;
util::Timestamp m_invoiceDate;
double m_laborCost;
util::Map<int, InventoryItem*> m_parts;
util::Map<std::string, InventoryItem*> m_parts;
double m_partsCost;
double m_discountPercentage;
double m_totalAmount;
@@ -30,8 +30,8 @@ public:
const std::string& bookingId,
ServiceBooking* booking,
const util::Timestamp& invoiceDate,
double laborCost, const util::Map<int,
InventoryItem*>& parts,
double laborCost,
const util::Map<std::string,InventoryItem*>& parts,
double partsCost,
double discountPercentage,
double totalAmount,
@@ -44,7 +44,7 @@ public:
ServiceBooking* getBooking() const;
const util::Timestamp& getInvoiceDate() const;
double getLaborCost() const;
const util::Map<int, InventoryItem*>& getParts() const;
const util::Map<std::string, InventoryItem*>& getParts() const;
double getPartsCost() const;
double getDiscountPercentage() const;
double getTotalAmount() const;
@@ -56,7 +56,7 @@ public:
void setBooking(ServiceBooking* booking);
void setInvoiceDate(const util::Timestamp& invoiceDate);
void setLaborCost(double laborCost);
void setParts(const util::Map<int, InventoryItem*>& parts);
void setParts(const util::Map<std::string, InventoryItem*>& parts);
void setPartsCost(double partsCost);
void setDiscountPercentage(double discountPercentage);
void setTotalAmount(double totalAmount);
@@ -1,7 +1,7 @@
#pragma once
#include <string>
#include "Timestamp.h"
#include "Enums.h"
#include "Timestamp.h"
class ServiceBooking;
class Service;
@@ -1 +1,135 @@
#include "PaymentManagementService.h"
#include "ServiceBooking.h"
#include "Service.h"
#include "InventoryItem.h"
#include "Utility.h"
#include "Factory.h"
#include "Timestamp.h"
#include "Invoice.h"
#include "JobCard.h"
#include "Enums.h"
/*
Function: createInventoryItemsMap (static helper)
Description: Builds a map of inventory items required for a given service and adds them to the bookings inventory map.
Parameters:
- completeInventoryItemMapOfBooking: util::Map<std::string, InventoryItem*>&, map to store inventory items for the booking
- currentService: const Service*, pointer to the current service
Returns:
- void
*/
static void createInventoryItemsMap(util::Map<std::string, InventoryItem*>& completeInventoryItemMapOfBooking, const Service* currentService)
{
auto& currentRequiredInventoryItems = currentService->getRequiredInventoryItems();
for (int iterator = 0; iterator < currentRequiredInventoryItems.getSize(); iterator++)
{
auto& currentRequiredInventoryItem = currentRequiredInventoryItems.getValueAt(iterator);
completeInventoryItemMapOfBooking.insert(currentRequiredInventoryItem->getId(), currentRequiredInventoryItem);
}
}
/*
Function: generateInvoice
Description: Generates an invoice for a completed service booking.
Validates that all job cards are completed, calculates labor and parts cost, applies discount,
and stores the invoice in the datastore.
Parameters:
- booking: ServiceBooking*, pointer to the service booking
Returns:
- void
Throws:
- std::runtime_error if booking is null or job cards are incomplete
*/
void PaymentManagementService::generateInvoice(ServiceBooking* booking)
{
if (!booking)
{
throw std::runtime_error("Invoice generation failed: booking is null.");
}
double totalLabourCost = 0, totalPartsCost = 0, totalServiceCost = 0;
double discountPercentage = booking->getDiscountPercentage();
std::string bookingID = booking->getId();
util::Map<std::string, Service*> servicesInTheBookedService = booking->getServices();
util::Map<std::string, InventoryItem*> completeInventoryItemMapOfBooking;
util::Map<std::string, JobCard*> currentJobCards = m_dataStore.getJobCards();
for (int iterator = 0; iterator < currentJobCards.getSize(); iterator++)
{
JobCard* currentJobCard = currentJobCards.getValueAt(iterator);
if (currentJobCard->getBookingId() == bookingID && currentJobCard->getStatus() != util::ServiceJobStatus::COMPLETED)
{
throw std::runtime_error("Invoice generation failed: not all job cards are completed for booking '" + bookingID + "'.");
}
}
for (int iterator = 0; iterator < servicesInTheBookedService.getSize(); iterator++)
{
Service* currentService = servicesInTheBookedService.getValueAt(iterator);
if (currentService)
{
createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService);
totalLabourCost += currentService->getLaborCost();
totalPartsCost += calculatePartsCost(currentService);
}
}
totalServiceCost = totalLabourCost + totalPartsCost;
totalServiceCost -= (totalServiceCost * (discountPercentage / 100));
Invoice* invoice = Factory::getObject<Invoice>(bookingID, booking, util::Timestamp(), totalLabourCost, completeInventoryItemMapOfBooking, totalPartsCost, discountPercentage, totalServiceCost, util::Timestamp(), util::PaymentMode::NOTSET, util::PaymentStatus::PENDING);
util::Map<std::string, Invoice*>& currentInvoices = m_dataStore.getInvoices();
currentInvoices.insert(invoice->getId(), invoice);
}
/*
Function: getInvoices
Description: Retrieves all invoices associated with a specific customer.
Parameters:
- customerID: std::string, ID of the customer
Returns:
- util::Map<std::string, Invoice*> containing the customers invoices
*/
util::Map<std::string, Invoice*> PaymentManagementService::getInvoices(const std::string& customerID)
{
util::Map<std::string, Invoice*>& currentInvoices = m_dataStore.getInvoices();
util::Map<std::string, Invoice*> currentUserInvoices;
for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
{
Invoice* currentInvoice = currentInvoices.getValueAt(iterator);
if (currentInvoice->getBooking()->getCustomerId() == customerID)
{
currentUserInvoices.insert(currentInvoice->getId(), currentInvoice);
}
}
return currentUserInvoices;
}
/*
Function: completePayment
Description: Completes payment for a specific invoice. Updates payment method, date, and status,
then sends a notification to the customer.
Parameters:
- invoiceID: std::string, ID of the invoice
- paymentMode: util::PaymentMode, mode of payment (e.g., ONLINE, OFFLINE)
Returns:
- void
Throws:
- std::runtime_error if the invoice ID is invalid
*/
void PaymentManagementService::completePayment(const std::string& invoiceID, util::PaymentMode paymentMode)
{
auto& currentInvoices = m_dataStore.getInvoices();
int invoiceIndex = currentInvoices.find(invoiceID);
if (invoiceIndex != -1)
{
Invoice* invoice = currentInvoices.getValueAt(invoiceIndex);
User* currentUser = invoice->getBooking()->getCustomer();
invoice->setPaymentMethod(paymentMode);
invoice->setPaymentDate(util::Timestamp());
invoice->setStatus(util::PaymentStatus::COMPLETED);
std::string title, message;
title = "Payment successful";
message = "Payment successful for invoice ID " + invoiceID;
sendNotification(currentUser, title, message);
}
else
{
throw std::runtime_error("Payment failed: invalid invoice ID.");
}
}
@@ -13,7 +13,8 @@ namespace util
enum class PaymentMode
{
ONLINE,
OFFLINE
OFFLINE,
NOTSET
};
enum class PaymentStatus
@@ -74,6 +75,8 @@ namespace util
return "ONLINE";
case PaymentMode::OFFLINE:
return "OFFLINE";
case PaymentMode::NOTSET:
return "NOTSET";
}
throw std::invalid_argument("Invalid PaymentMode");
}
@@ -0,0 +1,15 @@
#pragma once
#include "Service.h"
#include "InventoryItem.h"
inline double calculatePartsCost(const Service* service)
{
double cost = 0;
auto& requiredInventoryItems = service->getRequiredInventoryItems();
int requiredInventoryItemsSize = requiredInventoryItems.getSize();
for (int index = 0; index < requiredInventoryItemsSize; index++)
{
cost += requiredInventoryItems.getValueAt(index)->getPrice();
}
return cost;
}
@@ -1,10 +1,15 @@
#include <iomanip>
#include <iostream>
#include "CustomerMenu.h"
#include "InputHelper.h"
#include "OutputHelper.h"
#include "User.h"
#include "ServiceBooking.h"
#include "Invoice.h"
#include "Enums.h"
#include "ServiceBooking.h"
#include "User.h"
#include "Timestamp.h"
#include "Service.h"
#include "InventoryItem.h"
void CustomerMenu::showMenu()
{
@@ -106,12 +111,197 @@ void CustomerMenu::viewServiceHistory()
}
}
void CustomerMenu::completePayments()
/*
Function: selectInvoiceFromUserForPayment (static helper)
Description: Lists all pending invoices for the customer and allows selection by index.
Parameters:
- currentInvoices: util::Map<std::string, const Invoice*>&, map of customer invoices
Returns:
- std::string: ID of the selected invoice, or empty string if none selected
*/
static std::string selectInvoiceFromUserForPayment(const util::Map<std::string, const Invoice*>& currentInvoices)
{
int currentIndex = 1, choice;
util::Map<int, const Invoice*> pendingInvoicesForPayment;
std::cout << std::left
<< std::setw(6) << "Index"
<< std::setw(12) << "BookingID"
<< std::setw(15) << "VehicleBrand"
<< std::setw(15) << "VehicleNumber"
<< std::setw(12) << "TechID"
<< std::setw(20) << "TechnicianName"
<< std::setw(10) << "Discount(%)"
<< std::setw(12) << "TotalAmount"
<< std::setw(20) << "InvoiceDate"
<< std::endl;
for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
{
const Invoice* currentInvoice = currentInvoices.getValueAt(iterator);
if (currentInvoice && currentInvoice->getStatus() == util::PaymentStatus::PENDING)
{
std::cout << std::left
<< std::setw(6) << currentIndex
<< std::setw(12) << currentInvoice->getBookingId()
<< std::setw(15) << currentInvoice->getBooking()->getVehicleBrand()
<< std::setw(15) << currentInvoice->getBooking()->getVehicleNumber()
<< std::setw(12) << currentInvoice->getBooking()->getAssignedTechnician()->getId()
<< std::setw(20) << currentInvoice->getBooking()->getAssignedTechnician()->getName()
<< std::setw(10) << currentInvoice->getDiscountPercentage()
<< std::setw(12) << currentInvoice->getTotalAmount()
<< std::setw(20) << currentInvoice->getInvoiceDate().toString()
<< std::endl;
pendingInvoicesForPayment.insert(currentIndex++, currentInvoice);
}
}
if (pendingInvoicesForPayment.getSize() == 0)
{
std::cout << "No pending invoices available for payment.\n";
return "";
}
std::cout << "Select the Invoice to pay (Index): ";
util::read(choice);
int selectedIndex = pendingInvoicesForPayment.find(choice);
if (selectedIndex != -1)
{
const Invoice* selectedInvoice = pendingInvoicesForPayment.getValueAt(selectedIndex);
return selectedInvoice->getId();
}
else
{
std::cout << "Invalid choice.\n";
return "";
}
}
/*
Function: selectPaymentMode (static helper)
Description: Allows the customer to select a payment mode (ONLINE or OFFLINE).
Parameters:
- None
Returns:
- util::PaymentMode: Selected payment mode
*/
static util::PaymentMode selectPaymentMode()
{
int choice;
std::cout << "Enter the payment Mode\n1.OFFLINE\n2.ONLINE\nChoice: ";
util::read(choice);
if (choice == 1)
{
std::cout << "Offline mode selected.\n";
return util::PaymentMode::OFFLINE;
}
else if (choice == 2)
{
std::cout << "Online mode selected.\n";
return util::PaymentMode::ONLINE;
}
else
{
std::cout << "Invalid choice, Offline mode selected.\n";
return util::PaymentMode::OFFLINE;
}
}
/*
Function: completePayments
Description: Allows the customer to complete pending payments for invoices.
Validates invoice selection and payment mode before completing payment.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::completePayments()
{
util::clear();
util::Map<std::string, const Invoice*> currentInvoices = m_controller.getInvoicesByUser();
std::string selectedID = selectInvoiceFromUserForPayment(currentInvoices);
if (selectedID == "")
{
std::cout << "Payment failed.\n";
return;
}
util::PaymentMode paymentMode = selectPaymentMode();
m_controller.completePayment(selectedID, paymentMode);
std::cout << "Payment completed successfully.\n";
}
/*
Function: displayInvoices (static helper)
Description: Displays detailed information for all invoices associated with the customer,
including booking details, technician, discount, total amount, payment status, and items used.
Parameters:
- currentUserInvoices: util::Map<std::string, const Invoice*>, customers invoices
Returns:
- void
Throws:
- std::runtime_error if a null invoice is encountered
*/
static void displayInvoices(util::Map<std::string, const Invoice*> currentUserInvoices)
{
if (currentUserInvoices.getSize() == 0)
{
std::cout << "No invoices found for this account." << std::endl;
util::pressEnter();
return;
}
else
{
for (int index = 0; index < currentUserInvoices.getSize(); index++)
{
const Invoice* currentInvoice = currentUserInvoices.getValueAt(index);
if (currentInvoice)
{
std::cout << "\nInvoice Details\n";
std::cout << "Booking ID: " << currentInvoice->getBookingId() << std::endl;
std::cout << "Vehicle Brand: " << currentInvoice->getBooking()->getVehicleBrand() << std::endl;
std::cout << "Vehicle Number: " << currentInvoice->getBooking()->getVehicleNumber() << std::endl;
std::cout << "Technician ID: " << currentInvoice->getBooking()->getAssignedTechnician()->getId() << std::endl;
std::cout << "Technician Name: " << currentInvoice->getBooking()->getAssignedTechnician()->getName() << std::endl;
std::cout << "Discount(%): " << currentInvoice->getDiscountPercentage() << std::endl;
std::cout << "Total Amount: " << currentInvoice->getTotalAmount() << std::endl;
std::cout << "Invoice Date: " << currentInvoice->getInvoiceDate().toString() << std::endl;
std::cout << "Payment Status: " << util::getPaymentStatusString(currentInvoice->getStatus()) << std::endl;
auto inventoryItemsInInvoice = currentInvoice->getParts();
std::cout << "\nItems Used:\n";
std::cout << std::left
<< std::setw(20) << "ItemName"
<< std::setw(10) << "Quantity"
<< std::setw(10) << "Price"
<< std::endl;
std::cout << std::string(40, '-') << std::endl;
for (int iterator = 0; iterator < inventoryItemsInInvoice.getSize(); iterator++)
{
InventoryItem* currentItem = inventoryItemsInInvoice.getValueAt(iterator);
std::cout << std::left
<< std::setw(20) << currentItem->getPartName()
<< std::setw(10) << currentItem->getQuantity()
<< std::setw(10) << currentItem->getPrice()
<< std::endl;
}
}
else
{
throw std::runtime_error("Null invoice encountered while displaying invoices.");
}
}
}
}
/*
Function: viewInvoices
Description: Displays invoices associated with the customer by calling displayInvoices.
Parameters:
- None
Returns:
- void
*/
void CustomerMenu::viewInvoices()
{
util::clear();
util::Map<std::string, const Invoice*> currentUserInvoices = m_controller.getInvoicesByUser();
displayInvoices(currentUserInvoices);
}
void CustomerMenu::viewNotifications()