diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index f1ca400..3b674ed 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp @@ -409,10 +409,8 @@ void Controller::removeUser(const std::string& userID) User* user = m_userManagementService.getUser(userID); if (!user) { - throw std::runtime_error("Error User not Found.\n"); + throw std::runtime_error("Error: User not Found.\n"); } - m_serviceManagementService.cancelCustomerServiceBookings(userID); - m_serviceManagementService.cancelTechnicianJobs(userID); m_userManagementService.removeUser(userID); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp index 80e167d..2733577 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp @@ -294,7 +294,7 @@ void PaymentManagementService::generateInvoice(ServiceBooking* booking) { throw std::runtime_error("Invoice generation failed: booking is null."); } - double totalLabourCost = 0, totalPartsCost = 0, totalServiceCost = 0; + double totalLaborCost = 0, totalPartsCost = 0, totalServiceCost = 0; double discountPercentage = booking->getDiscountPercentage(); std::string bookingID = booking->getId(); util::Map servicesInTheBookedService = booking->getServices(); @@ -303,9 +303,10 @@ void PaymentManagementService::generateInvoice(ServiceBooking* booking) for (int iterator = 0; iterator < currentJobCards.getSize(); iterator++) { JobCard* currentJobCard = currentJobCards.getValueAt(iterator); - if (currentJobCard->getBookingId() == bookingID && currentJobCard->getStatus() != util::ServiceJobStatus::COMPLETED) + util::ServiceJobStatus currentJobCardStatus = currentJobCard->getStatus(); + if (currentJobCard->getBookingId() == bookingID && currentJobCardStatus != util::ServiceJobStatus::CANCELLED && currentJobCardStatus != util::ServiceJobStatus::COMPLETED) { - throw std::runtime_error("Invoice generation failed: not all job cards are completed for booking '" + bookingID + "'."); + throw std::runtime_error("Invoice generation failed: Not all job cards are completed for booking '" + bookingID + "'."); } } for (int iterator = 0; iterator < servicesInTheBookedService.getSize(); iterator++) @@ -314,13 +315,13 @@ void PaymentManagementService::generateInvoice(ServiceBooking* booking) if (currentService) { createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService); - totalLabourCost += currentService->getLaborCost(); + totalLaborCost += currentService->getLaborCost(); totalPartsCost += util::calculatePartsCost(currentService); } } - totalServiceCost = totalLabourCost + totalPartsCost; + totalServiceCost = totalLaborCost + totalPartsCost; totalServiceCost -= (totalServiceCost * (discountPercentage / 100)); - Invoice* invoice = Factory::getObject(bookingID, booking, util::Timestamp(), totalLabourCost, completeInventoryItemMapOfBooking, totalPartsCost, discountPercentage, totalServiceCost, util::Timestamp(), util::PaymentMode::NOTSET, util::PaymentStatus::PENDING); + Invoice* invoice = Factory::getObject(bookingID, booking, util::Timestamp(), totalLaborCost, completeInventoryItemMapOfBooking, totalPartsCost, discountPercentage, totalServiceCost, util::Timestamp(), util::PaymentMode::NOTSET, util::PaymentStatus::PENDING); util::Map& currentInvoices = m_dataStore.getInvoices(); currentInvoices.insert(invoice->getId(), invoice); } @@ -375,7 +376,7 @@ void PaymentManagementService::completePayment(const std::string& invoiceID, uti invoice->setStatus(util::PaymentStatus::COMPLETED); std::string title, message; title = "Payment successful"; - message = "Payment successful for invoice ID " + invoiceID; + message = "Payment successful for Invoice ID " + invoiceID; sendNotification(currentUser, title, message); } } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index b4fbc22..5cd870b 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -507,6 +507,89 @@ void ServiceManagementService::saveObservers() util::saveObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this); } +/* +Function: restoreInventory +Description: Restores inventory quantities for all required items in the services associated + with a given booking. Each item's quantity is incremented by a fixed value. +Parameter: ServiceBooking* booking - Pointer to the booking whose inventory items need to be restored +Return type: void +*/ +static void restoreInventory(ServiceBooking* booking) +{ + const int INCREMENT_VALUE = 1; + if (!booking) + { + return; + } + const auto& services = booking->getServices(); + for (int serviceIterator = 0; serviceIterator < services.getSize(); ++serviceIterator) + { + Service* service = services.getValueAt(serviceIterator); + if (!service) + { + continue; + } + const auto& items = service->getRequiredInventoryItems(); + for (int InventoryIterator = 0; InventoryIterator < items.getSize(); ++InventoryIterator) + { + InventoryItem* item = items.getValueAt(InventoryIterator); + if (item) + { + item->setQuantity(item->getQuantity() + INCREMENT_VALUE); + } + } + } +} + +/* +Function: processBookingCancellation +Description: Cancels jobs and updates the status of a given booking. Sends notifications to the + specified user, resets technician assignment if needed, and restores inventory items. +Parameter: ServiceBooking* booking - Pointer to the booking being cancelled + util::ServiceJobStatus newServiceBookingStatus - New status to assign to the booking + const std::string& notificationTitle - Title of the booking cancellation notification + const std::string& notificationMessage - Message body of the booking cancellation notification + User* notifyUser - User to notify about the cancellation + util::ServiceJobStatus jobCardStatus - New status to assign to associated job cards + const std::string& jobNotificationTitle - Title of the job cancellation notification + const std::string& jobNotificationMessage - Message body of the job cancellation notification + util::Map& jobs - Collection of job cards to update + ServiceManagementService& currentService - Reference to the service for sending notifications +Return type: void +*/ +static void processBookingCancellation(ServiceBooking* booking, + util::ServiceJobStatus newServiceBookingStatus, + const std::string& notificationTitle, + const std::string& notificationMessage, + User* notifyUser, + util::ServiceJobStatus jobCardStatus, + const std::string& jobNotificationTitle, + const std::string& jobNotificationMessage, + util::Map& jobs, ServiceManagementService& currentService) +{ + if (!booking || !notifyUser) + { + return; + } + for (int jobIterator = 0; jobIterator < jobs.getSize(); ++jobIterator) + { + JobCard* jobCard = jobs.getValueAt(jobIterator); + if (jobCard && jobCard->getBookingId() == booking->getId()) + { + jobCard->setStatus(jobCardStatus); + currentService.sendNotification(notifyUser, jobNotificationTitle, jobNotificationMessage); + } + } + booking->setStatus(newServiceBookingStatus); + currentService.sendNotification(notifyUser, notificationTitle, notificationMessage); + if (newServiceBookingStatus == util::ServiceJobStatus::PENDING) + { + booking->setAssignedTechnician(nullptr); + booking->setAssignedTechnicianId(""); + } + restoreInventory(booking); +} + /* Function: cancelCustomerServiceBookings Description: Cancels all service bookings associated with a given customer or technician. @@ -515,69 +598,47 @@ Description: Cancels all service bookings associated with a given customer or te Parameter: const std::string& userID - ID of the customer or technician Return type: void */ -void ServiceManagementService::cancelCustomerServiceBookings(const std::string& userID) +void ServiceManagementService::cancelCustomerServiceBookings(const std::string& customerID) { - const int INCREMENT_VALUE = 1; auto& users = m_dataStore.getUsers(); - int userIndex = users.find(userID); + int userIndex = users.find(customerID); if (userIndex == -1) { - throw std::runtime_error("User not found: " + userID); + throw std::runtime_error("User not found: " + customerID); } - User* user = users.getValueAt(userIndex); - if (user == nullptr) + User* customer = users.getValueAt(userIndex); + if (!customer) { - throw std::runtime_error("User not found: " + userID); + throw std::runtime_error("User not found: " + customerID); } - util::UserType type = user->getUserType(); - auto& bookings = DataStore::getInstance().getServiceBookings(); - for (int bookingIterator = 0; bookingIterator < bookings.getSize(); bookingIterator++) + auto& bookings = m_dataStore.getServiceBookings(); + auto& jobs = m_dataStore.getJobCards(); + for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++) { - ServiceBooking* booking = bookings.getValueAt(bookingIterator); - if (booking != nullptr && - (booking->getCustomerId() == userID || booking->getAssignedTechnicianId() == userID)) + ServiceBooking* booking = bookings.getValueAt(iteratorOne); + if (!booking) { - if (booking->getStatus() == util::ServiceJobStatus::PENDING || - booking->getStatus() == util::ServiceJobStatus::STARTED) - { - if (type == util::UserType::CUSTOMER) - { - booking->setStatus(util::ServiceJobStatus::CANCELLED); - booking->setCustomer(nullptr); - booking->setCustomerId(""); - User* assignedTechnician = booking->getAssignedTechnician(); - std::string title = "Customer Service Cancelled"; - std::string message = "The customer has cancelled their service booking. Your assigned job card has been cancelled and the inventory has been restocked."; - sendNotification(assignedTechnician, title, message); - } - else if (type == util::UserType::TECHNICIAN) - { - booking->setStatus(util::ServiceJobStatus::PENDING); - std::string title = "Technician Unavailable"; - 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."; - sendNotification(booking->getCustomer(), title, message); - } - booking->setAssignedTechnician(nullptr); - booking->setAssignedTechnicianId(""); - const auto& ListOfServices = booking->getServices(); - for (int serviceIterator = 0; serviceIterator < ListOfServices.getSize(); serviceIterator++) - { - Service* service = ListOfServices.getValueAt(serviceIterator); - if (service != nullptr) - { - const auto& items = service->getRequiredInventoryItems(); - for (int itemIterator = 0; itemIterator < items.getSize(); itemIterator++) - { - InventoryItem* item = items.getValueAt(itemIterator); - if (item != nullptr) - { - item->setQuantity(item->getQuantity() + INCREMENT_VALUE); - } - } - } - } - } + continue; } + if (booking->getCustomerId() != customerID) + { + continue; + } + if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED) + { + continue; + } + User* assignedTechnician = booking->getAssignedTechnician(); + 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 + ); } } @@ -590,34 +651,48 @@ Return type: void */ void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID) { - const int INCREMENT_VALUE = 1; - auto& jobs = m_dataStore.getJobCards(); - for (int jobIterator = 0; jobIterator < jobs.getSize(); jobIterator++) + auto& users = m_dataStore.getUsers(); + int userIndex = users.find(technicianID); + if (userIndex == -1) { - JobCard* job = jobs.getValueAt(jobIterator); - if (job != nullptr && job->getTechnicianId() == technicianID) + throw std::runtime_error("User not found: " + technicianID); + } + User* technician = users.getValueAt(userIndex); + if (!technician) + { + throw std::runtime_error("User not found: " + technicianID); + } + auto& bookings = m_dataStore.getServiceBookings(); + auto& jobs = m_dataStore.getJobCards(); + for (int iteratorOne = 0; iteratorOne < bookings.getSize(); iteratorOne++) + { + ServiceBooking* booking = bookings.getValueAt(iteratorOne); + if (!booking) { - if (job->getStatus() == util::ServiceJobStatus::PENDING || job->getStatus() == util::ServiceJobStatus::STARTED) - { - job->setStatus(util::ServiceJobStatus::CANCELLED); - std::string title = "Job Cancelled"; - std::string message = "The Job has cancelled. Your job card has been cancelled and the inventory has been restocked."; - sendNotification(job->getTechnician(), title, message); - Service* service = job->getService(); - if (service != nullptr) - { - const auto& items = service->getRequiredInventoryItems(); - for (int itemIterator = 0; itemIterator < items.getSize(); itemIterator++) - { - InventoryItem* item = items.getValueAt(itemIterator); - if (item != nullptr) - { - item->setQuantity(item->getQuantity() + INCREMENT_VALUE); - } - } - } - } + continue; } + std::string technicianId = booking->getAssignedTechnicianId(); + if (technicianId != technicianID) + { + continue; + } + if (booking->getStatus() != util::ServiceJobStatus::PENDING && booking->getStatus() != util::ServiceJobStatus::STARTED) + { + continue; + } + User* customer = booking->getCustomer(); + if (!customer) + { + continue; + } + std::string title = "Technician Unavailable"; + 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 + ); } } @@ -1069,7 +1144,7 @@ void ServiceManagementService::completeJob(const std::string& jobID) { currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED); paymentManagementService.generateInvoice(currentJob->getBooking()); - std::string title = "Service Booking completed,Invoice Generated."; + 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); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 84fa7aa..8ba68d0 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -306,6 +306,14 @@ void UserManagementService::removeUser(const std::string& userID) User* user = m_dataStore.getUsers().getValueAt(index); if (user != nullptr) { + if (user->getUserType() == util::UserType::CUSTOMER) + { + serviceManagementService.cancelCustomerServiceBookings(userID); + } + if (user->getUserType() == util::UserType::TECHNICIAN) + { + serviceManagementService.cancelTechnicianJobs(userID); + } user->setState(util::State::INACTIVE); inventoryManagementService.detach(user); paymentManagementService.detach(user); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index bb7e995..b81074e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -263,6 +263,7 @@ Return type: void void AdminMenu::removeInventoryItem() { util::clear(); + std::cout << "Remove Inventory Item\n"; auto inventoryItems = m_controller.getInventoryItems(); auto activeItems = filterActiveItems(inventoryItems); int activeItemsSize = activeItems.getSize(); @@ -402,6 +403,11 @@ void AdminMenu::createService() util::Map activeInventoryItems = filterActiveItems(currentInventoryItems); util::Vector selectedInventoryItems; selectInventoryItems(activeInventoryItems,selectedInventoryItems); + if (selectedInventoryItems.isEmpty()) + { + util::pressEnter(); + return; + } std::cout << "\nEnter the labour cost: "; util::read(labourCost); m_controller.createService(serviceName, selectedInventoryItems, labourCost); @@ -428,7 +434,7 @@ void AdminMenu::removeService() if (selectedServiceID != "") { m_controller.removeService(selectedServiceID); - std::cout << "Service removed sucessfully.\n\n"; + std::cout << "Service removed successfully.\n\n"; } else { @@ -541,7 +547,7 @@ void AdminMenu::createComboPackages() while (true) { chosenService = selectServiceFromServices(activeServices); - if (chosenService == nullptr) + if (!chosenService) { std::cout << "Failed to create combo package!\n\n"; util::pressEnter(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h index 9703042..cd968eb 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -49,7 +49,7 @@ inline std::string selectServicesToRemove(util::Map std::cout << std::left << std::setw(6) << "Index" << std::setw(12) << "Service ID" - << std::setw(20) << "Name" + << std::setw(35) << "Name" << std::setw(10) << "Labor Cost" << std::endl; for (int iterator = 0; iterator < currentServices.getSize(); iterator++) @@ -62,7 +62,7 @@ inline std::string selectServicesToRemove(util::Map std::cout << std::left << std::setw(6) << currentIndex << std::setw(12) << currentService->getId() - << std::setw(20) << currentService->getName() + << std::setw(35) << util::truncateString(currentService->getName(), 30) << std::setw(10) << currentService->getLaborCost() << std::endl; currentServicesMap.insert(currentIndex++, currentService); @@ -94,13 +94,15 @@ inline void selectInventoryItems(util::Map& c bool doRun = true; util::Map currentInventoryMap; int choice; - if (currentInventoryItems.getSize() == 0) + if (currentInventoryItems.isEmpty()) { std::cout << "No Items Present, Inventory empty.\n"; return; } while (doRun) { + util::clear(); + std::cout << "Create Service\n"; std::cout << "\nSelect Required Items\n"; bool hasInventoryItems = false; int currentIndex = 1; @@ -119,6 +121,19 @@ inline void selectInventoryItems(util::Map& c { continue; } + bool alreadySelected = false; + for (int iteratorOne = 0; iteratorOne < selectedInventoryItems.getSize(); iteratorOne++) + { + if (selectedInventoryItems[iteratorOne] == currentInventoryItem->getId()) + { + alreadySelected = true; + break; + } + } + if (alreadySelected) + { + continue; + } std::cout << std::left << std::setw(6) << currentIndex << std::setw(12) << currentInventoryItem->getId() @@ -133,10 +148,9 @@ inline void selectInventoryItems(util::Map& c { break; } - std::cout << "Select the item (Index) or enter -1 to exit: "; + std::cout << "Select the item (Index) or enter 0 to exit: "; util::read(choice); - - if (choice == -1) + if (choice == 0) { doRun = false; } @@ -144,6 +158,7 @@ inline void selectInventoryItems(util::Map& c { selectedInventoryItems.push_back(currentInventoryMap.getValueAt(currentInventoryMap.find(choice))->getId()); std::cout << "Item added successfully.\n" << std::endl; + util::pressEnter(); } else { @@ -840,6 +855,7 @@ inline void displayAllActiveUsers(util::Map& activeUse std::cout << std::left << std::setw(10) << "Index" << std::setw(15) << "User ID" << std::setw(25) << "Username" + << std::setw(25) << "Full Name" << std::setw(25) << "User Type" << std::endl; for (int iterator = 0; iterator < activeUserCount; iterator++) @@ -850,6 +866,7 @@ inline void displayAllActiveUsers(util::Map& activeUse std::cout << std::left << std::setw(10) << (iterator + 1) << std::setw(15) << user->getId() << std::setw(25) << user->getUserName() + << std::setw(25) << user->getName() << std::setw(25) << util::getUserTypeString(user->getUserType()) << std::endl; } @@ -1066,7 +1083,7 @@ inline util::Map filterActiveItems(const util for (int index = 0; index < inventorySize; index++) { const InventoryItem* item = inventoryItems.getValueAt(index); - if (item != nullptr && item->getState() != util::State::INACTIVE) + if (item && item->getState() != util::State::INACTIVE) { activeItems.insert(item->getId(), item); } @@ -1171,21 +1188,21 @@ inline void displayComboPackagesWithIndex(util::Map& c const ComboPackage* currentComboPackage = currentComboPackageIndexMap.getValueAt(iterator); if (currentComboPackage == nullptr) { - throw std::runtime_error("Error accessing the combopackage.\n"); + throw std::runtime_error("Error accessing the combo package.\n"); } if (iterator == 0) { std::cout << std::left << std::setw(8) << "Index" << std::setw(10) << "ID" - << std::setw(20) << "Package Name" + << std::setw(35) << "Package Name" << std::setw(15) << "Discount (%)" << "\n"; } std::cout << std::left << std::setw(8) << currentComboPackageIndexMap.getKeyAt(iterator) << std::setw(10) << currentComboPackage->getId() - << std::setw(20) << currentComboPackage->getPackageName() + << std::setw(35) << util::truncateString(currentComboPackage->getPackageName(), 30) << std::setw(15) << currentComboPackage->getDiscountPercentage() << "\n"; }