Merged PR 1127: Fix notification UI formatting, payment flow issues, and observer cleanup
Changes: - Fix notification table alignment issues in admin notification screens - Add proper spacing for notification title column display - Remove unnecessary tab spacing from Configure Notification Preferences heading - Change ServiceBooking ID prefix to avoid conflict with Service IDs - Remove unnecessary newline characters from service booking completion notifications - Detach removed users from all service observer lists during user removal - Fix Complete Payments screen clearing immediately after heading display - Improve table spacing in Complete Payments screen - Prevent invalid payment mode selection from defaulting to OFFLINE mode Fixes #1780 Fixes #1783 Fixes #1777 Fixes #1786 Related work items: #1777, #1780, #1783, #1786
This commit is contained in:
@@ -24,9 +24,10 @@ Parameters: None
|
|||||||
Returns: A new ServiceBooking object.
|
Returns: A new ServiceBooking object.
|
||||||
*/
|
*/
|
||||||
ServiceBooking::ServiceBooking()
|
ServiceBooking::ServiceBooking()
|
||||||
: m_id("SRV" + std::to_string(++m_uid)),
|
: m_id("SBK" + std::to_string(++m_uid)),
|
||||||
m_customer(nullptr),
|
m_customer(nullptr),
|
||||||
m_assignedTechnician(nullptr),
|
m_assignedTechnician(nullptr),
|
||||||
|
m_status(util::ServiceJobStatus::PENDING),
|
||||||
m_discountPercentage(0.0) {}
|
m_discountPercentage(0.0) {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -56,7 +57,7 @@ ServiceBooking::ServiceBooking(
|
|||||||
const std::string& vehicleModel,
|
const std::string& vehicleModel,
|
||||||
double discountPercentage
|
double discountPercentage
|
||||||
)
|
)
|
||||||
: m_id("SRV" + std::to_string(++m_uid)),
|
: m_id("SBK" + std::to_string(++m_uid)),
|
||||||
m_status(status),
|
m_status(status),
|
||||||
m_services(services),
|
m_services(services),
|
||||||
m_customerId(customerId),
|
m_customerId(customerId),
|
||||||
|
|||||||
+7
-4
@@ -833,6 +833,9 @@ void ServiceManagementService::createJobCard(const std::string& bookingID, const
|
|||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to create job card.");
|
throw std::runtime_error("Failed to create job card.");
|
||||||
}
|
}
|
||||||
|
title = "Technician assigned";
|
||||||
|
message = "A technician has been assigned to your Service Booking with ID " + bookingID;
|
||||||
|
sendNotification(currentBooking->getCustomer(), title, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1055,11 +1058,11 @@ void ServiceManagementService::completeJob(const std::string& jobID)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to complete the job, some error occured or job already completed.");
|
throw std::runtime_error("Failed to complete the job, some error occurred or job already completed.");
|
||||||
}
|
}
|
||||||
if (!jobStatusUpdated)
|
if (!jobStatusUpdated)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to complete the job, some error occured or job already completed.");
|
throw std::runtime_error("Failed to complete the job, some error occurred or job already completed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs);
|
serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs);
|
||||||
@@ -1067,8 +1070,8 @@ void ServiceManagementService::completeJob(const std::string& jobID)
|
|||||||
{
|
{
|
||||||
currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED);
|
currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED);
|
||||||
paymentManagementService.generateInvoice(currentJob->getBooking());
|
paymentManagementService.generateInvoice(currentJob->getBooking());
|
||||||
std::string title = "Service Booking completed,Invoice Generated.\n";
|
std::string title = "Service Booking completed,Invoice Generated.";
|
||||||
std::string message = "Services completed for the booking and invoice generated.\n";
|
std::string message = "Services completed for the booking and invoice generated.";
|
||||||
sendNotification(currentJob->getBooking()->getCustomer(), title, message);
|
sendNotification(currentJob->getBooking()->getCustomer(), title, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
@@ -297,6 +297,9 @@ Return type: void
|
|||||||
*/
|
*/
|
||||||
void UserManagementService::removeUser(const std::string& userID)
|
void UserManagementService::removeUser(const std::string& userID)
|
||||||
{
|
{
|
||||||
|
InventoryManagementService inventoryManagementService;
|
||||||
|
PaymentManagementService paymentManagementService;
|
||||||
|
ServiceManagementService serviceManagementService;
|
||||||
int index = m_dataStore.getUsers().find(userID);
|
int index = m_dataStore.getUsers().find(userID);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
@@ -304,6 +307,9 @@ void UserManagementService::removeUser(const std::string& userID)
|
|||||||
if (user != nullptr)
|
if (user != nullptr)
|
||||||
{
|
{
|
||||||
user->setState(util::State::INACTIVE);
|
user->setState(util::State::INACTIVE);
|
||||||
|
inventoryManagementService.detach(user);
|
||||||
|
paymentManagementService.detach(user);
|
||||||
|
serviceManagementService.detach(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,4 +21,28 @@ namespace util
|
|||||||
{
|
{
|
||||||
std::cout << "\x1B[2J\x1B[H" << std::flush;
|
std::cout << "\x1B[2J\x1B[H" << std::flush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: truncateString
|
||||||
|
Description:
|
||||||
|
Truncates a string if its length exceeds the given maximum length.
|
||||||
|
The truncated string ends with "..." to indicate omitted characters.
|
||||||
|
Parameters:
|
||||||
|
- text: const std::string&, input string to truncate
|
||||||
|
- maxLength: size_t, maximum allowed length of the returned string
|
||||||
|
Returns:
|
||||||
|
- std::string: Original string if within limit, otherwise truncated string with "..."
|
||||||
|
*/
|
||||||
|
inline std::string truncateString(const std::string& text, size_t maxLength)
|
||||||
|
{
|
||||||
|
if (text.length() <= maxLength)
|
||||||
|
{
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
if (maxLength <= 3)
|
||||||
|
{
|
||||||
|
return std::string(maxLength, '.');
|
||||||
|
}
|
||||||
|
return text.substr(0, maxLength - 3) + "...";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -327,19 +327,18 @@ Returns:
|
|||||||
*/
|
*/
|
||||||
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::clear();
|
|
||||||
int currentIndex = 1, choice;
|
int currentIndex = 1, choice;
|
||||||
util::Map<int, const Invoice*> pendingInvoicesForPayment;
|
util::Map<int, const Invoice*> pendingInvoicesForPayment;
|
||||||
std::cout << std::left
|
std::cout << std::left
|
||||||
<< std::setw(6) << "Index"
|
<< std::setw(8) << "Index"
|
||||||
<< std::setw(12) << "BookingID"
|
<< std::setw(15) << "Booking ID"
|
||||||
<< std::setw(15) << "VehicleBrand"
|
<< std::setw(20) << "Vehicle Brand"
|
||||||
<< std::setw(15) << "VehicleNumber"
|
<< std::setw(20) << "Vehicle Number"
|
||||||
<< std::setw(12) << "Technician ID"
|
<< std::setw(18) << "Technician ID"
|
||||||
<< std::setw(20) << "Technician Name"
|
<< std::setw(25) << "Technician Name"
|
||||||
<< std::setw(10) << "Discount(%)"
|
<< std::setw(15) << "Discount(%)"
|
||||||
<< std::setw(12) << "TotalAmount"
|
<< std::setw(15) << "TotalAmount"
|
||||||
<< std::setw(20) << "InvoiceDate"
|
<< std::setw(22) << "Invoice Timestamp"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
|
for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++)
|
||||||
{
|
{
|
||||||
@@ -348,17 +347,17 @@ inline std::string selectInvoiceFromUserForPayment(const util::Map<std::string,
|
|||||||
{
|
{
|
||||||
const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician();
|
const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician();
|
||||||
std::cout << std::left
|
std::cout << std::left
|
||||||
<< std::setw(6) << currentIndex
|
<< std::setw(8) << currentIndex
|
||||||
<< std::setw(12) << currentInvoice->getBookingId()
|
<< std::setw(15) << currentInvoice->getBookingId()
|
||||||
<< std::setw(15) << currentInvoice->getBooking()->getVehicleBrand()
|
<< std::setw(20) << currentInvoice->getBooking()->getVehicleBrand()
|
||||||
<< std::setw(15) << currentInvoice->getBooking()->getVehicleNumber()
|
<< std::setw(20) << currentInvoice->getBooking()->getVehicleNumber()
|
||||||
<< std::setw(12) << ((currentTechnician != nullptr && currentTechnician->getId() != "") ?
|
<< std::setw(18) << ((currentTechnician != nullptr && currentTechnician->getId() != "") ?
|
||||||
currentTechnician->getId() : "Null")
|
currentTechnician->getId() : "Null")
|
||||||
<< std::setw(20) << ((currentTechnician != nullptr && currentTechnician->getName() != "") ?
|
<< std::setw(25) << ((currentTechnician != nullptr && currentTechnician->getName() != "") ?
|
||||||
currentTechnician->getName() : "Null")
|
currentTechnician->getName() : "Null")
|
||||||
<< std::setw(10) << currentInvoice->getDiscountPercentage()
|
<< std::setw(15) << currentInvoice->getDiscountPercentage()
|
||||||
<< std::setw(12) << currentInvoice->getTotalAmount()
|
<< std::setw(15) << currentInvoice->getTotalAmount()
|
||||||
<< std::setw(20) << currentInvoice->getInvoiceDate().toString()
|
<< std::setw(22) << currentInvoice->getInvoiceDate().toString()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
pendingInvoicesForPayment.insert(currentIndex++, currentInvoice);
|
pendingInvoicesForPayment.insert(currentIndex++, currentInvoice);
|
||||||
}
|
}
|
||||||
@@ -394,6 +393,9 @@ Returns:
|
|||||||
inline util::PaymentMode selectPaymentMode()
|
inline util::PaymentMode selectPaymentMode()
|
||||||
{
|
{
|
||||||
int choice;
|
int choice;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
util::clear();
|
||||||
std::cout << "Enter the payment Mode\n1.OFFLINE\n2.ONLINE\nChoice: ";
|
std::cout << "Enter the payment Mode\n1.OFFLINE\n2.ONLINE\nChoice: ";
|
||||||
util::read(choice);
|
util::read(choice);
|
||||||
if (choice == 1)
|
if (choice == 1)
|
||||||
@@ -408,8 +410,9 @@ inline util::PaymentMode selectPaymentMode()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "Invalid choice. Offline mode selected.\n";
|
std::cout << "Invalid choice. Try again.\n";
|
||||||
return util::PaymentMode::OFFLINE;
|
util::pressEnter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,9 +556,9 @@ inline const Notification* selectNotification(const util::Vector<const Notificat
|
|||||||
{
|
{
|
||||||
util::Map<int, const Notification*> indexedNotifications;
|
util::Map<int, const Notification*> indexedNotifications;
|
||||||
std::cout << std::left
|
std::cout << std::left
|
||||||
<< std::setw(6) << "Index"
|
<< std::setw(10) << "Index"
|
||||||
<< std::setw(15) << "ID"
|
<< std::setw(15) << "ID"
|
||||||
<< std::setw(30) << "Title"
|
<< std::setw(35) << "Title"
|
||||||
<< std::setw(25) << "Timestamp"
|
<< std::setw(25) << "Timestamp"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
int currentIndex = 1;
|
int currentIndex = 1;
|
||||||
@@ -565,9 +568,9 @@ inline const Notification* selectNotification(const util::Vector<const Notificat
|
|||||||
if (currentNotification)
|
if (currentNotification)
|
||||||
{
|
{
|
||||||
std::cout << std::left
|
std::cout << std::left
|
||||||
<< std::setw(6) << currentIndex
|
<< std::setw(10) << currentIndex
|
||||||
<< std::setw(15) << currentNotification->getId()
|
<< std::setw(15) << currentNotification->getId()
|
||||||
<< std::setw(35) << currentNotification->getTitle()
|
<< std::setw(35) << util::truncateString(currentNotification->getTitle(), 30)
|
||||||
<< std::setw(25) << currentNotification->getCreatedAt().toString()
|
<< std::setw(25) << currentNotification->getCreatedAt().toString()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
indexedNotifications.insert(currentIndex, currentNotification);
|
indexedNotifications.insert(currentIndex, currentNotification);
|
||||||
@@ -780,7 +783,6 @@ inline const Service* selectServiceFromServices(const util::Map<std::string, con
|
|||||||
util::Map<int, const Service*> activeServicesMap;
|
util::Map<int, const Service*> activeServicesMap;
|
||||||
int currentIndex = 1;
|
int currentIndex = 1;
|
||||||
int userInputIndex;
|
int userInputIndex;
|
||||||
std::cout << std::endl;
|
|
||||||
std::cout << std::left
|
std::cout << std::left
|
||||||
<< std::setw(10) << "Index"
|
<< std::setw(10) << "Index"
|
||||||
<< std::setw(15) << "Service ID"
|
<< std::setw(15) << "Service ID"
|
||||||
@@ -886,7 +888,7 @@ inline bool getNotificationPreference(const std::string& serviceName)
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
util::clear();
|
util::clear();
|
||||||
std::cout << " Configure Notification Preferences\n";
|
std::cout << "Configure Notification Preferences\n";
|
||||||
std::cout << "\n" << serviceName << " Notifications\n";
|
std::cout << "\n" << serviceName << " Notifications\n";
|
||||||
std::cout << "1. Enable Notifications\n";
|
std::cout << "1. Enable Notifications\n";
|
||||||
std::cout << "2. Disable Notifications\n";
|
std::cout << "2. Disable Notifications\n";
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ Author: Trenser
|
|||||||
Date:19-May-2026
|
Date:19-May-2026
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
#include "Enums.h"
|
#include "Enums.h"
|
||||||
#include "InputHelper.h"
|
#include "InputHelper.h"
|
||||||
#include "OutputHelper.h"
|
#include "OutputHelper.h"
|
||||||
@@ -23,6 +25,8 @@ Return type: void
|
|||||||
*/
|
*/
|
||||||
void UserInterface::run()
|
void UserInterface::run()
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
m_controller.loadSystemData();
|
m_controller.loadSystemData();
|
||||||
m_controller.runSystemChecks();
|
m_controller.runSystemChecks();
|
||||||
bool isMenuActive = true;
|
bool isMenuActive = true;
|
||||||
@@ -46,6 +50,19 @@ void UserInterface::run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_controller.saveSystemData();
|
m_controller.saveSystemData();
|
||||||
|
}
|
||||||
|
catch (const std::invalid_argument& exception)
|
||||||
|
{
|
||||||
|
std::cout << "Exception: Invalid Argument: " << exception.what() << std::endl;
|
||||||
|
}
|
||||||
|
catch (const std::exception& exception)
|
||||||
|
{
|
||||||
|
std::cout << "Exception: " << exception.what() << std::endl;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::cout << "Unknown error occurred." << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user