diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.cpp index eff3229..3db950c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.cpp @@ -1,7 +1,24 @@ +/* +File: Trenser.VehicleServiceSystem.cpp +Description: Entry point for the Vehicle Service Management System. + Initializes the UserInterface and starts the application loop. +Author: Trenser +Date: 19-May-2026 +*/ + #include "UserInterface.h" +/* +Function: main +Description: The main entry point of the application. + Creates a UserInterface object and invokes the run method to start the system. +Parameters: + - None +Returns: + - int: Exit status code (0 for successful execution). +*/ int main() { UserInterface userInterface; userInterface.run(); -} +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj index a65c46d..8627061 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj @@ -171,15 +171,21 @@ + + + + + + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters index 77d0509..73b9291 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj.filters @@ -233,5 +233,23 @@ Header Files\Models + + Header Files\Utilities + + + Header Files\Utilities + + + Header Files\Utilities + + + Header Files\Utilities + + + Header Files\Utilities + + + Header Files\Views + \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index d536e8a..3b674ed 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp @@ -1,147 +1,617 @@ +/* +File: Controller.cpp +Description: Implementation file containing the method definitions of the + Controller class, including authentication, user creation, + service purchasing, and system checks. +Author: Trenser +Date:19-May-2026 +*/ +#include "ComboPackage.h" #include "Controller.h" +#include "Enums.h" +#include "InventoryItem.h" +#include "Invoice.h" +#include "JobCard.h" +#include "Service.h" +#include "ServiceBooking.h" +#include "User.h" +#include +/* +Function: login +Description: Authenticates a user by delegating to the authentication management service. +Parameter: const std::string& username - user’s username + const std::string& password - user’s password +Return type: bool - true if login successful, false otherwise +*/ bool Controller::login(const std::string& username, const std::string& password) { - return false; + return m_authenticationManagementService.login(username, password); } +/* +Function: logout +Description: Logs out the currently authenticated user. +Parameter: None +Return type: void +*/ void Controller::logout() { + m_authenticationManagementService.logout(); } +/* +Function: changePassword +Description: Changes the password of the currently authenticated user. +Parameter: const std::string& newPassword - new password to set +Return type: void +*/ void Controller::changePassword(const std::string& newPassword) { + m_authenticationManagementService.changePassword(newPassword); } -void Controller::createCustomer(const std::string& username, const std::string& password, const std::string& email, const std::string& phone) +/* +Function: createCustomer +Description: Creates a new customer account with the provided details. +Parameter: const std::string& username - customer’s username + const std::string& name - customer’s name + const std::string& password - customer’s password + const std::string& email - customer’s email + const std::string& phone - customer’s phone number +Return type: void +*/ + +void Controller::createCustomer(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone) { + m_userManagementService.createUser(username, name, password, email, phone, util::UserType::CUSTOMER); } +/* +Function: getAuthenticatedUser +Description: Retrieves the currently authenticated user. +Parameter: None +Return type: const User* - pointer to the authenticated user +*/ const User* Controller::getAuthenticatedUser() { - return nullptr; + return m_authenticationManagementService.getAuthenticatedUser(); } -void Controller::createTechnician(const std::string& username, const std::string& password, const std::string& email, const std::string& phone) +/* +Function: createTechnician +Description: Creates a new technician account with provided details by + delegating to the user management service. +Parameter: const std::string& username - technician's username + const std::string& password - technician's password + const std::string& email - technician's email address + const std::string& phoneNumber - technician's phone number +Return type: void +*/ +void Controller::createTechnician(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phoneNumber) { + m_userManagementService.createUser(username, name, password, email, phoneNumber, util::UserType::TECHNICIAN); } +/* +Function: updateUserDetails +Description: Updates the email and phone details of the currently authenticated user. +Parameter: const std::string& email - new email address + const std::string& phone - new phone number +Return type: void +*/ void Controller::updateUserDetails(const std::string& email, const std::string& phone) { + User* authenticatedUser = m_authenticationManagementService.getAuthenticatedUser(); + if (authenticatedUser == nullptr) + { + throw std::runtime_error("No user currently logged in!"); + } + m_userManagementService.updateUserDetails(authenticatedUser->getId(), email, phone); } +/* +Function: getServices +Description: Retrieves all available services in read-only form. +Parameters: + - None +Returns: + - util::Map containing all services +*/ util::Map Controller::getServices() { - return util::Map(); + util::Map currentServices = m_serviceManagementService.getServices(); + util::Map readOnlyServices; + for (int iterator = 0; iterator < currentServices.getSize(); iterator++) + { + readOnlyServices.insert(currentServices.getValueAt(iterator)->getId(), currentServices.getValueAt(iterator)); + } + return readOnlyServices; } +/* +Function: getComboPackages +Description: Retrieves all available combo packages from the service + management service and constructs a read-only map. +Parameter: None +Return type: util::Map +*/ util::Map Controller::getComboPackages() { - return util::Map(); + util::Map currentAvailableComboPackages = m_serviceManagementService.getComboPackages(); + util::Map readOnlyComboPackages; + for (int iterator = 0; iterator < currentAvailableComboPackages.getSize(); iterator++) + { + ComboPackage* currentComboPackage = currentAvailableComboPackages.getValueAt(iterator); + if (currentComboPackage) + { + readOnlyComboPackages.insert(currentComboPackage->getId(), currentComboPackage); + } + } + return readOnlyComboPackages; } +/* +Function: purchaseService +Description: Purchases one or more services for a vehicle by delegating to the service management service. +Parameter: const util::Vector& serviceIDs - IDs of services to purchase + const std::string& vehicleNumber - vehicle registration number + const std::string& vehicleBrand - brand of the vehicle + const std::string& vehicleModel - model of the vehicle +Return type: void +*/ void Controller::purchaseService(const util::Vector& serviceIDs, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel) { + m_serviceManagementService.purchaseService(serviceIDs, vehicleNumber, vehicleBrand, vehicleModel); } +/* +Function: purchaseComboPackage +Description: Purchases a combo package for a vehicle by delegating to the service management service. +Parameter: const std::string& comboPackageID - ID of the combo package + const std::string& vehicleNumber - vehicle registration number + const std::string& vehicleBrand - brand of the vehicle + const std::string& vehicleModel - model of the vehicle +Return type: void +*/ void Controller::purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel) { + m_serviceManagementService.purchaseComboPackage(comboPackageID, vehicleNumber, vehicleBrand, vehicleModel); } +/* +Function: getInventoryItems +Description: Retrieves all inventory items from the inventory management service + and constructs a read-only map for external use. +Parameter: None +Return type: util::Map +*/ util::Map Controller::getInventoryItems() { - return util::Map(); + auto inventoryItems = m_inventoryManagementService.getInventoryItems(); + util::Map readOnlyInventoryItems; + int inventoryItemsMapSize = inventoryItems.getSize(); + for (int index = 0; index < inventoryItemsMapSize; index++) + { + readOnlyInventoryItems.insert(inventoryItems.getKeyAt(index), inventoryItems.getValueAt(index)); + } + return readOnlyInventoryItems; } +/* +Function: getInventoryItem +Description: Retrieves a specific inventory item by its ID from the inventory management service. +Parameter: const std::string& inventoryItemID - ID of the inventory item +Return type: const InventoryItem* +*/ const InventoryItem* Controller::getInventoryItem(const std::string& inventoryItemID) { - return nullptr; + return m_inventoryManagementService.getInventoryItem(inventoryItemID); } +/* +Function: addInventoryItem +Description: Adds a new inventory item with specified details to the inventory management service. +Parameter: const std::string& partName - name of the part + int quantity - quantity of the part + double price - price of the part +Return type: void +*/ void Controller::addInventoryItem(const std::string& partName, int quantity, double price) { + m_inventoryManagementService.addInventoryItem(partName, quantity, price); } +/* +Function: removeInventoryItem +Description: Removes an inventory item from the inventory management service by its ID. +Parameter: const std::string& inventoryItemID - ID of the inventory item +Return type: void +*/ void Controller::removeInventoryItem(const std::string& inventoryItemID) { + m_inventoryManagementService.removeInventoryItem(inventoryItemID); } +/* +Function: addInventoryItemStock +Description: Adds stock to an existing inventory item in the inventory management service. +Parameter: const std::string& selectedItemId - ID of the inventory item + int quantity - quantity to add +Return type: void +*/ +void Controller::addInventoryItemStock(const std::string& selectedItemId, int quantity) +{ + m_inventoryManagementService.addInventoryItemStock(selectedItemId, quantity); +} + +/* +Function: getServiceBookings +Description: Retrieves all service bookings in read-only form. +Parameters: + - None +Returns: + - util::Map containing service bookings +*/ util::Map Controller::getServiceBookings() { - return util::Map(); + auto serviceBookings = m_serviceManagementService.getServiceBookings(); + util::Map readOnlyServiceBookings; + for (int iterator = 0; iterator < serviceBookings.getSize(); iterator++) + { + readOnlyServiceBookings.insert(serviceBookings.getKeyAt(iterator), serviceBookings.getValueAt(iterator)); + } + return readOnlyServiceBookings; } +/* +Function: getServiceBookingsByUser +Description: Retrieves all service bookings for a specific user. +Parameters: + - userID: std::string, the user ID +Returns: + - util::Map containing bookings for the user +*/ util::Map Controller::getServiceBookingsByUser(const std::string userID) { - return util::Map(); + util::Map readOnlyServiceBookingsByUserMap; + util::Map currentServiceBookingsByUser = m_serviceManagementService.getServiceBookings(userID); + for (int iterator = 0; iterator < currentServiceBookingsByUser.getSize(); iterator++) + { + readOnlyServiceBookingsByUserMap.insert(currentServiceBookingsByUser.getValueAt(iterator)->getId(), currentServiceBookingsByUser.getValueAt(iterator)); + } + return readOnlyServiceBookingsByUserMap; } +/* +Function: getUsers +Description: Retrieves all users from the user management service and + constructs a read-only map. +Parameter: None +Return type: util::Map +*/ util::Map Controller::getUsers() { - return util::Map(); + auto listOfUsers = m_userManagementService.getUsers(); + util::Map readOnlyUserList; + for (int iterator = 0; iterator < listOfUsers.getSize(); iterator++) + { + readOnlyUserList.insert(listOfUsers.getKeyAt(iterator), listOfUsers.getValueAt(iterator)); + } + return readOnlyUserList; } +/* +Function: getUsers +Description: Retrieves users filtered by user type. +Parameters: + - userType: util::UserType, type of user (CUSTOMER, TECHNICIAN, ADMIN) +Returns: + - util::Map containing users of the specified type +*/ util::Map Controller::getUsers(util::UserType userType) { - return util::Map(); + auto userMap = m_userManagementService.getUsers(userType); + util::Map readOnlyUserMap; + for (int iterator = 0; iterator < userMap.getSize(); iterator++) + { + readOnlyUserMap.insert(userMap.getKeyAt(iterator), userMap.getValueAt(iterator)); + } + return readOnlyUserMap; } +/* +Function: createJobCard +Description: Creates a job card for a service booking assigned to a technician. +Parameters: + - bookingID: std::string, ID of the service booking + - technicianID: std::string, ID of the technician + - serviceID: std::string, ID of the service +Returns: + - void +*/ void Controller::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID) { + m_serviceManagementService.createJobCard(bookingID, technicianID, serviceID); } +/* +Function: createService +Description: Creates a new service with associated inventory items and labor cost. +Parameters: + - name: std::string, name of the service + - inventoryItemIDs: Vector of inventory item IDs + - laborCost: double, labor cost +Returns: + - void +*/ void Controller::createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost) { + m_serviceManagementService.createService(name, inventoryItemIDs, laborCost); } +/* +Function: removeService +Description: Removes a service from the system by ID. +Parameters: + - serviceID: std::string, ID of the service +Returns: + - void +*/ void Controller::removeService(const std::string& serviceID) { + m_serviceManagementService.removeService(serviceID); } +/* +Function: getJobCardsByUser +Description: Retrieves job cards assigned to the authenticated technician. +Parameters: + - None +Returns: + - util::Map containing job cards +*/ util::Map Controller::getJobCardsByUser() { - return util::Map(); + const User* currentUser = getAuthenticatedUser(); + auto jobCardsAssignedToTechnician = m_serviceManagementService.getJobCards(currentUser->getId()); + util::Map readOnlyJobCardMap; + for (int iterator = 0; iterator < jobCardsAssignedToTechnician.getSize(); iterator++) + { + JobCard* currentJobCard = jobCardsAssignedToTechnician.getValueAt(iterator); + readOnlyJobCardMap.insert(currentJobCard->getId(), currentJobCard); + } + return readOnlyJobCardMap; } +/* +Function: completeJob +Description: Marks a job card as completed. +Parameters: + - jobID: std::string, ID of the job card +Returns: + - void +*/ void Controller::completeJob(const std::string& jobID) { + m_serviceManagementService.completeJob(jobID); } +/* +Function: removeUser +Description: Removes a user by ID. Cancels associated service bookings + and technician jobs before removing the user from the system. +Parameter: const std::string& userID - ID of the user to remove +Return type: void +*/ void Controller::removeUser(const std::string& userID) { + User* user = m_userManagementService.getUser(userID); + if (!user) + { + throw std::runtime_error("Error: User not Found.\n"); + } + m_userManagementService.removeUser(userID); } +/* +Function: createComboPackage +Description: Creates a new combo package with specified services and discount + percentage by delegating to the service management service. +Parameter: const std::string& name - name of the combo package + const util::Vector& serviceIDs - list of service IDs + double discountPercentage - discount percentage for the package +Return type: void +*/ void Controller::createComboPackage(const std::string& name, const util::Vector& serviceIDs, double discountPercentage) { + m_serviceManagementService.createComboPackage(name, serviceIDs, discountPercentage); } +/* +Function: removeComboPackage +Description: Removes a combo package by ID by delegating to the service + management service. +Parameter: const std::string& comboPackageID - ID of the combo package +Return type: void +*/ void Controller::removeComboPackage(const std::string& comboPackageID) { + m_serviceManagementService.removeComboPackage(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 containing the user’s invoices +*/ util::Map Controller::getInvoicesByUser() { - return util::Map(); + User* currentUser = m_authenticationManagementService.getAuthenticatedUser(); + util::Map currentUserInvoices = m_paymentManagementService.getInvoices(currentUser->getId()); + util::Map 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); } +/* +Function: getNotifications +Description: Retrieves all notifications for the currently authenticated user. + Converts them into a read-only vector before returning. +Parameters: None +Return type: util::Vector +*/ util::Vector Controller::getNotifications() { - return util::Vector(); + const User* authenticatedUser = m_authenticationManagementService.getAuthenticatedUser(); + if (!authenticatedUser) + { + throw std::runtime_error("No user is currently logged in!"); + } + auto notifications = m_userManagementService.getUserNotifications(authenticatedUser->getId()); + int numberOfNotifications = notifications.getSize(); + util::Vector readOnlyNotifications; + for (int index = 0; index < numberOfNotifications; index++) + { + readOnlyNotifications.push_back(notifications[index]); + } + return readOnlyNotifications; } +/* +Function: deleteNotification +Description: Deletes a specific notification for the currently authenticated user. +Parameters: + - notificationID: std::string, the unique identifier of the notification +Return type: void +*/ void Controller::deleteNotification(const std::string& notificationID) { + const User* authenticatedUser = m_authenticationManagementService.getAuthenticatedUser(); + if (!authenticatedUser) + { + throw std::runtime_error("No user is currently logged in!"); + } + m_userManagementService.deleteNotification(notificationID, authenticatedUser->getId()); } -void Controller::configureNotifications(const std::string& userID, bool paymentNotifications, bool serviceNotifications) +/* +Function: configureNotifications +Description: Configures notification preferences for the authenticated user. + Attaches or detaches the user from payment and service notifications. +Parameters: + - paymentNotifications: bool, enable/disable payment notifications + - serviceNotifications: bool, enable/disable service notifications +Return type: void +*/ +void Controller::configureNotifications(bool paymentNotifications, bool serviceNotifications) { + User* authenticatedUser = m_authenticationManagementService.getAuthenticatedUser(); + if (authenticatedUser) + { + if (paymentNotifications) + { + m_paymentManagementService.attach(authenticatedUser); + } + else + { + m_paymentManagementService.detach(authenticatedUser); + } + if (serviceNotifications) + { + m_serviceManagementService.attach(authenticatedUser); + } + else + { + m_serviceManagementService.detach(authenticatedUser); + } + } + else + { + throw std::runtime_error("No user is currently logged in!"); + } } +/* +Function: loadSystemData +Description: Loads all system data from persistent storage into memory. + Invokes the respective management services to load users, inventory items, services, + combo packages, service bookings, job cards, invoices, and observers. +Parameters: + - None +Returns: + - void +*/ +void Controller::loadSystemData() +{ + m_userManagementService.loadUsers(); + m_inventoryManagementService.loadInventoryItems(); + m_serviceManagementService.loadServices(); + m_serviceManagementService.loadComboPackages(); + m_serviceManagementService.loadServiceBookings(); + m_serviceManagementService.loadJobCards(); + m_paymentManagementService.loadInvoices(); + m_serviceManagementService.loadObservers(); + m_paymentManagementService.loadObservers(); + m_inventoryManagementService.loadObservers(); +} + +/* +Function: saveSystemData +Description: Saves all system data from memory back to persistent storage. + Invokes the respective management services to save users, inventory items, services, + combo packages, service bookings, job cards, invoices, and observers. +Parameters: + - None +Returns: + - void +*/ +void Controller::saveSystemData() +{ + m_userManagementService.saveUsers(); + m_inventoryManagementService.saveInventoryItems(); + m_serviceManagementService.saveServices(); + m_serviceManagementService.saveComboPackages(); + m_serviceManagementService.saveServiceBookings(); + m_serviceManagementService.saveJobCards(); + m_paymentManagementService.saveInvoices(); + m_serviceManagementService.saveObservers(); + m_paymentManagementService.saveObservers(); + m_inventoryManagementService.saveObservers(); +} + +/* +Function: runSystemChecks +Description: Runs system checks to ensure critical configurations, such as verifying admin existence. +Parameter: None +Return type: void +*/ void Controller::runSystemChecks() { + m_userManagementService.ensureAdminExists(); + m_inventoryManagementService.sendLowStockAlerts(); + m_paymentManagementService.sendPaymentReminders(); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 3aabb58..e75ebd4 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h @@ -1,7 +1,21 @@ +/* +File: Controller.h +Description: Header file declaring the Controller class, which manages + user authentication, inventory, services, bookings, job cards, + invoices, and notifications in the system. +Author: Trenser +Date:19-May-2026 +*/ + #pragma once -#include "Map.h" #include +#include "AuthenticationManagementService.h" #include "Enums.h" +#include "InventoryManagementService.h" +#include "Map.h" +#include "PaymentManagementService.h" +#include "ServiceManagementService.h" +#include "UserManagementService.h" class Service; class ComboPackage; @@ -14,13 +28,19 @@ class Notification; class Controller { +private: + AuthenticationManagementService m_authenticationManagementService; + UserManagementService m_userManagementService; + ServiceManagementService m_serviceManagementService; + InventoryManagementService m_inventoryManagementService; + PaymentManagementService m_paymentManagementService; public: bool login(const std::string& username, const std::string& password); void logout(); void changePassword(const std::string& newPassword); - void createCustomer(const std::string& username, const std::string& password, const std::string& email, const std::string& phone); + void createCustomer(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone); const User* getAuthenticatedUser(); - void createTechnician(const std::string& username, const std::string& password, const std::string& email, const std::string& phone); + void createTechnician(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone); void updateUserDetails(const std::string& email, const std::string& phone); util::Map getServices(); util::Map getComboPackages(); @@ -29,6 +49,7 @@ public: util::Map getInventoryItems(); const InventoryItem* getInventoryItem(const std::string& inventoryItemID); void addInventoryItem(const std::string& partName, int quantity, double price); + void addInventoryItemStock(const std::string& selectedItemId, int quantity); void removeInventoryItem(const std::string& inventoryItemID); util::Map getServiceBookings(); util::Map getServiceBookingsByUser(const std::string userID); @@ -46,6 +67,8 @@ public: void completePayment(const std::string& invoiceID, util::PaymentMode paymentMode); util::Vector getNotifications(); void deleteNotification(const std::string& notificationID); - void configureNotifications(const std::string& userID, bool paymentNotifications, bool serviceNotifications); + void configureNotifications(bool paymentNotifications, bool serviceNotifications); + void loadSystemData(); + void saveSystemData(); void runSystemChecks(); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/patterns/Observer.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/patterns/Observer.h index 98f0efa..7fd7262 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/patterns/Observer.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/patterns/Observer.h @@ -1,3 +1,10 @@ +/* +File: Observer.h +Description: Declares the Observer interface for handling notifications in the Vehicle Service Management System. +Author: Trenser +Date: 19-May-2026 +*/ + #pragma once class Notification; @@ -6,5 +13,5 @@ class Observer { public: virtual ~Observer() = default; - virtual void update(Notification* notification) = 0; + virtual void addNotification(Notification* notification) = 0; }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/patterns/Subject.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/patterns/Subject.h index 309a59d..09b8ac3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/patterns/Subject.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/core/patterns/Subject.h @@ -1,6 +1,14 @@ +/* +File: Subject.h +Description: Declares the Subject interface for managing user attachments and detachments in the Observer design pattern within the Vehicle Service Management System. +Author: Trenser +Date: 19-May-2026 +*/ + #pragma once #include #include "Map.h" +#include "Vector.h" class User; class Notification; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp index dd0e016..3419f44 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp @@ -1,46 +1,128 @@ +/* +File: DataStore.cpp +Description: Implements the DataStore class which provides a centralized singleton repository + for managing system data in the Vehicle Service Management System. + Includes accessors for users, services, combo packages, service bookings, + job cards, inventory items, invoices, and payments. +Author: Trenser +Date: 19-May-2026 +*/ + #include "DataStore.h" +/* +Function: getInstance +Description: Provides a singleton instance of the DataStore class. +Parameters: + - None +Returns: + - Reference to the single DataStore instance. +*/ DataStore& DataStore::getInstance() { static DataStore dataStore; return dataStore; } +/* +Function: getUsers +Description: Retrieves the internal map of users. +Parameters: + - None +Returns: + - Reference to util::Map containing all users. +*/ util::Map& DataStore::getUsers() { return m_users; } +/* +Function: getServices +Description: Retrieves the internal map of services. +Parameters: + - None +Returns: + - Reference to util::Map containing all services. +*/ util::Map& DataStore::getServices() { return m_services; } +/* +Function: getComboPackages +Description: Retrieves the internal map of combo packages. +Parameters: + - None +Returns: + - Reference to util::Map containing all combo packages. +*/ util::Map& DataStore::getComboPackages() { return m_comboPackages; } +/* +Function: getServiceBookings +Description: Retrieves the internal map of service bookings. +Parameters: + - None +Returns: + - Reference to util::Map containing all service bookings. +*/ util::Map& DataStore::getServiceBookings() { return m_serviceBookings; } +/* +Function: getJobCards +Description: Retrieves the internal map of job cards. +Parameters: + - None +Returns: + - Reference to util::Map containing all job cards. +*/ util::Map& DataStore::getJobCards() { return m_jobCards; } +/* +Function: getInventoryItems +Description: Retrieves the internal map of inventory items. +Parameters: + - None +Returns: + - Reference to util::Map containing all inventory items. +*/ util::Map& DataStore::getInventoryItems() { return m_inventoryItems; } +/* +Function: getInvoices +Description: Retrieves the internal map of invoices. +Parameters: + - None +Returns: + - Reference to util::Map containing all invoices. +*/ util::Map& DataStore::getInvoices() { return m_invoices; } +/* +Function: getPayments +Description: Retrieves the internal map of payments. +Parameters: + - None +Returns: + - Reference to util::Map containing all payments. +*/ util::Map& DataStore::getPayments() { return m_payments; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h index 924e8e4..cde9b4e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.h @@ -1,5 +1,11 @@ -#pragma once +/* +File: DataStore.h +Description: Declares the DataStore singleton class responsible for managing collections of users, services, combo packages, service bookings, job cards, inventory items, invoices, and payments in the Vehicle Service Management System. +Author: Trenser +Date: 19-May-2026 +*/ +#pragma once #include #include "Map.h" diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ComboPackage.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ComboPackage.cpp index 6216922..4e69d9f 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ComboPackage.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ComboPackage.cpp @@ -1,65 +1,341 @@ +/* +File: ComboPackage.cpp +Description: Implements the ComboPackage class which represents a bundled set of services in the Vehicle Service Management System. + Provides constructors, accessors, and mutators for package details such as ID, name, discount percentage, state, + and associated services. +Author: Trenser +Date: 19-May-2026 +*/ + +#include +#include #include "ComboPackage.h" +#include "Service.h" +#include "Factory.h" +#include "StringHelper.h" int ComboPackage::m_uid = 0; +/* +Function: ComboPackage +Description: Default constructor that initializes a new combo package with a unique ID, + active state, and zero discount percentage. +Parameters: + - None +Returns: + - A new ComboPackage object. +*/ ComboPackage::ComboPackage() : m_id("CMP" + std::to_string(++m_uid)), m_status(util::State::ACTIVE), m_discountPercentage(0.0) {} +/* +Function: ComboPackage +Description: Parameterized constructor that initializes a new combo package with a unique ID, + specified package name, discount percentage, active state, and associated services. +Parameters: + - packageName: Name of the combo package. + - discountPercentage: Discount percentage applied to the package. + - services: Map of services included in the package. +Returns: + - A new ComboPackage object. +*/ ComboPackage::ComboPackage(const std::string& packageName, double discountPercentage, const util::Map& services) : m_id("CMP" + std::to_string(++m_uid)), m_packageName(packageName), m_discountPercentage(discountPercentage), m_status(util::State::ACTIVE), - m_services(services) {} + m_services(services) +{ + int numberOfServices = m_services.getSize(); + auto servicePointers = m_services.getValues(); + for (int index = 0; index < numberOfServices; index++) + { + m_serviceIDs.push_back(servicePointers[index]->getId()); + } +} +/* +Function: ComboPackage (parameterized constructor with ID) +Description: Initializes a combo package with an existing ID, name, discount percentage, + service IDs, and state. Updates UID tracking based on ID. +Parameters: + - id: const std::string&, unique ID of the package + - packageName: const std::string&, name of the package + - discountPercentage: double, discount percentage applied + - serviceIDs: const util::Vector&, IDs of services included + - status: util::State, state of the package (ACTIVE/INACTIVE) +Returns: + - A new ComboPackage object +*/ +ComboPackage::ComboPackage(const std::string& id, const std::string& packageName, double discountPercentage, const util::Vector& serviceIDs, util::State status) + : m_id(id), + m_packageName(packageName), + m_discountPercentage(discountPercentage), + m_serviceIDs(serviceIDs), + m_status(status) +{ + int idNumber = util::extractNumber(m_id); + if (idNumber > m_uid) + { + m_uid = idNumber; + } +} + +/* +Function: getId +Description: Retrieves the unique ID of the combo package. +Parameters: + - None +Returns: + - const std::string& representing the package ID. +*/ const std::string& ComboPackage::getId() const { return m_id; } +/* +Function: getPackageName +Description: Retrieves the name of the combo package. +Parameters: + - None +Returns: + - const std::string& representing the package name. +*/ const std::string& ComboPackage::getPackageName() const { return m_packageName; } +/* +Function: getDiscountPercentage +Description: Retrieves the discount percentage applied to the combo package. +Parameters: + - None +Returns: + - double representing the discount percentage. +*/ double ComboPackage::getDiscountPercentage() const { return m_discountPercentage; } +/* +Function: getState +Description: Retrieves the current state (ACTIVE/INACTIVE) of the combo package. +Parameters: + - None +Returns: + - util::State representing the package state. +*/ util::State ComboPackage::getState() const { return m_status; } +const util::Vector& ComboPackage::getServiceIDs() const +{ + return m_serviceIDs; +} + +/* +Function: getServices +Description: Retrieves the map of services included in the combo package. +Parameters: + - None +Returns: + - const util::Map& representing the services. +*/ const util::Map& ComboPackage::getServices() const { return m_services; } +/* +Function: setId +Description: Sets the unique ID of the combo package. +Parameters: + - id: New ID string. +Returns: + - void +*/ void ComboPackage::setId(const std::string& id) { m_id = id; } +/* +Function: setPackageName +Description: Sets the name of the combo package. +Parameters: + - packageName: New package name string. +Returns: + - void +*/ void ComboPackage::setPackageName(const std::string& packageName) { m_packageName = packageName; } +/* +Function: setDiscountPercentage +Description: Sets the discount percentage for the combo package. +Parameters: + - discountPercentage: New discount percentage value. +Returns: + - void +*/ void ComboPackage::setDiscountPercentage(double discountPercentage) { m_discountPercentage = discountPercentage; } +/* +Function: setServices +Description: Sets the services included in the combo package. +Parameters: + - services: Map of services to be associated with the package. +Returns: + - void +*/ void ComboPackage::setServices(const util::Map& services) { m_services = services; + m_serviceIDs.clear(); + int numberOfServices = m_services.getSize(); + auto servicePointers = m_services.getValues(); + for (int index = 0; index < numberOfServices; index++) + { + m_serviceIDs.push_back(servicePointers[index]->getId()); + } } +/* +Function: setState +Description: Sets the state (ACTIVE/INACTIVE) of the combo package. +Parameters: + - status: New state value. +Returns: + - void +*/ void ComboPackage::setState(util::State status) { m_status = status; } + +/* +Function: getServiceIDsAsString (static helper) +Description: Converts a vector of service IDs into a single string separated by '|'. +Parameters: + - serviceIDs: const util::Vector&, vector of service IDs +Returns: + - std::string: Concatenated service IDs string +*/ +static std::string getServiceIDsAsString(const util::Vector& serviceIDs) +{ + int numberOfServices = serviceIDs.getSize(); + std::string serviceIDsString; + for (int index = 0; index < numberOfServices; index++) + { + serviceIDsString += serviceIDs[index]; + if (index < numberOfServices - 1) + { + serviceIDsString += '|'; + } + } + return serviceIDsString; +} + +/* +Function: getServiceIDsAsVector (static helper) +Description: Converts a string of service IDs separated by '|' into a vector. +Parameters: + - serviceIDsString: const std::string&, concatenated service IDs string +Returns: + - util::Vector: Vector of service IDs +*/ +static util::Vector getServiceIDsAsVector(const std::string& serviceIDsString) +{ + util::Vector serviceIDs; + std::string serviceID; + std::istringstream serializedServiceIDs(serviceIDsString); + while (getline(serializedServiceIDs, serviceID, '|')) + { + serviceIDs.push_back(serviceID); + } + return serviceIDs; +} + +/* +Function: serialize +Description: Serializes the combo package into a CSV-formatted string. +Parameters: + - None +Returns: + - std::string: Serialized combo package record +*/ +std::string ComboPackage::serialize() const +{ + std::ostringstream serializedComboPackage; + serializedComboPackage << m_id << ',' + << m_packageName << ',' + << m_discountPercentage << ',' + << getServiceIDsAsString(m_serviceIDs) << ',' + << util::getStateString(m_status); + return serializedComboPackage.str(); +} + +/* +Function: deserialize +Description: Deserializes a CSV-formatted string into a ComboPackage object. +Parameters: + - record: const std::string&, serialized combo package record +Returns: + - ComboPackage*: Pointer to the deserialized ComboPackage object +Throws: + - std::runtime_error if data is invalid +*/ +ComboPackage* ComboPackage::deserialize(const std::string& record) +{ + std::string id, packageName; + std::string discountPercentageString, serviceIDsString, statusString; + double discountPercentage; + std::istringstream serializedComboPackage(record); + getline(serializedComboPackage, id, ','); + getline(serializedComboPackage, packageName, ','); + getline(serializedComboPackage, discountPercentageString, ','); + getline(serializedComboPackage, serviceIDsString, ','); + getline(serializedComboPackage, statusString, ','); + try + { + discountPercentage = std::stod(discountPercentageString); + } + catch (...) + { + throw std::runtime_error("Invalid combo package data"); + } + util::Vector serviceIDs = getServiceIDsAsVector(serviceIDsString); + util::State status = util::getState(statusString); + return Factory::getObject( + id, + packageName, + discountPercentage, + serviceIDs, + status + ); +} + +/* +Function: getHeaders +Description: Retrieves the CSV headers for combo package serialization. +Parameters: + - None +Returns: + - std::string: Header string ("ID,PackageName,DiscountPercentage,ServiceIDs,Status") +*/ +std::string ComboPackage::getHeaders() +{ + return "ID,PackageName,DiscountPercentage,ServiceIDs,Status"; +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ComboPackage.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ComboPackage.h index 4b28d54..941c2b3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ComboPackage.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ComboPackage.h @@ -1,6 +1,14 @@ +/* +File: ComboPackage.h +Description: Declares the ComboPackage class which represents a service package with a unique ID, package name, discount percentage, associated services, and status in the Vehicle Service Management System. +Author: Trenser +Date: 19-May-2026 +*/ + #pragma once #include #include "Map.h" +#include "Vector.h" #include "Enums.h" class Service; @@ -12,14 +20,17 @@ private: std::string m_id; std::string m_packageName; double m_discountPercentage; + util::Vector m_serviceIDs; util::Map m_services; util::State m_status; public: ComboPackage(); ComboPackage(const std::string& packageName, double discountPercentage, const util::Map& services); + ComboPackage(const std::string& id, const std::string& packageName, double discountPercentage, const util::Vector& serviceIDs, util::State status); const std::string& getId() const; const std::string& getPackageName() const; double getDiscountPercentage() const; + const util::Vector& getServiceIDs() const; const util::Map& getServices() const; util::State getState() const; void setId(const std::string& id); @@ -27,4 +38,7 @@ public: void setDiscountPercentage(double discountPercentage); void setServices(const util::Map& services); void setState(util::State status); + std::string serialize() const; + static ComboPackage* deserialize(const std::string&); + static std::string getHeaders(); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/InventoryItem.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/InventoryItem.cpp index c3dbbaa..f34b8a5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/InventoryItem.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/InventoryItem.cpp @@ -1,13 +1,45 @@ +/* +File: InventoryItem.cpp +Description: Implements the InventoryItem class which represents an inventory item in the Vehicle Service Management System. + Provides constructors, accessors, and mutators for item details such as ID, part name, quantity, price, and state. +Author: Trenser +Date: 19-May-2026 +*/ + +#include +#include +#include "Factory.h" +#include "StringHelper.h" #include "InventoryItem.h" int InventoryItem::m_uid = 0; +/* +Function: InventoryItem +Description: Default constructor that initializes a new inventory item with a unique ID, + active state, zero quantity, and zero price. +Parameters: + - None +Returns: + - A new InventoryItem object. +*/ InventoryItem::InventoryItem() : m_id("IIM" + std::to_string(++m_uid)), m_quantity(0), m_status(util::State::ACTIVE), m_price(0.0) {} +/* +Function: InventoryItem +Description: Parameterized constructor that initializes a new inventory item with a unique ID, + specified part name, quantity, price, and active state. +Parameters: + - partName: Name of the inventory item. + - quantity: Initial quantity of the item. + - price: Price of the item. +Returns: + - A new InventoryItem object. +*/ InventoryItem::InventoryItem(const std::string& partName, int quantity, double price) : m_id("IIM" + std::to_string(++m_uid)), m_partName(partName), @@ -15,52 +47,232 @@ InventoryItem::InventoryItem(const std::string& partName, int quantity, double p m_status(util::State::ACTIVE), m_price(price) {} +/* +Function: InventoryItem (parameterized constructor with ID) +Description: Initializes an inventory item with an existing ID, part name, quantity, + price, and state. Updates UID tracking based on ID. +Parameters: + - id: const std::string&, unique ID of the item + - partName: const std::string&, name of the part + - quantity: int, quantity of the part + - price: double, price of the part + - status: util::State, state of the item (ACTIVE/INACTIVE) +Returns: + - A new InventoryItem object +*/ +InventoryItem::InventoryItem(const std::string& id, const std::string& partName, int quantity, double price, util::State status) + : m_id(id), + m_partName(partName), + m_quantity(quantity), + m_status(status), + m_price(price) +{ + int idNumber = util::extractNumber(m_id); + if (idNumber > m_uid) + { + m_uid = idNumber; + } +} + +/* +Function: getId +Description: Retrieves the unique ID of the inventory item. +Parameters: + - None +Returns: + - const std::string& representing the item ID. +*/ const std::string& InventoryItem::getId() const { return m_id; } +/* +Function: getPartName +Description: Retrieves the part name of the inventory item. +Parameters: + - None +Returns: + - const std::string& representing the part name. +*/ const std::string& InventoryItem::getPartName() const { return m_partName; } +/* +Function: getQuantity +Description: Retrieves the current quantity of the inventory item. +Parameters: + - None +Returns: + - int representing the quantity. +*/ int InventoryItem::getQuantity() const { return m_quantity; } +/* +Function: getPrice +Description: Retrieves the price of the inventory item. +Parameters: + - None +Returns: + - double representing the price. +*/ double InventoryItem::getPrice() const { return m_price; } +/* +Function: getState +Description: Retrieves the current state (ACTIVE/INACTIVE) of the inventory item. +Parameters: + - None +Returns: + - util::State representing the item state. +*/ util::State InventoryItem::getState() const { return m_status; } +/* +Function: setId +Description: Sets the unique ID of the inventory item. +Parameters: + - id: New ID string. +Returns: + - void +*/ void InventoryItem::setId(const std::string& id) { m_id = id; } +/* +Function: setPartName +Description: Sets the part name of the inventory item. +Parameters: + - partName: New part name string. +Returns: + - void +*/ void InventoryItem::setPartName(const std::string& partName) { m_partName = partName; } +/* +Function: setQuantity +Description: Sets the quantity of the inventory item. +Parameters: + - quantity: New quantity value. +Returns: + - void +*/ void InventoryItem::setQuantity(int quantity) { m_quantity = quantity; } +/* +Function: setPrice +Description: Sets the price of the inventory item. +Parameters: + - price: New price value. +Returns: + - void +*/ void InventoryItem::setPrice(double price) { m_price = price; } +/* +Function: setState +Description: Sets the state (ACTIVE/INACTIVE) of the inventory item. +Parameters: + - status: New state value. +Returns: + - void +*/ void InventoryItem::setState(util::State status) { m_status = status; +} + +/* +Function: serialize +Description: Serializes the inventory item into a CSV-formatted string. +Parameters: + - None +Returns: + - std::string: Serialized inventory item record +*/ +std::string InventoryItem::serialize() const +{ + std::ostringstream serializedInventoryItem; + serializedInventoryItem << m_id << ',' + << m_partName << ',' + << m_quantity << ',' + << m_price << ',' + << util::getStateString(m_status); + return serializedInventoryItem.str(); +} + +/* +Function: deserialize +Description: Deserializes a CSV-formatted string into an InventoryItem object. +Parameters: + - record: const std::string&, serialized inventory item record +Returns: + - InventoryItem*: Pointer to the deserialized InventoryItem object +Throws: + - std::runtime_error if data is invalid +*/ +InventoryItem* InventoryItem::deserialize(const std::string& record) +{ + std::string id, partName; + std::string quantityString, priceString, statusString; + int quantity; + double price; + std::istringstream serializedInventoryItem(record); + getline(serializedInventoryItem, id, ','); + getline(serializedInventoryItem, partName, ','); + getline(serializedInventoryItem, quantityString, ','); + getline(serializedInventoryItem, priceString, ','); + getline(serializedInventoryItem, statusString, ','); + try + { + quantity = std::stoi(quantityString); + price = std::stod(priceString); + } + catch (...) + { + throw std::runtime_error("Invalid inventory item data"); + } + util::State status = util::getState(statusString); + return Factory::getObject( + id, + partName, + quantity, + price, + status + ); +} + +/* +Function: getHeaders +Description: Retrieves the CSV headers for inventory item serialization. +Parameters: + - None +Returns: + - std::string: Header string ("ID,PartName,Quantity,Price,Status") +*/ +std::string InventoryItem::getHeaders() +{ + return "ID,PartName,Quantity,Price,Status"; } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/InventoryItem.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/InventoryItem.h index d9618bc..5808e8f 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/InventoryItem.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/InventoryItem.h @@ -1,3 +1,12 @@ +/* +File: InventoryItem.h +Description: Declares the InventoryItem class which represents parts in the Vehicle Service Management System. + Each item has a unique ID, part name, quantity, price, and status. +Author: Trenser +Date: 19-May-2026 +*/ + + #pragma once #include #include "Enums.h" @@ -14,6 +23,7 @@ private: public: InventoryItem(); InventoryItem(const std::string& partName, int quantity, double price); + InventoryItem(const std::string& id, const std::string& partName, int quantity, double price, util::State status); const std::string& getId() const; const std::string& getPartName() const; int getQuantity() const; @@ -24,4 +34,7 @@ public: void setQuantity(int quantity); void setPrice(double price); void setState(util::State status); + std::string serialize() const; + static InventoryItem* deserialize(const std::string&); + static std::string getHeaders(); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.cpp index ba7bc84..f24a013 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.cpp @@ -1,7 +1,31 @@ +/* +File: Invoice.cpp +Description: Implements the Invoice class which represents an invoice in the Vehicle Service Management System. + Provides constructors, accessors, and mutators for invoice details such as ID, booking, costs, + discount percentage, total amount, payment details, and status. +Author: Trenser +Date: 19-May-2026 +*/ + +#include +#include #include "Invoice.h" +#include "Factory.h" +#include "InventoryItem.h" +#include "StringHelper.h" int Invoice::m_uid = 0; +/* +Function: Invoice +Description: Default constructor that initializes a new invoice with a unique ID, + null booking, zero costs, zero discount, zero total amount, + and default payment method and status. +Parameters: + - None +Returns: + - A new Invoice object. +*/ Invoice::Invoice() : m_id("INV" + std::to_string(++m_uid)), m_booking(nullptr), @@ -12,12 +36,30 @@ Invoice::Invoice() m_paymentMethod(util::PaymentMode()), m_status(util::PaymentStatus()) {} +/* +Function: Invoice +Description: Parameterized constructor that initializes a new invoice with a unique ID and specified details. +Parameters: + - bookingId: ID of the associated service booking. + - booking: Pointer to the ServiceBooking object. + - invoiceDate: Timestamp of when the invoice was created. + - laborCost: Cost of labor for the service. + - parts: Map of inventory items used in the service. + - partsCost: Total cost of parts. + - discountPercentage: Discount applied to the invoice. + - totalAmount: Final total amount after discount. + - paymentDate: Timestamp of when payment was made. + - paymentMethod: Payment mode (ONLINE/OFFLINE). + - status: Payment status (PENDING/COMPLETED). +Returns: + - A new Invoice object. +*/ Invoice::Invoice( const std::string& bookingId, ServiceBooking* booking, const util::Timestamp& invoiceDate, - double laborCost, const util::Map& parts, + double laborCost, + const util::Map& parts, double partsCost, double discountPercentage, double totalAmount, @@ -36,124 +78,495 @@ Invoice::Invoice( m_totalAmount(totalAmount), m_paymentDate(paymentDate), m_paymentMethod(paymentMethod), - m_status(status) {} + m_status(status) +{ + int numberOfParts = m_parts.getSize(); + auto partPointers = m_parts.getValues(); + for (int index = 0; index < numberOfParts; index++) + { + m_partIDs.push_back(partPointers[index]->getId()); + } +} +Invoice::Invoice( + const std::string& id, + const std::string& bookingId, + const util::Timestamp& invoiceDate, + const util::Vector& partIDs, + double laborCost, + double partsCost, + double discountPercentage, + double totalAmount, + const util::Timestamp& paymentDate, + util::PaymentMode paymentMethod, + util::PaymentStatus status +) + : m_id(id), + m_bookingId(bookingId), + m_booking(nullptr), + m_invoiceDate(invoiceDate), + m_partIDs(partIDs), + m_laborCost(laborCost), + m_partsCost(partsCost), + m_discountPercentage(discountPercentage), + m_totalAmount(totalAmount), + m_paymentDate(paymentDate), + m_paymentMethod(paymentMethod), + m_status(status) +{ + int idNumber = util::extractNumber(m_id); + if (idNumber > m_uid) + { + m_uid = idNumber; + } +} +/* +Function: getId +Description: Retrieves the unique ID of the invoice. +Returns: + - const std::string& representing the invoice ID. +*/ const std::string& Invoice::getId() const { return m_id; } +/* +Function: getBookingId +Description: Retrieves the booking ID associated with the invoice. +Returns: + - const std::string& representing the booking ID. +*/ const std::string& Invoice::getBookingId() const { return m_bookingId; } +/* +Function: getBooking +Description: Retrieves the pointer to the associated ServiceBooking. +Returns: + - ServiceBooking* representing the booking. +*/ ServiceBooking* Invoice::getBooking() const { return m_booking; } +/* +Function: getInvoiceDate +Description: Retrieves the timestamp of the invoice creation date. +Returns: + - const util::Timestamp& representing the invoice date. +*/ const util::Timestamp& Invoice::getInvoiceDate() const { return m_invoiceDate; } +/* +Function: getLaborCost +Description: Retrieves the labor cost associated with the invoice. +Returns: + - double representing the labor cost. +*/ double Invoice::getLaborCost() const { return m_laborCost; } -const util::Map& Invoice::getParts() const +/* +Function: getPartIDs +Description: Retrieves the IDs of parts used in the invoice. +Parameters: + - None +Returns: + - const util::Vector&: Part IDs +*/ +const util::Vector& Invoice::getPartIDs() const +{ + return m_partIDs; +} + +/* +Function: getParts +Description: Retrieves the map of inventory items used in the service. +Returns: + - const util::Map& representing the parts. +*/ +const util::Map& Invoice::getParts() const { return m_parts; } +/* +Function: getPartsCost +Description: Retrieves the total cost of parts used in the service. +Returns: + - double representing the parts cost. +*/ double Invoice::getPartsCost() const { return m_partsCost; } +/* +Function: getDiscountPercentage +Description: Retrieves the discount percentage applied to the invoice. +Returns: + - double representing the discount percentage. +*/ double Invoice::getDiscountPercentage() const { return m_discountPercentage; } +/* +Function: getTotalAmount +Description: Retrieves the total amount of the invoice after discount. +Returns: + - double representing the total amount. +*/ double Invoice::getTotalAmount() const { return m_totalAmount; } +/* +Function: getPaymentDate +Description: Retrieves the timestamp of the payment date. +Returns: + - const util::Timestamp& representing the payment date. +*/ const util::Timestamp& Invoice::getPaymentDate() const { return m_paymentDate; } +/* +Function: getPaymentMethod +Description: Retrieves the payment mode used for the invoice. +Returns: + - util::PaymentMode representing the payment method. +*/ util::PaymentMode Invoice::getPaymentMethod() const { return m_paymentMethod; } +/* +Function: getStatus +Description: Retrieves the payment status of the invoice. +Returns: + - util::PaymentStatus representing the payment status. +*/ util::PaymentStatus Invoice::getStatus() const { return m_status; } +/* +Function: setId +Description: Sets the unique ID of the invoice. +Parameters: + - id: New invoice ID string. +Returns: + - void +*/ void Invoice::setId(const std::string& id) { m_id = id; } +/* +Function: setBookingId +Description: Sets the booking ID associated with the invoice. +Parameters: + - bookingId: New booking ID string. +Returns: + - void +*/ void Invoice::setBookingId(const std::string& bookingId) { m_bookingId = bookingId; } +/* +Function: setBooking +Description: Sets the associated ServiceBooking pointer. +Parameters: + - booking: Pointer to the ServiceBooking object. +Returns: + - void +*/ void Invoice::setBooking(ServiceBooking* booking) { m_booking = booking; } +/* +Function: setInvoiceDate +Description: Sets the invoice creation date. +Parameters: + - invoiceDate: New timestamp for the invoice date. +Returns: + - void +*/ void Invoice::setInvoiceDate(const util::Timestamp& invoiceDate) { m_invoiceDate = invoiceDate; } +/* +Function: setLaborCost +Description: Sets the labor cost for the invoice. +Parameters: + - laborCost: New labor cost value. +Returns: + - void +*/ void Invoice::setLaborCost(double laborCost) { m_laborCost = laborCost; } -void Invoice::setParts(const util::Map& parts) +/* +Function: setParts +Description: Sets the inventory items used in the service. +Parameters: + - parts: Map of inventory items. +Returns: + - void +*/ +void Invoice::setParts(const util::Map& parts) { m_parts = parts; + m_partIDs.clear(); + int numberOfParts = m_parts.getSize(); + auto partPointers = m_parts.getValues(); + for (int index = 0; index < numberOfParts; index++) + { + m_partIDs.push_back(partPointers[index]->getId()); + } } +/* +Function: setPartsCost +Description: Sets the total cost of parts used in the service. +Parameters: + - partsCost: New parts cost value. +Returns: + - void +*/ void Invoice::setPartsCost(double partsCost) { m_partsCost = partsCost; } +/* +Function: setDiscountPercentage +Description: Sets the discount percentage applied to the invoice. +Parameters: + - discountPercentage: New discount percentage value. +Returns: + - void +*/ void Invoice::setDiscountPercentage(double discountPercentage) { m_discountPercentage = discountPercentage; } +/* +Function: setTotalAmount +Description: Sets the total amount of the invoice. +Parameters: + - totalAmount: New total amount value. +Returns: + - void +*/ void Invoice::setTotalAmount(double totalAmount) { m_totalAmount = totalAmount; } +/* +Function: setPaymentDate +Description: Sets the payment date for the invoice. +Parameters: + - paymentDate: New timestamp for the payment date. +Returns: + - void +*/ void Invoice::setPaymentDate(const util::Timestamp& paymentDate) { m_paymentDate = paymentDate; } +/* +Function: setPaymentMethod +Description: Sets the payment mode for the invoice. +Parameters: + - paymentMethod: New payment mode value. +Returns: + - void +*/ void Invoice::setPaymentMethod(util::PaymentMode paymentMethod) { m_paymentMethod = paymentMethod; } +/* +Function: setStatus +Description: Sets the payment status of the invoice. +Parameters: + - status: New payment status value. +Returns: + - void +*/ void Invoice::setStatus(util::PaymentStatus status) { m_status = status; } + +/* +Function: getPartIDsAsString (static helper) +Description: Converts a vector of part IDs into a single string separated by '|'. +Parameters: + - partIDs: const util::Vector&, vector of part IDs +Returns: + - std::string: Concatenated part IDs string +*/ +static std::string getPartIDsAsString(const util::Vector& partIDs) +{ + int numberOfParts = partIDs.getSize(); + std::string partIDsString; + for (int index = 0; index < numberOfParts; index++) + { + partIDsString += partIDs[index]; + if (index < numberOfParts - 1) + { + partIDsString += '|'; + } + } + return partIDsString; +} + +/* +Function: getPartIDsAsVector (static helper) +Description: Converts a string of part IDs separated by '|' into a vector. +Parameters: + - partIDsString: const std::string&, concatenated part IDs string +Returns: + - util::Vector: Vector of part IDs +*/ +static util::Vector getPartIDsAsVector(const std::string& partIDsString) +{ + util::Vector partIDs; + std::string partID; + std::istringstream serializedPartIDs(partIDsString); + while (getline(serializedPartIDs, partID, '|')) + { + partIDs.push_back(partID); + } + return partIDs; +} + +/* +Function: serialize +Description: Serializes the invoice into a CSV-formatted string. +Parameters: + - None +Returns: + - std::string: Serialized invoice record +*/ +std::string Invoice::serialize() const +{ + std::ostringstream serializedInvoice; + serializedInvoice << m_id << ',' + << m_bookingId << ',' + << m_invoiceDate.toString() << ',' + << m_laborCost << ',' + << getPartIDsAsString(m_partIDs) << ',' + << m_partsCost << ',' + << m_discountPercentage << ',' + << m_totalAmount << ',' + << m_paymentDate.toString() << ',' + << util::getPaymentModeString(m_paymentMethod) << ',' + << util::getPaymentStatusString(m_status); + return serializedInvoice.str(); +} + +/* +Function: deserialize +Description: Deserializes a CSV-formatted string into an Invoice object. +Parameters: + - record: const std::string&, serialized invoice record +Returns: + - Invoice*: Pointer to the deserialized Invoice object +Throws: + - std::runtime_error if data is invalid +*/ +Invoice* Invoice::deserialize(const std::string& record) +{ + std::string id, bookingId; + std::string invoiceDateString, laborCostString, partIDsString; + std::string partsCostString, discountPercentageString, totalAmountString; + std::string paymentDateString, paymentMethodString, statusString; + double laborCost, partsCost, discountPercentage, totalAmount; + std::istringstream serializedInvoice(record); + getline(serializedInvoice, id, ','); + getline(serializedInvoice, bookingId, ','); + getline(serializedInvoice, invoiceDateString, ','); + getline(serializedInvoice, laborCostString, ','); + getline(serializedInvoice, partIDsString, ','); + getline(serializedInvoice, partsCostString, ','); + getline(serializedInvoice, discountPercentageString, ','); + getline(serializedInvoice, totalAmountString, ','); + getline(serializedInvoice, paymentDateString, ','); + getline(serializedInvoice, paymentMethodString, ','); + getline(serializedInvoice, statusString, ','); + util::Timestamp invoiceDate; + util::Timestamp paymentDate; + try + { + invoiceDate = util::Timestamp::fromString(invoiceDateString); + paymentDate = util::Timestamp::fromString(paymentDateString); + laborCost = std::stod(laborCostString); + partsCost = std::stod(partsCostString); + discountPercentage = std::stod(discountPercentageString); + totalAmount = std::stod(totalAmountString); + } + catch (...) + { + throw std::runtime_error("Invalid invoice data"); + } + util::Vector partIDs = getPartIDsAsVector(partIDsString); + util::PaymentMode paymentMethod = util::getPaymentMode(paymentMethodString); + util::PaymentStatus status = util::getPaymentStatus(statusString); + return Factory::getObject( + id, + bookingId, + invoiceDate, + partIDs, + laborCost, + partsCost, + discountPercentage, + totalAmount, + paymentDate, + paymentMethod, + status + ); +} + +/* +Function: getHeaders +Description: Retrieves the CSV headers for invoice serialization. +Parameters: + - None +Returns: + - std::string: Header string ("ID,BookingID,InvoiceDate,LaborCost,PartIDs,PartsCost,DiscountPercentage,TotalAmount,PaymentDate,PaymentMethod,Status") +*/ +std::string Invoice::getHeaders() +{ + return "ID,BookingID,InvoiceDate,LaborCost,PartIDs,PartsCost,DiscountPercentage,TotalAmount,PaymentDate,PaymentMethod,Status"; +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.h index 212d33f..3374de9 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Invoice.h @@ -1,6 +1,16 @@ +/* +File: Invoice.h +Description: Declares the Invoice class which represents billing details for a service booking in the Vehicle Service Management System. + Each invoice includes booking information, labor cost, parts used, discount percentage, total amount, payment details, and status. +Author: Trenser +Date: 19-May-2026 +*/ + + #pragma once #include #include "Map.h" +#include "Vector.h" #include "Timestamp.h" #include "Enums.h" @@ -16,22 +26,22 @@ private: ServiceBooking* m_booking; util::Timestamp m_invoiceDate; double m_laborCost; - util::Map m_parts; + util::Vector m_partIDs; + util::Map m_parts; double m_partsCost; double m_discountPercentage; double m_totalAmount; util::Timestamp m_paymentDate; util::PaymentMode m_paymentMethod; util::PaymentStatus m_status; - public: Invoice(); Invoice( const std::string& bookingId, ServiceBooking* booking, const util::Timestamp& invoiceDate, - double laborCost, const util::Map& parts, + double laborCost, + const util::Map& parts, double partsCost, double discountPercentage, double totalAmount, @@ -39,12 +49,26 @@ public: util::PaymentMode paymentMethod, util::PaymentStatus status ); + Invoice( + const std::string& id, + const std::string& bookingId, + const util::Timestamp& invoiceDate, + const util::Vector& partIDs, + double laborCost, + double partsCost, + double discountPercentage, + double totalAmount, + const util::Timestamp& paymentDate, + util::PaymentMode paymentMethod, + util::PaymentStatus status + ); const std::string& getId() const; const std::string& getBookingId() const; ServiceBooking* getBooking() const; const util::Timestamp& getInvoiceDate() const; double getLaborCost() const; - const util::Map& getParts() const; + const util::Vector& getPartIDs() const; + const util::Map& getParts() const; double getPartsCost() const; double getDiscountPercentage() const; double getTotalAmount() const; @@ -56,11 +80,14 @@ public: void setBooking(ServiceBooking* booking); void setInvoiceDate(const util::Timestamp& invoiceDate); void setLaborCost(double laborCost); - void setParts(const util::Map& parts); + void setParts(const util::Map& parts); void setPartsCost(double partsCost); void setDiscountPercentage(double discountPercentage); void setTotalAmount(double totalAmount); void setPaymentDate(const util::Timestamp& paymentDate); void setPaymentMethod(util::PaymentMode paymentMethod); void setStatus(util::PaymentStatus status); + std::string serialize() const; + static Invoice* deserialize(const std::string&); + static std::string getHeaders(); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp index 04e9195..214a8e0 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.cpp @@ -1,14 +1,51 @@ +/* +File: JobCard.cpp +Description: Implementation file containing the method definitions of the + JobCard class, including constructors, getters, and setters + for job card attributes. +Author: Trenser +Date:19-May-2026 +*/ + +#include +#include #include "JobCard.h" +#include "Factory.h" +#include "StringHelper.h" +#include "Enums.h" int JobCard::m_uid = 0; +/* +Function: JobCard +Description: Default constructor that initializes a new job card with + a unique ID and default values. +Parameter: None +Return type: Constructor +*/ JobCard::JobCard() : m_id("JC" + std::to_string(++m_uid)), m_booking(nullptr), m_service(nullptr), m_technician(nullptr), - m_status(ServiceJobStatus()) {} + m_status(util::ServiceJobStatus()) {} +/* +Function: JobCard +Description: Parameterized constructor that initializes a new job card with a unique ID and specified details. +Parameters: + - bookingId: ID of the associated service booking. + - booking: Pointer to the ServiceBooking object. + - service: Pointer to the Service object. + - serviceId: ID of the associated service. + - technicianId: ID of the assigned technician. + - technician: Pointer to the User object representing the technician. + - assignedDate: Timestamp of when the job was assigned. + - status: Current status of the job (STARTED/COMPLETED). + - completionDate: Timestamp of when the job was completed. +Returns: + - A new JobCard object. +*/ JobCard::JobCard(const std::string& bookingId, ServiceBooking* booking, Service* service, @@ -16,7 +53,7 @@ JobCard::JobCard(const std::string& bookingId, const std::string& technicianId, User* technician, const util::Timestamp& assignedDate, - ServiceJobStatus status, + util::ServiceJobStatus status, const util::Timestamp& completionDate ) : m_id("JC" + std::to_string(++m_uid)), @@ -30,102 +67,363 @@ JobCard::JobCard(const std::string& bookingId, m_status(status), m_completionDate(completionDate) {} +/* +Function: JobCard (parameterized constructor with ID) +Description: Initializes a job card with an existing ID, booking ID, service ID, + technician ID, assignment date, completion date, and status. + Updates UID tracking based on ID. +Parameters: + - id: const std::string&, unique job card ID + - bookingId: const std::string&, ID of the booking + - serviceId: const std::string&, ID of the service + - technicianId: const std::string&, ID of the technician + - assignedDate: const util::Timestamp&, date of assignment + - status: util::ServiceJobStatus, job status + - completionDate: const util::Timestamp&, date of completion +Returns: + - A new JobCard object +*/ +JobCard::JobCard(const std::string& id, + const std::string& bookingId, + const std::string& serviceId, + const std::string& technicianId, + const util::Timestamp& assignedDate, + util::ServiceJobStatus status, + const util::Timestamp& completionDate +) + : m_id(id), + m_bookingId(bookingId), + m_booking(nullptr), + m_service(nullptr), + m_serviceId(serviceId), + m_technicianId(technicianId), + m_technician(nullptr), + m_assignedDate(assignedDate), + m_status(status), + m_completionDate(completionDate) +{ + int idNumber = util::extractNumber(m_id); + if (idNumber > m_uid) + { + m_uid = idNumber; + } +} + +/* +Function: getId +Description: Retrieves the unique ID of the job card. +Returns: + - const std::string& representing the job card ID. +*/ const std::string& JobCard::getId() const { return m_id; } +/* +Function: getBookingId +Description: Retrieves the booking ID associated with the job card. +Returns: + - const std::string& representing the booking ID. +*/ const std::string& JobCard::getBookingId() const { return m_bookingId; } +/* +Function: getBooking +Description: Retrieves the pointer to the associated ServiceBooking. +Returns: + - ServiceBooking* representing the booking. +*/ ServiceBooking* JobCard::getBooking() const { return m_booking; } +/* +Function: getService +Description: Retrieves the pointer to the associated Service. +Returns: + - Service* representing the service. +*/ Service* JobCard::getService() const { return m_service; } +/* +Function: getServiceId +Description: Retrieves the service ID associated with the job card. +Returns: + - const std::string& representing the service ID. +*/ const std::string& JobCard::getServiceId() const { return m_serviceId; } +/* +Function: getTechnicianId +Description: Retrieves the technician ID associated with the job card. +Returns: + - const std::string& representing the technician ID. +*/ const std::string& JobCard::getTechnicianId() const { return m_technicianId; } +/* +Function: getTechnician +Description: Retrieves the pointer to the assigned technician. +Returns: + - User* representing the technician. +*/ User* JobCard::getTechnician() const { return m_technician; } +/* +Function: getAssignedDate +Description: Retrieves the timestamp of when the job was assigned. +Returns: + - const util::Timestamp& representing the assigned date. +*/ const util::Timestamp& JobCard::getAssignedDate() const { return m_assignedDate; } -ServiceJobStatus JobCard::getStatus() const +/* +Function: getStatus +Description: Retrieves the current status of the job. +Returns: + - ServiceJobStatus representing the job status. +*/ +util::ServiceJobStatus JobCard::getStatus() const { return m_status; } +/* +Function: getCompletionDate +Description: Retrieves the timestamp of when the job was completed. +Returns: + - const util::Timestamp& representing the completion date. +*/ const util::Timestamp& JobCard::getCompletionDate() const { return m_completionDate; } +/* +Function: setId +Description: Sets the unique ID of the job card. +Parameters: + - id: New job card ID string. +Returns: + - void +*/ void JobCard::setId(const std::string& id) { m_id = id; } +/* +Function: setBookingId +Description: Sets the booking ID associated with the job card. +Parameters: + - bookingId: New booking ID string. +Returns: + - void +*/ void JobCard::setBookingId(const std::string& bookingId) { m_bookingId = bookingId; } +/* +Function: setBooking +Description: Sets the associated ServiceBooking pointer. +Parameters: + - booking: Pointer to the ServiceBooking object. +Returns: + - void +*/ void JobCard::setBooking(ServiceBooking* booking) { m_booking = booking; } +/* +Function: setService +Description: Sets the associated Service pointer. +Parameters: + - service: Pointer to the Service object. +Returns: + - void +*/ void JobCard::setService(Service* service) { m_service = service; } +/* +Function: setServiceId +Description: Sets the service ID associated with the job card. +Parameters: + - serviceId: New service ID string. +Returns: + - void +*/ void JobCard::setServiceId(const std::string& serviceId) { m_serviceId = serviceId; } +/* +Function: setTechnicianId +Description: Sets the technician ID associated with the job card. +Parameters: + - technicianId: New technician ID string. +Returns: + - void +*/ void JobCard::setTechnicianId(const std::string& technicianId) { m_technicianId = technicianId; } +/* +Function: setTechnician +Description: Sets the pointer to the assigned technician. +Parameters: + - technician: Pointer to the User object. +Returns: + - void +*/ void JobCard::setTechnician(User* technician) { m_technician = technician; } +/* +Function: setAssignedDate +Description: Sets the timestamp of when the job was assigned. +Parameters: + - assignedDate: New timestamp for the assigned date. +Returns: + - void +*/ void JobCard::setAssignedDate(const util::Timestamp& assignedDate) { m_assignedDate = assignedDate; } -void JobCard::setStatus(ServiceJobStatus status) +/* +Function: setStatus +Description: Sets the current status of the job. +Parameters: + - status: New job status value. +Returns: + - void +*/ +void JobCard::setStatus(util::ServiceJobStatus status) { m_status = status; } +/* +Function: setCompletionDate +Description: Sets the timestamp of when the job was completed. +Parameters: + - completionDate: New timestamp for the completion date. +Returns: + - void +*/ void JobCard::setCompletionDate(const util::Timestamp& completionDate) { m_completionDate = completionDate; +} + +/* +Function: serialize +Description: Serializes the job card into a CSV-formatted string. +Parameters: + - None +Returns: + - std::string: Serialized job card record +*/ +std::string JobCard::serialize() const +{ + std::ostringstream serializedJobCard; + serializedJobCard << m_id << ',' + << m_bookingId << ',' + << m_serviceId << ',' + << m_technicianId << ',' + << m_assignedDate.toString() << ',' + << util::getServiceJobStatusString(m_status) << ',' + << m_completionDate.toString(); + return serializedJobCard.str(); +} + +/* +Function: deserialize +Description: Deserializes a CSV-formatted string into a JobCard object. +Parameters: + - record: const std::string&, serialized job card record +Returns: + - JobCard*: Pointer to the deserialized JobCard object +Throws: + - std::runtime_error if timestamp parsing fails +*/ +JobCard* JobCard::deserialize(const std::string& record) +{ + std::string id, bookingId, serviceId, technicianId; + std::string assignedDateString, statusString, completionDateString; + std::istringstream serializedJobCard(record); + getline(serializedJobCard, id, ','); + getline(serializedJobCard, bookingId, ','); + getline(serializedJobCard, serviceId, ','); + getline(serializedJobCard, technicianId, ','); + getline(serializedJobCard, assignedDateString, ','); + getline(serializedJobCard, statusString, ','); + getline(serializedJobCard, completionDateString, ','); + util::Timestamp assignedDate; + util::Timestamp completionDate; + try + { + assignedDate = util::Timestamp::fromString(assignedDateString); + completionDate = util::Timestamp::fromString(completionDateString); + } + catch (...) + { + throw std::runtime_error("Invalid timestamp"); + } + util::ServiceJobStatus status = util::getServiceJobStatus(statusString); + return Factory::getObject( + id, + bookingId, + serviceId, + technicianId, + assignedDate, + status, + completionDate + ); +} + +/* +Function: getHeaders +Description: Retrieves the CSV headers for job card serialization. +Parameters: + - None +Returns: + - std::string: Header string ("ID,BookingID,ServiceID,TechnicianID,AssignedDate,Status,CompletionDate") +*/ +std::string JobCard::getHeaders() +{ + return "ID,BookingID,ServiceID,TechnicianID,AssignedDate,Status,CompletionDate"; } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h index 15a8a5d..a845263 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/JobCard.h @@ -1,13 +1,21 @@ +/* +File: JobCard.h +Description: Header file declaring the JobCard class, which represents + a service job card containing booking, service, technician, + and status details. +Author: Trenser +Date:19-May-2026 +*/ + #pragma once #include +#include "Enums.h" #include "Timestamp.h" class ServiceBooking; class Service; class User; -enum class ServiceJobStatus : int; - class JobCard { private: @@ -20,9 +28,8 @@ private: std::string m_technicianId; User* m_technician; util::Timestamp m_assignedDate; - ServiceJobStatus m_status; + util::ServiceJobStatus m_status; util::Timestamp m_completionDate; - public: JobCard(); JobCard(const std::string& bookingId, @@ -32,7 +39,15 @@ public: const std::string& technicianId, User* technician, const util::Timestamp& assignedDate, - ServiceJobStatus status, + util::ServiceJobStatus status, + const util::Timestamp& completionDate + ); + JobCard(const std::string& id, + const std::string& bookingId, + const std::string& serviceId, + const std::string& technicianId, + const util::Timestamp& assignedDate, + util::ServiceJobStatus status, const util::Timestamp& completionDate ); const std::string& getId() const; @@ -43,7 +58,7 @@ public: const std::string& getTechnicianId() const; User* getTechnician() const; const util::Timestamp& getAssignedDate() const; - ServiceJobStatus getStatus() const; + util::ServiceJobStatus getStatus() const; const util::Timestamp& getCompletionDate() const; void setId(const std::string& id); void setBookingId(const std::string& bookingId); @@ -53,6 +68,9 @@ public: void setTechnicianId(const std::string& technicianId); void setTechnician(User* technician); void setAssignedDate(const util::Timestamp& assignedDate); - void setStatus(ServiceJobStatus status); + void setStatus(util::ServiceJobStatus status); void setCompletionDate(const util::Timestamp& completionDate); + std::string serialize() const; + static JobCard* deserialize(const std::string&); + static std::string getHeaders(); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Notification.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Notification.cpp index dc3ed1d..0bae917 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Notification.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Notification.cpp @@ -1,11 +1,42 @@ +/* +File: Notification.cpp +Description: Implements the Notification class which represents system notifications in the Vehicle Service Management System. + Provides constructors, accessors, and mutators for notification details such as ID, recipient, title, message, and timestamp. +Author: Trenser +Date: 19-May-2026 +*/ + +#include #include "Notification.h" +#include "StringHelper.h" +#include "Factory.h" int Notification::m_uid = 0; +/* +Function: Notification +Description: Default constructor that initializes a new notification with a unique ID and null recipient. +Parameters: + - None +Returns: + - A new Notification object. +*/ Notification::Notification() : m_id("NOT" + std::to_string(++m_uid)), m_recipient(nullptr) {} +/* +Function: Notification +Description: Parameterized constructor that initializes a new notification with a unique ID and specified details. +Parameters: + - recipientUserId: ID of the recipient user. + - recipient: Pointer to the User object representing the recipient. + - title: Title of the notification. + - message: Message content of the notification. + - createdAt: Timestamp of when the notification was created. +Returns: + - A new Notification object. +*/ Notification::Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt) : m_id("NOT" + std::to_string(++m_uid)), m_recipientUserId(recipientUserId), @@ -14,62 +45,243 @@ Notification::Notification(const std::string& recipientUserId, User* recipient, m_message(message), m_createdAt(createdAt) {} +/* +Function: Notification (parameterized constructor with ID) +Description: Initializes a notification with an existing ID, recipient details, + title, message, and creation timestamp. Updates UID tracking based on ID. +Parameters: + - id: const std::string&, unique notification ID + - recipientUserId: const std::string&, ID of the recipient user + - title: const std::string&, notification title + - message: const std::string&, notification message + - createdAt: const util::Timestamp&, timestamp of creation +Returns: + - A new Notification object +*/ +Notification::Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt) + : m_id(id), + m_recipientUserId(recipientUserId), + m_recipient(nullptr), + m_title(title), + m_message(message), + m_createdAt(createdAt) +{ + int idNumber = util::extractNumber(m_id); + if (idNumber > m_uid) + { + m_uid = idNumber; + } +} + +/* +Function: getId +Description: Retrieves the unique ID of the notification. +Returns: + - const std::string& representing the notification ID. +*/ const std::string& Notification::getId() const { return m_id; } +/* +Function: getRecipientUserId +Description: Retrieves the recipient user ID associated with the notification. +Returns: + - const std::string& representing the recipient user ID. +*/ const std::string& Notification::getRecipientUserId() const { return m_recipientUserId; } +/* +Function: getRecipient +Description: Retrieves the pointer to the recipient user. +Returns: + - User* representing the recipient. +*/ User* Notification::getRecipient() const { return m_recipient; } +/* +Function: getTitle +Description: Retrieves the title of the notification. +Returns: + - const std::string& representing the notification title. +*/ const std::string& Notification::getTitle() const { return m_title; } +/* +Function: getMessage +Description: Retrieves the message content of the notification. +Returns: + - const std::string& representing the notification message. +*/ const std::string& Notification::getMessage() const { return m_message; } +/* +Function: getCreatedAt +Description: Retrieves the timestamp of when the notification was created. +Returns: + - const util::Timestamp& representing the creation timestamp. +*/ const util::Timestamp& Notification::getCreatedAt() const { return m_createdAt; } +/* +Function: setId +Description: Sets the unique ID of the notification. +Parameters: + - id: New notification ID string. +Returns: + - void +*/ void Notification::setId(const std::string& id) { m_id = id; } +/* +Function: setRecipientUserId +Description: Sets the recipient user ID for the notification. +Parameters: + - recipientUserId: New recipient user ID string. +Returns: + - void +*/ void Notification::setRecipientUserId(const std::string& recipientUserId) { m_recipientUserId = recipientUserId; } +/* +Function: setRecipient +Description: Sets the recipient user pointer for the notification. +Parameters: + - recipient: Pointer to the User object. +Returns: + - void +*/ void Notification::setRecipient(User* recipient) { m_recipient = recipient; } +/* +Function: setTitle +Description: Sets the title of the notification. +Parameters: + - title: New notification title string. +Returns: + - void +*/ void Notification::setTitle(const std::string& title) { m_title = title; } +/* +Function: setMessage +Description: Sets the message content of the notification. +Parameters: + - message: New notification message string. +Returns: + - void +*/ void Notification::setMessage(const std::string& message) { m_message = message; } +/* +Function: setCreatedAt +Description: Sets the timestamp of when the notification was created. +Parameters: + - createdAt: New timestamp value. +Returns: + - void +*/ void Notification::setCreatedAt(const util::Timestamp& createdAt) { m_createdAt = createdAt; +} + +/* +Function: serialize +Description: Serializes the notification into a CSV-formatted string. +Parameters: + - None +Returns: + - std::string: Serialized notification record +*/ +std::string Notification::serialize() const +{ + std::ostringstream serializedNotification; + serializedNotification << m_id << ',' + << m_recipientUserId << ',' + << m_title << ',' + << m_message << ',' + << m_createdAt.toString(); + return serializedNotification.str(); +} + +/* +Function: deserialize +Description: Deserializes a CSV-formatted string into a Notification object. +Parameters: + - record: const std::string&, serialized notification record +Returns: + - Notification*: Pointer to the deserialized Notification object +Throws: + - std::runtime_error if timestamp parsing fails +*/ +Notification* Notification::deserialize(const std::string& record) +{ + std::string id, recipientUserId, title, message, createdAtTimestampString; + std::istringstream serializedNotification(record); + getline(serializedNotification, id, ','); + getline(serializedNotification, recipientUserId, ','); + getline(serializedNotification, title, ','); + getline(serializedNotification, message, ','); + getline(serializedNotification, createdAtTimestampString, ','); + util::Timestamp createdAtTimestamp; + try + { + createdAtTimestamp = util::Timestamp::fromString(createdAtTimestampString); + } + catch (...) + { + throw std::runtime_error("Invalid createdAt timestamp"); + } + return Factory::getObject( + id, + recipientUserId, + title, + message, + createdAtTimestamp + ); +} + +/* +Function: getHeaders +Description: Retrieves the CSV headers for notification serialization. +Parameters: + - None +Returns: + - std::string: Header string ("ID,RecipientID,Title,Message,Timestamp") +*/ +std::string Notification::getHeaders() +{ + return "ID,RecipientID,Title,Message,Timestamp"; } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Notification.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Notification.h index f86499e..57869fa 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Notification.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Notification.h @@ -1,3 +1,11 @@ +/* +File: Notification.h +Description: Declares the Notification class which represents system messages sent to users in the Vehicle Service Management System. + Each notification includes a unique ID, recipient details, title, message content, and timestamp of creation. +Author: Trenser +Date: 19-May-2026 +*/ + #pragma once #include #include "Timestamp.h" @@ -17,6 +25,7 @@ private: public: Notification(); Notification(const std::string& recipientUserId, User* recipient, const std::string& title, const std::string& message, const util::Timestamp& createdAt); + Notification(const std::string& id, const std::string& recipientUserId, const std::string& title, const std::string& message, const util::Timestamp& createdAt); const std::string& getId() const; const std::string& getRecipientUserId() const; User* getRecipient() const; @@ -29,4 +38,7 @@ public: void setTitle(const std::string& title); void setMessage(const std::string& message); void setCreatedAt(const util::Timestamp& createdAt); + std::string serialize() const; + static Notification* deserialize(const std::string&); + static std::string getHeaders(); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Service.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Service.cpp index fa7f509..0717467 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Service.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Service.cpp @@ -1,65 +1,337 @@ +/* +File: Service.cpp +Description: Implements the Service class which represents a vehicle service in the Vehicle Service Management System. + Provides constructors, accessors, and mutators for service details such as ID, name, required inventory items, + labor cost, and state. +Author: Trenser +Date: 19-May-2026 +*/ + +#include #include "Service.h" +#include "InventoryItem.h" +#include "StringHelper.h" +#include "Factory.h" int Service::m_uid = 0; +/* +Function: Service +Description: Default constructor that initializes a new service with a unique ID, + active state, and zero labor cost. +Parameters: + - None +Returns: + - A new Service object. +*/ Service::Service() : m_id("SRV" + std::to_string(++m_uid)), m_status(util::State::ACTIVE), m_laborCost(0.0) {} +/* +Function: Service +Description: Parameterized constructor that initializes a new service with a unique ID and specified details. +Parameters: + - name: Name of the service. + - requiredInventoryItems: Map of inventory items required for the service. + - laborCost: Labor cost associated with the service. +Returns: + - A new Service object. +*/ Service::Service(const std::string& name, const util::Map& requiredInventoryItems, double laborCost) : m_id("SRV" + std::to_string(++m_uid)), m_name(name), m_requiredInventoryItems(requiredInventoryItems), m_status(util::State::ACTIVE), - m_laborCost(laborCost) {} + m_laborCost(laborCost) +{ + int numberOfInventoryItems = m_requiredInventoryItems.getSize(); + auto inventoryItemPointers = m_requiredInventoryItems.getValues(); + for (int index = 0; index < numberOfInventoryItems; index++) + { + m_requiredInventoryItemIDs.push_back(inventoryItemPointers[index]->getId()); + } +} +/* +Function: Service (parameterized constructor with ID) +Description: Initializes a service with an existing ID, name, inventory item IDs, + labor cost, and state. Updates UID tracking based on ID. +Parameters: + - id: const std::string&, unique service ID + - name: const std::string&, name of the service + - requiredInventoryItemIDs: const util::Vector&, IDs of required inventory items + - laborCost: double, labor cost of the service + - status: util::State, state of the service (ACTIVE/INACTIVE) +Returns: + - A new Service object +*/ +Service::Service(const std::string& id, const std::string& name, const util::Vector& requiredInventoryItemIDs, double laborCost, util::State status) + : m_id(id), + m_name(name), + m_requiredInventoryItemIDs(requiredInventoryItemIDs), + m_status(status), + m_laborCost(laborCost) +{ + int idNumber = util::extractNumber(m_id); + if (idNumber > m_uid) + { + m_uid = idNumber; + } +} + +/* +Function: getId +Description: Retrieves the unique ID of the service. +Returns: + - const std::string& representing the service ID. +*/ const std::string& Service::getId() const { return m_id; } +/* +Function: getName +Description: Retrieves the name of the service. +Returns: + - const std::string& representing the service name. +*/ const std::string& Service::getName() const { return m_name; } +/* +Function: getRequiredInventoryItemIDs +Description: Retrieves the IDs of required inventory items for the service. +Parameters: + - None +Returns: + - const util::Vector&: Inventory item IDs +*/ +const util::Vector& Service::getRequiredInventoryItemIDs() const +{ + return m_requiredInventoryItemIDs; +} + +/* +Function: getRequiredInventoryItems +Description: Retrieves the map of inventory items required for the service. +Returns: + - const util::Map& representing the required inventory items. +*/ const util::Map& Service::getRequiredInventoryItems() const { return m_requiredInventoryItems; } +/* +Function: getLaborCost +Description: Retrieves the labor cost associated with the service. +Returns: + - double representing the labor cost. +*/ double Service::getLaborCost() const { return m_laborCost; } +/* +Function: getState +Description: Retrieves the current state (ACTIVE/INACTIVE) of the service. +Returns: + - util::State representing the service state. +*/ util::State Service::getState() const { return m_status; } +/* +Function: setId +Description: Sets the unique ID of the service. +Parameters: + - id: New service ID string. +Returns: + - void +*/ void Service::setId(const std::string& id) { m_id = id; } +/* +Function: setName +Description: Sets the name of the service. +Parameters: + - name: New service name string. +Returns: + - void +*/ void Service::setName(const std::string& name) { m_name = name; } +/* +Function: setRequiredInventoryItems +Description: Sets the inventory items required for the service. +Parameters: + - requiredInventoryItems: Map of inventory items. +Returns: + - void +*/ void Service::setRequiredInventoryItems(const util::Map& requiredInventoryItems) { m_requiredInventoryItems = requiredInventoryItems; + m_requiredInventoryItemIDs.clear(); + int numberOfRequiredInventoryItems = m_requiredInventoryItems.getSize(); + auto inventoryItemPointers = m_requiredInventoryItems.getValues(); + for (int index = 0; index < numberOfRequiredInventoryItems; index++) + { + m_requiredInventoryItemIDs.push_back(inventoryItemPointers[index]->getId()); + } } +/* +Function: setLaborCost +Description: Sets the labor cost for the service. +Parameters: + - laborCost: New labor cost value. +Returns: + - void +*/ void Service::setLaborCost(double laborCost) { m_laborCost = laborCost; } +/* +Function: setState +Description: Sets the state (ACTIVE/INACTIVE) of the service. +Parameters: + - status: New state value. +Returns: + - void +*/ void Service::setState(util::State status) { m_status = status; +} + +/* +Function: getInventoryItemIDsAsString (static helper) +Description: Converts a vector of inventory item IDs into a single string separated by '|'. +Parameters: + - inventoryItemIds: const util::Vector&, vector of inventory item IDs +Returns: + - std::string: Concatenated inventory item IDs string +*/ +static std::string getInventoryItemIDsAsString(const util::Vector& inventoryItemIds) +{ + int numberOfInventoryItems = inventoryItemIds.getSize(); + std::string inventoryItemIDs; + for (int index = 0; index < numberOfInventoryItems; index++) + { + inventoryItemIDs += inventoryItemIds[index]; + if (index < numberOfInventoryItems - 1) + { + inventoryItemIDs += '|'; + } + } + return inventoryItemIDs; +} + +/* +Function: getInventoryItemIDsAsVector (static helper) +Description: Converts a string of inventory item IDs separated by '|' into a vector. +Parameters: + - inventoryItemIDsString: const std::string&, concatenated inventory item IDs string +Returns: + - util::Vector: Vector of inventory item IDs +*/ +static util::Vector getInventoryItemIDsAsVector(const std::string& inventoryItemIDsString) +{ + util::Vector inventoryItemIDs; + std::string inventoryItemID; + std::istringstream serializedInventoryItemIDs(inventoryItemIDsString); + while (getline(serializedInventoryItemIDs, inventoryItemID, '|')) + { + inventoryItemIDs.push_back(inventoryItemID); + } + return inventoryItemIDs; +} + +/* +Function: serialize +Description: Serializes the service into a CSV-formatted string. +Parameters: + - None +Returns: + - std::string: Serialized service record +*/ +std::string Service::serialize() const +{ + std::ostringstream serializedService; + serializedService << m_id << ',' + << m_name << ',' + << getInventoryItemIDsAsString(m_requiredInventoryItemIDs) << ',' + << m_laborCost << ',' + << util::getStateString(m_status); + return serializedService.str(); +} + +/* +Function: deserialize +Description: Deserializes a CSV-formatted string into a Service object. +Parameters: + - record: const std::string&, serialized service record +Returns: + - Service*: Pointer to the deserialized Service object +Throws: + - std::runtime_error if labor cost parsing fails +*/ +Service* Service::deserialize(const std::string& record) +{ + std::string id, name; + std::string inventoryItemIDsString, laborCostString, statusString; + double laborCost; + std::istringstream serializedService(record); + getline(serializedService, id, ','); + getline(serializedService, name, ','); + getline(serializedService, inventoryItemIDsString, ','); + getline(serializedService, laborCostString, ','); + getline(serializedService, statusString, ','); + util::Vector inventoryItemIDs = getInventoryItemIDsAsVector(inventoryItemIDsString); + try + { + laborCost = std::stod(laborCostString); + } + catch (...) + { + throw std::runtime_error("Invalid labor cost"); + } + util::State status = util::getState(statusString); + return Factory::getObject( + id, + name, + inventoryItemIDs, + laborCost, + status + ); +} + +/* +Function: getHeaders +Description: Retrieves the CSV headers for service serialization. +Parameters: + - None +Returns: + - std::string: Header string ("ID,Name,InventoryIDs,LaborCost,Status") +*/ +std::string Service::getHeaders() +{ + return "ID,Name,InventoryIDs,LaborCost,Status"; } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Service.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Service.h index b0d3175..b80e674 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Service.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/Service.h @@ -1,6 +1,16 @@ +/* +File: Service.h +Description: Declares the Service class which represents a vehicle service in the Vehicle Service Management System. + Each service includes a unique ID, name, required inventory items, labor cost, and status. +Author: Trenser +Date: 19-May-2026 +*/ + + #pragma once #include #include "Map.h" +#include "Vector.h" #include "Enums.h" class InventoryItem; @@ -11,14 +21,17 @@ private: static int m_uid; std::string m_id; std::string m_name; + util::Vector m_requiredInventoryItemIDs; util::Map m_requiredInventoryItems; double m_laborCost; util::State m_status; public: Service(); Service(const std::string& name, const util::Map& requiredInventoryItems, double laborCost); + Service(const std::string& id, const std::string& name, const util::Vector& requiredInventoryItemIDs, double laborCost, util::State state); const std::string& getId() const; const std::string& getName() const; + const util::Vector& getRequiredInventoryItemIDs() const; const util::Map& getRequiredInventoryItems() const; double getLaborCost() const; util::State getState() const; @@ -27,4 +40,7 @@ public: void setRequiredInventoryItems(const util::Map& requiredInventoryItems); void setLaborCost(double laborCost); void setState(util::State status); + std::string serialize() const; + static Service* deserialize(const std::string&); + static std::string getHeaders(); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp index 1fdfaf0..31b9d87 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.cpp @@ -1,14 +1,52 @@ +/* +File: ServiceBooking.cpp +Description: Implementation file containing the method definitions of the + ServiceBooking class, including constructors, getters, and setters + for booking attributes. +Author: Trenser +Date:19-May-2026 +*/ +#include +#include #include "ServiceBooking.h" +#include "Service.h" +#include "Enums.h" +#include "Factory.h" +#include "StringHelper.h" int ServiceBooking::m_uid = 0; +/* +Function: ServiceBooking +Description: Default constructor that initializes a new service booking with a unique ID, + null customer, and zero discount percentage. +Parameters: None +Returns: A new ServiceBooking object. +*/ ServiceBooking::ServiceBooking() - : m_id("SRV" + std::to_string(++m_uid)), + : m_id("SBK" + std::to_string(++m_uid)), m_customer(nullptr), + m_assignedTechnician(nullptr), + m_status(util::ServiceJobStatus::PENDING), m_discountPercentage(0.0) {} +/* +Function: ServiceBooking +Description: Parameterized constructor that initializes a new service booking with a unique ID and specified details. +Parameters: + - id: Booking ID string. + - status: Current status of the booking (e.g., PENDING, COMPLETED). + - services: Map of services included in the booking. + - customerId: ID of the customer. + - customer: Pointer to the User object representing the customer. + - vehicleNumber: Vehicle registration number. + - vehicleBrand: Brand of the vehicle. + - vehicleModel: Model of the vehicle. + - discountPercentage: Discount applied to the booking. +Returns: + - A new ServiceBooking object. +*/ ServiceBooking::ServiceBooking( - const std::string& id, util::ServiceJobStatus status, const util::Map& services, @@ -17,11 +55,9 @@ ServiceBooking::ServiceBooking( const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel, - const std::string& assignedTechnicianId, - const std::string& assignedTechnician, double discountPercentage ) - : m_id("SRV" + std::to_string(++m_uid)), + : m_id("SBK" + std::to_string(++m_uid)), m_status(status), m_services(services), m_customerId(customerId), @@ -29,118 +65,456 @@ ServiceBooking::ServiceBooking( m_vehicleNumber(vehicleNumber), m_vehicleBrand(vehicleBrand), m_vehicleModel(vehicleModel), - m_assignedTechnicianId(assignedTechnicianId), - m_assignedTechnician(assignedTechnician), + m_assignedTechnicianId(""), + m_assignedTechnician(nullptr), m_discountPercentage(discountPercentage) { + int numberOfServices = m_services.getSize(); + auto servicePointers = m_services.getValues(); + for (int index = 0; index < numberOfServices; index++) + { + m_serviceIDs.push_back(servicePointers[index]->getId()); + } } +/* +Function: ServiceBooking (parameterized constructor with ID) +Description: Initializes a service booking with an existing ID, status, service IDs, + customer details, vehicle details, technician ID, and discount percentage. + Updates UID tracking based on ID. +Parameters: + - id: const std::string&, unique booking ID + - status: util::ServiceJobStatus, job status of the booking + - serviceIDs: const util::Vector&, IDs of booked services + - customerId: const std::string&, ID of the customer + - vehicleNumber: const std::string&, vehicle number + - vehicleBrand: const std::string&, vehicle brand + - vehicleModel: const std::string&, vehicle model + - assignedTechnicianId: const std::string&, ID of the assigned technician + - discountPercentage: double, discount applied +Returns: + - A new ServiceBooking object +*/ +ServiceBooking::ServiceBooking( + const std::string& id, + util::ServiceJobStatus status, + const util::Vector& serviceIDs, + const std::string& customerId, + const std::string& vehicleNumber, + const std::string& vehicleBrand, + const std::string& vehicleModel, + const std::string& assignedTechnicianId, + double discountPercentage +) + : m_id(id), + m_status(status), + m_serviceIDs(serviceIDs), + m_customerId(customerId), + m_customer(nullptr), + m_vehicleNumber(vehicleNumber), + m_vehicleBrand(vehicleBrand), + m_vehicleModel(vehicleModel), + m_assignedTechnicianId(assignedTechnicianId), + m_assignedTechnician(nullptr), + m_discountPercentage(discountPercentage) +{ + int idNumber = util::extractNumber(m_id); + if (idNumber > m_uid) + { + m_uid = idNumber; + } +} + +/* +Function: getId +Description: Retrieves the unique identifier of the service booking. +Parameter: None +Return type: const std::string& +*/ const std::string& ServiceBooking::getId() const { return m_id; } +/* +Function: getStatus +Description: Retrieves the current status of the service booking. +Parameter: None +Return type: util::ServiceJobStatus +*/ util::ServiceJobStatus ServiceBooking::getStatus() const { return m_status; } +/* +Function: getServiceIDs +Description: Retrieves the IDs of services booked. +Parameters: + - None +Returns: + - const util::Vector&: Service IDs +*/ +const util::Vector& ServiceBooking::getServiceIDs() const +{ + return m_serviceIDs; +} + +/* +Function: getServices +Description: Retrieves the services associated with the booking. +Parameter: None +Return type: const util::Map& +*/ +/* +Function: getServices +Description: Retrieves the services associated with the booking. +Parameter: None +Return type: const util::Map& +*/ const util::Map& ServiceBooking::getServices() const { return m_services; } +/* +Function: getCustomerId +Description: Retrieves the customer ID associated with the booking. +Parameter: None +Return type: const std::string& +*/ const std::string& ServiceBooking::getCustomerId() const { return m_customerId; } +/* +Function: getCustomer +Description: Retrieves the customer object associated with the booking. +Parameter: None +Return type: User* +*/ User* ServiceBooking::getCustomer() const { return m_customer; } +/* +Function: getVehicleNumber +Description: Retrieves the vehicle registration number for the booking. +Parameter: None +Return type: const std::string& +*/ const std::string& ServiceBooking::getVehicleNumber() const { return m_vehicleNumber; } +/* +Function: getVehicleBrand +Description: Retrieves the brand of the vehicle for the booking. +Parameter: None +Return type: const std::string& +*/ const std::string& ServiceBooking::getVehicleBrand() const { return m_vehicleBrand; } +/* +Function: getVehicleModel +Description: Retrieves the model of the vehicle for the booking. +Parameter: None +Return type: const std::string& +*/ const std::string& ServiceBooking::getVehicleModel() const { return m_vehicleModel; } +/* +Function: getAssignedTechnicianId +Description: Retrieves the ID of the technician assigned to the booking. +Parameter: None +Return type: const std::string& +*/ const std::string& ServiceBooking::getAssignedTechnicianId() const { return m_assignedTechnicianId; } -const std::string& ServiceBooking::getAssignedTechnician() const +/* +Function: getAssignedTechnician +Description: Retrieves the technician object assigned to the booking. +Parameter: None +Return type: User* +*/ +User* ServiceBooking::getAssignedTechnician() const { return m_assignedTechnician; } - +/* +Function: getDiscountPercentage +Description: Retrieves the discount percentage applied to the booking. +Parameter: None +Return type: double +*/ double ServiceBooking::getDiscountPercentage() const { return m_discountPercentage; } +/* +Function: setId +Description: Sets the unique identifier of the service booking. +Parameter: const std::string& id - new booking ID +Return type: void +*/ void ServiceBooking::setId(const std::string& id) { m_id = id; } +/* +Function: setStatus +Description: Sets the current status of the service booking. +Parameter: const util::ServiceJobStatus& status - new booking status +Return type: void +*/ void ServiceBooking::setStatus(const util::ServiceJobStatus& status) { m_status = status; } +/* +Function: setServices +Description: Sets the services associated with the booking. +Parameter: const util::Map& services - new services map +Return type: void +*/ void ServiceBooking::setServices(const util::Map& services) { m_services = services; + m_serviceIDs.clear(); + int numberOfServices = m_services.getSize(); + auto servicePointers = m_services.getValues(); + for (int index = 0; index < numberOfServices; index++) + { + m_serviceIDs.push_back(servicePointers[index]->getId()); + } } +/* +Function: setCustomerId +Description: Sets the customer ID for the booking. +Parameter: const std::string& customerId - new customer ID +Return type: void +*/ void ServiceBooking::setCustomerId(const std::string& customerId) { m_customerId = customerId; } +/* +Function: setCustomer +Description: Sets the customer object for the booking. +Parameter: User* customer - pointer to the customer object +Return type: void +*/ void ServiceBooking::setCustomer(User* customer) { m_customer = customer; } +/* +Function: setVehicleNumber +Description: Sets the vehicle registration number for the booking. +Parameter: const std::string& vehicleNumber - new vehicle number +Return type: void +*/ void ServiceBooking::setVehicleNumber(const std::string& vehicleNumber) { m_vehicleNumber = vehicleNumber; } +/* +Function: setVehicleBrand +Description: Sets the brand of the vehicle for the booking. +Parameter: const std::string& vehicleBrand - new vehicle brand +Return type: void +*/ void ServiceBooking::setVehicleBrand(const std::string& vehicleBrand) { m_vehicleBrand = vehicleBrand; } +/* +Function: setVehicleModel +Description: Sets the model of the vehicle for the booking. +Parameter: const std::string& vehicleModel - new vehicle model +Return type: void +*/ void ServiceBooking::setVehicleModel(const std::string& vehicleModel) { m_vehicleModel = vehicleModel; } +/* +Function: setAssignedTechnicianId +Description: Sets the ID of the technician assigned to the booking. +Parameter: const std::string& assignedTechnicianId - new technician ID +Return type: void +*/ void ServiceBooking::setAssignedTechnicianId(const std::string& assignedTechnicianId) { m_assignedTechnicianId = assignedTechnicianId; } -void ServiceBooking::setAssignedTechnician(const std::string& assignedTechnician) +/* +Function: setAssignedTechnician +Description: Sets the technician object assigned to the booking. +Parameter: User* assignedTechnician - pointer to the technician object +Return type: void +*/ +void ServiceBooking::setAssignedTechnician(User* assignedTechnician) { m_assignedTechnician = assignedTechnician; } +/* +Function: setDiscountPercentage +Description: Sets the discount percentage for the booking. +Parameter: double discountPercentage - new discount percentage +Return type: void +*/ void ServiceBooking::setDiscountPercentage(double discountPercentage) { m_discountPercentage = discountPercentage; +} + +/* +Function: getServiceIDsAsString (static helper) +Description: Converts a vector of service IDs into a single string separated by '|'. +Parameters: + - serviceIDs: const util::Vector&, vector of service IDs +Returns: + - std::string: Concatenated service IDs string +*/ +static std::string getServiceIDsAsString(const util::Vector& serviceIDs) +{ + int numberOfServices = serviceIDs.getSize(); + std::string serviceIDsString; + for (int index = 0; index < numberOfServices; index++) + { + serviceIDsString += serviceIDs[index]; + if (index < numberOfServices - 1) + { + serviceIDsString += '|'; + } + } + return serviceIDsString; +} + +/* +Function: getServiceIDsAsVector (static helper) +Description: Converts a string of service IDs separated by '|' into a vector. +Parameters: + - serviceIDsString: const std::string&, concatenated service IDs string +Returns: + - util::Vector: Vector of service IDs +*/ +static util::Vector getServiceIDsAsVector(const std::string& serviceIDsString) +{ + util::Vector serviceIDs; + std::string serviceID; + std::istringstream serializedServiceIDs(serviceIDsString); + while (getline(serializedServiceIDs, serviceID, '|')) + { + serviceIDs.push_back(serviceID); + } + return serviceIDs; +} + +/* +Function: serialize +Description: Serializes the service booking into a CSV-formatted string. +Parameters: + - None +Returns: + - std::string: Serialized booking record +*/ +std::string ServiceBooking::serialize() const +{ + std::ostringstream serializedBooking; + serializedBooking << m_id << ',' + << util::getServiceJobStatusString(m_status) << ',' + << getServiceIDsAsString(m_serviceIDs) << ',' + << m_customerId << ',' + << m_vehicleNumber << ',' + << m_vehicleBrand << ',' + << m_vehicleModel << ',' + << m_assignedTechnicianId << ',' + << m_discountPercentage << ','; + return serializedBooking.str(); +} + +/* +Function: deserialize +Description: Deserializes a CSV-formatted string into a ServiceBooking object. +Parameters: + - record: const std::string&, serialized booking record +Returns: + - ServiceBooking*: Pointer to the deserialized ServiceBooking object +Throws: + - std::runtime_error if discount percentage parsing fails +*/ +ServiceBooking* ServiceBooking::deserialize(const std::string& record) +{ + std::string id, customerId, vehicleNumber, vehicleBrand, vehicleModel, assignedTechnicianId; + std::string serviceJobStatusString, serviceIDsString, discountPercentageString; + double discountPercentage; + std::istringstream serializedBooking(record); + getline(serializedBooking, id, ','); + getline(serializedBooking, serviceJobStatusString, ','); + getline(serializedBooking, serviceIDsString, ','); + getline(serializedBooking, customerId, ','); + getline(serializedBooking, vehicleNumber, ','); + getline(serializedBooking, vehicleBrand, ','); + getline(serializedBooking, vehicleModel, ','); + getline(serializedBooking, assignedTechnicianId, ','); + getline(serializedBooking, discountPercentageString, ','); + util::Vector serviceIDs = getServiceIDsAsVector(serviceIDsString); + try + { + discountPercentage = std::stod(discountPercentageString); + } + catch (...) + { + throw std::runtime_error("Invalid discount percentage"); + } + util::ServiceJobStatus status = util::getServiceJobStatus(serviceJobStatusString); + return Factory::getObject( + id, + status, + serviceIDs, + customerId, + vehicleNumber, + vehicleBrand, + vehicleModel, + assignedTechnicianId, + discountPercentage + ); +} + +/* +Function: getHeaders +Description: Retrieves the CSV headers for service booking serialization. +Parameters: + - None +Returns: + - std::string: Header string ("ID,Status,ServiceIDs,CustomerID,VehicleNumber,VehicleBrand,VehicleModel,AssignedTechnicianID,DiscountPercentage") +*/ +std::string ServiceBooking::getHeaders() +{ + return "ID,Status,ServiceIDs,CustomerID,VehicleNumber,VehicleBrand,VehicleModel,AssignedTechnicianID,DiscountPercentage"; } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.h index 5ecc1b0..24acb32 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/ServiceBooking.h @@ -1,6 +1,15 @@ +/* +File: ServiceBooking.h +Description: Header file declaring the ServiceBooking class, which represents + a booking of services by a customer, including vehicle details, + assigned technician, and discount information. +Author: Trenser +Date:19-May-2026 +*/ #pragma once #include #include "Map.h" +#include "Vector.h" #include "Enums.h" class Service; @@ -12,6 +21,7 @@ private: static int m_uid; std::string m_id; util::ServiceJobStatus m_status; + util::Vector m_serviceIDs; util::Map m_services; std::string m_customerId; User* m_customer; @@ -19,12 +29,11 @@ private: std::string m_vehicleBrand; std::string m_vehicleModel; std::string m_assignedTechnicianId; - std::string m_assignedTechnician; + User* m_assignedTechnician; double m_discountPercentage; public: ServiceBooking(); ServiceBooking( - const std::string& id, util::ServiceJobStatus status, const util::Map& services, @@ -33,12 +42,22 @@ public: const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel, + double discountPercentage + ); + ServiceBooking( + const std::string& id, + util::ServiceJobStatus status, + const util::Vector& serviceIDs, + const std::string& customerId, + const std::string& vehicleNumber, + const std::string& vehicleBrand, + const std::string& vehicleModel, const std::string& assignedTechnicianId, - const std::string& assignedTechnician, double discountPercentage ); const std::string& getId() const; util::ServiceJobStatus getStatus() const; + const util::Vector& getServiceIDs() const; const util::Map& getServices() const; const std::string& getCustomerId() const; User* getCustomer() const; @@ -46,7 +65,7 @@ public: const std::string& getVehicleBrand() const; const std::string& getVehicleModel() const; const std::string& getAssignedTechnicianId() const; - const std::string& getAssignedTechnician() const; + User* getAssignedTechnician() const; double getDiscountPercentage() const; void setId(const std::string& id); void setStatus(const util::ServiceJobStatus& status); @@ -57,6 +76,9 @@ public: void setVehicleBrand(const std::string& vehicleBrand); void setVehicleModel(const std::string& vehicleModel); void setAssignedTechnicianId(const std::string& assignedTechnicianId); - void setAssignedTechnician(const std::string& assignedTechnician); + void setAssignedTechnician(User* assignedTechnician); void setDiscountPercentage(double discountPercentage); + std::string serialize() const; + static ServiceBooking* deserialize(const std::string&); + static std::string getHeaders(); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/User.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/User.cpp index 52d85a9..0b4e86e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/User.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/User.cpp @@ -1,14 +1,48 @@ +/* +File: User.cpp +Description: Implements the User class which represents system users in the Vehicle Service Management System. + Provides constructors, destructor, accessors, and mutators for user details such as ID, username, + password, name, phone, email, role, state, and notifications. +Author: Trenser +Date: 19-May-2026 +*/ + +#include #include "User.h" #include "Notification.h" #include "Enums.h" +#include "Factory.h" +#include "StringHelper.h" int User::m_uid = 0; +/* +Function: User +Description: Default constructor that initializes a new user with a unique ID, + default role as CUSTOMER, and active state. +Parameters: + - None +Returns: + - A new User object. +*/ User::User() : m_id("USR" + std::to_string(++m_uid)), m_type(util::UserType::CUSTOMER), m_status(util::State::ACTIVE) {} +/* +Function: User +Description: Parameterized constructor that initializes a new user with a unique ID and specified details. +Parameters: + - userName: Username for login. + - password: Password for authentication. + - name: Full name of the user. + - phone: Phone number of the user. + - email: Email address of the user. + - role: Role of the user (CUSTOMER, ADMIN, TECHNICIAN, etc.). +Returns: + - A new User object. +*/ User::User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role) : m_id("USR" + std::to_string(++m_uid)), m_userName(userName), @@ -19,104 +53,339 @@ User::User(const std::string& userName, const std::string& password, const std:: m_type(role), m_status(util::State::ACTIVE) {} -User::~User() +/* +Function: User (parameterized constructor with ID) +Description: Initializes a user with an existing ID, credentials, personal details, + role, and state. Updates UID tracking based on ID. +Parameters: + - userId: const std::string&, unique user ID + - userName: const std::string&, username + - password: const std::string&, password + - name: const std::string&, full name + - phone: const std::string&, phone number + - email: const std::string&, email address + - role: util::UserType, role of the user + - status: util::State, state of the user (ACTIVE/INACTIVE) +Returns: + - A new User object +*/ +User::User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status) + : m_id(userId), + m_userName(userName), + m_password(password), + m_name(name), + m_phone(phone), + m_email(email), + m_type(role), + m_status(status) { - for (int index = 0; index < m_notifications.getSize(); index++) + int idNumber = util::extractNumber(m_id); + if (idNumber > m_uid) { - delete m_notifications.getValues()[index]; + m_uid = idNumber; } } +/* +Function: ~User +Description: Destructor that cleans up dynamically allocated notifications associated with the user. +Parameters: + - None +Returns: + - void +*/ +User::~User() +{ + auto values = m_notifications.getValues(); + for (int index = 0; index < values.getSize(); index++) + { + delete values[index]; + } +} + +/* +Function: getId +Description: Retrieves the unique ID of the user. +Returns: + - const std::string& representing the user ID. +*/ const std::string& User::getId() const { return m_id; } +/* +Function: getUserName +Description: Retrieves the username of the user. +Returns: + - const std::string& representing the username. +*/ const std::string& User::getUserName() const { return m_userName; } +/* +Function: getPassword +Description: Retrieves the password of the user. +Returns: + - const std::string& representing the password. +*/ const std::string& User::getPassword() const { return m_password; } +/* +Function: getName +Description: Retrieves the full name of the user. +Returns: + - const std::string& representing the name. +*/ const std::string& User::getName() const { return m_name; } +/* +Function: getPhone +Description: Retrieves the phone number of the user. +Returns: + - const std::string& representing the phone number. +*/ const std::string& User::getPhone() const { return m_phone; } +/* +Function: getEmail +Description: Retrieves the email address of the user. +Returns: + - const std::string& representing the email. +*/ const std::string& User::getEmail() const { return m_email; } +/* +Function: getNotifications +Description: Retrieves the map of notifications associated with the user. +Returns: + - util::Map& representing the notifications. +*/ util::Map& User::getNotifications() { return m_notifications; } +/* +Function: getUserType +Description: Retrieves the role of the user. +Returns: + - util::UserType representing the user role. +*/ util::UserType User::getUserType() const { return m_type; } +/* +Function: getState +Description: Retrieves the current state (ACTIVE/INACTIVE) of the user. +Returns: + - util::State representing the user state. +*/ util::State User::getState() const { return m_status; } +/* +Function: setId +Description: Sets the unique ID of the user. +Parameters: + - id: New user ID string. +Returns: + - void +*/ void User::setId(const std::string& id) { m_id = id; } +/* +Function: setUserName +Description: Sets the username of the user. +Parameters: + - userName: New username string. +Returns: + - void +*/ void User::setUserName(const std::string& userName) { m_userName = userName; } +/* +Function: setPassword +Description: Sets the password of the user. +Parameters: + - password: New password string. +Returns: + - void +*/ void User::setPassword(const std::string& password) { m_password = password; } +/* +Function: setName +Description: Sets the full name of the user. +Parameters: + - name: New name string. +Returns: + - void +*/ void User::setName(const std::string& name) { m_name = name; } +/* +Function: setPhone +Description: Sets the phone number of the user. +Parameters: + - phone: New phone number string. +Returns: + - void +*/ void User::setPhone(const std::string& phone) { m_phone = phone; } +/* +Function: setEmail +Description: Sets the email address of the user. +Parameters: + - email: New email string. +Returns: + - void +*/ void User::setEmail(const std::string& email) { m_email = email; } +/* +Function: addNotification +Description: Adds a new notification to the user’s notification map. +Parameters: + - notification: Pointer to the Notification object. +Returns: + - void +*/ void User::addNotification(Notification* notification) { - m_notifications.insert(notification->getId(), notification); + if (notification) + { + m_notifications.insert(notification->getId(), notification); + } } +/* +Function: setRole +Description: Sets the role of the user. +Parameters: + - role: New user role value. +Returns: + - void +*/ void User::setRole(util::UserType role) { m_type = role; } +/* +Function: setState +Description: Sets the state (ACTIVE/INACTIVE) of the user. +Parameters: + - status: New state value. +Returns: + - void +*/ void User::setState(util::State status) { m_status = status; } -void User::update(Notification* notification) +/* +Function: serialize +Description: Serializes the user into a CSV-formatted string. +Parameters: + - None +Returns: + - std::string: Serialized user record +*/ +std::string User::serialize() const { + std::ostringstream serializedUser; + serializedUser << m_id << ',' + << m_userName << ',' + << m_password << ',' + << m_name << ',' + << m_phone << ',' + << m_email << ',' + << util::getUserTypeString(m_type) << ',' + << util::getStateString(m_status); + return serializedUser.str(); } + +/* +Function: deserialize +Description: Deserializes a CSV-formatted string into a User object. +Parameters: + - record: const std::string&, serialized user record +Returns: + - User*: Pointer to the deserialized User object +*/ +User* User::deserialize(const std::string& record) +{ + std::string id, name, username, phone, password, email; + std::string userTypeString, stateString; + std::istringstream serializedUser(record); + getline(serializedUser, id, ','); + getline(serializedUser, username, ','); + getline(serializedUser, password, ','); + getline(serializedUser, name, ','); + getline(serializedUser, phone, ','); + getline(serializedUser, email, ','); + getline(serializedUser, userTypeString, ','); + getline(serializedUser, stateString); + util::UserType userType = util::getUserType(userTypeString); + util::State status = util::getState(stateString); + return Factory::getObject(id, + username, + password, + name, + phone, + email, + userType, + status); +} + +/* +Function: getHeaders +Description: Retrieves the CSV headers for user serialization. +Parameters: + - None +Returns: + - std::string: Header string ("ID,Username,Password,Name,Phone,Email,UserType,UserStatus") +*/ +std::string User::getHeaders() +{ + return "ID,Username,Password,Name,Phone,Email,UserType,UserStatus"; +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/User.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/User.h index bde21e1..12923f6 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/User.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/models/User.h @@ -1,3 +1,12 @@ +/* +File: User.h +Description: Declares the User class which represents system users in the Vehicle Service Management System. + Each user has a unique ID, credentials, personal details, notifications, role type, and status. + The User class also implements the Observer interface to handle notifications. +Author: Trenser +Date: 19-May-2026 +*/ + #pragma once #include #include "Map.h" @@ -22,6 +31,7 @@ private: public: User(); User(const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role); + User(const std::string& userId, const std::string& userName, const std::string& password, const std::string& name, const std::string& phone, const std::string& email, util::UserType role, util::State status); ~User(); const std::string& getId() const; const std::string& getUserName() const; @@ -38,8 +48,10 @@ public: void setName(const std::string& name); void setPhone(const std::string& phone); void setEmail(const std::string& email); - void addNotification(Notification* notification); + void addNotification(Notification* notification) override; void setRole(util::UserType role); void setState(util::State status); - void update(Notification* notification) override; + std::string serialize() const; + static User* deserialize(const std::string&); + static std::string getHeaders(); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp index ca07fee..dc3a94c 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.cpp @@ -1,3 +1,82 @@ +/* +File: AuthenticationManagementService.cpp +Description: Implementation file containing the method definitions of the + AuthenticationManagementService class, including logout and + password change logic. +Author: Trenser +Date:19-May-2026 +*/ + +#include #include "AuthenticationManagementService.h" +#include "User.h" User* AuthenticationManagementService::m_authenticatedUser = nullptr; + +/* +Function: login +Description: Authenticates a user by checking the provided username and password + against the stored users in the DataStore. If successful, sets the + authenticated user. +Parameter: const std::string& username - user’s username + const std::string& password - user’s password +Return type: bool - true if login successful, false otherwise +*/ +bool AuthenticationManagementService::login(const std::string& username, const std::string& password) +{ + util::Map users = m_dataStore.getUsers(); + int usersMapSize = users.getSize(); + for (int index = 0; index < usersMapSize; index++) + { + User* user = users.getValueAt(index); + if (username == user->getUserName()) + { + if (password == user->getPassword()) + { + m_authenticatedUser = user; + return true; + } + return false; + } + } + return false; +} + +/* +Function: getAuthenticatedUser +Description: Retrieves the currently authenticated user. +Parameter: None +Return type: User* - pointer to the authenticated user +*/ +User* AuthenticationManagementService::getAuthenticatedUser() +{ + return m_authenticatedUser; +} + +/* +Function: logout +Description: Logs out the currently authenticated user by clearing the + static authenticated user pointer. +Parameter: None +Return type: void +*/ +void AuthenticationManagementService::logout() +{ + m_authenticatedUser = nullptr; +} + +/* +Function: changePassword +Description: Changes the password of the currently authenticated user. + Throws an exception if no user is logged in. +Parameter: const std::string& newPassword - new password to set +Return type: void +*/ +void AuthenticationManagementService::changePassword(const std::string& newPassword) +{ + if (m_authenticatedUser == nullptr) + { + throw std::runtime_error("There is no user currently logged in!"); + } + m_authenticatedUser->setPassword(newPassword); +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h index ee0ed91..47266a1 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/AuthenticationManagementService.h @@ -1,3 +1,12 @@ +/* +File: AuthenticationManagementService.h +Description: Header file declaring the AuthenticationManagementService class, which manages + user authentication, login, logout, password changes, and retrieval of the + authenticated user. +Author: Trenser +Date:19-May-2026 +*/ + #pragma once #include #include "DataStore.h" diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp index 39ef719..d08d957 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.cpp @@ -1 +1,341 @@ +/* +File: InventoryManagementService.cpp +Description: Implements the InventoryManagementService class, which manages inventory + items and observer relationships within the system. Provides methods + for loading and saving inventory items from persistent storage, as well + as attaching and persisting observers for notification handling. +Author: Trenser +Date: 22-May-2026 +*/ + +#include +#include "Config.h" +#include "Enums.h" +#include "Factory.h" +#include "FileManager.h" +#include "InventoryItem.h" #include "InventoryManagementService.h" +#include "Timestamp.h" +#include "User.h" +#include "Utility.h" +#include "Vector.h" + + +util::Map InventoryManagementService::m_observers{}; + +/* +Function: sendLowStockAlertsToAdmins (static helper) +Description: Sends low stock alert notifications to all admin users for a given inventory item. +Parameters: + - inventoryManagementService: InventoryManagementService&, service used to send notifications + - inventoryItem: const InventoryItem*, pointer to the low-stock inventory item + - adminUsers: const util::Vector&, list of admin users to notify +Returns: + - None +*/ +static void sendLowStockAlertsToAdmins(InventoryManagementService& inventoryManagementService, const InventoryItem* inventoryItem, const util::Vector& adminUsers) +{ + int adminUsersSize = adminUsers.getSize(); + for (int index = 0; index < adminUsersSize; index++) + { + std::string title = "Low Stock Alert"; + std::string message = "The inventory item with ID " + inventoryItem->getId() + " has very low quantity in the inventory"; + inventoryManagementService.sendNotification( + adminUsers[index], + title, + message + ); + } +} + +/* +Function: sendLowStockAlerts +Description: Sends alerts to user for inventory items with low stock +Parameters: + - None +Returns: + - None +*/ +void InventoryManagementService::sendLowStockAlerts() +{ + auto& inventoryItems = m_dataStore.getInventoryItems(); + if (inventoryItems.isEmpty()) + { + return; + } + int inventoryItemsSize = inventoryItems.getSize(); + auto& usersMap = m_dataStore.getUsers(); + int usersMapSize = usersMap.getSize(); + util::Vector adminUsers; + for (int index = 0; index < usersMapSize; index++) + { + User* user = usersMap.getValueAt(index); + if (user->getUserType() == util::UserType::ADMIN) + { + adminUsers.push_back(user); + } + } + int adminUsersSize = adminUsers.getSize(); + if (adminUsersSize < 1) + { + throw std::runtime_error("The system has no admins present!"); + } + for (int index = 0; index < inventoryItemsSize; index++) + { + InventoryItem* inventoryItem = inventoryItems.getValueAt(index); + if (inventoryItem && inventoryItem->getQuantity() < config::threshold::INVENTORY_LOW_STOCK_THRESHOLD) + { + sendLowStockAlertsToAdmins(*this, inventoryItem, adminUsers); + } + } +} + +/* +Function: getObserverIDs +Description: Retrieves the IDs of all observers currently attached to the + InventoryManagementService. +Parameters: + - None +Returns: + - util::Vector: Vector of observer user IDs +*/ +util::Vector InventoryManagementService::getObserverIDs() +{ + util::Vector observerIDs; + int numberOfObservers = m_observers.getSize(); + for (int index = 0; index < numberOfObservers; index++) + { + User* observer = m_observers.getValueAt(index); + if (observer) + { + observerIDs.push_back(observer->getId()); + } + } + return observerIDs; +} + +/* +Function: loadInventoryItems +Description: Loads inventory items from persistent storage into the datastore. + Uses FileManager to deserialize inventory items from the configured file. +Parameters: + - None +Returns: + - void +*/ +void InventoryManagementService::loadInventoryItems() +{ + util::FileManager inventoryItemFileManager(config::file::INVENTORYITEM_FILE); + auto& inventoryItems = m_dataStore.getInventoryItems(); + auto inventoryItemsMap = inventoryItemFileManager.load(); + int numberOfInventoryItems = inventoryItemsMap.getSize(); + for (int index = 0; index < numberOfInventoryItems; index++) + { + inventoryItems[inventoryItemsMap.getKeyAt(index)] = inventoryItemsMap.getValueAt(index); + } +} + +/* +Function: saveInventoryItems +Description: Saves inventory items from the datastore to persistent storage. + Uses FileManager to serialize inventory items into the configured file. +Parameters: + - None +Returns: + - void +*/ +void InventoryManagementService::saveInventoryItems() +{ + util::FileManager inventoryItemFileManager(config::file::INVENTORYITEM_FILE); + auto& inventoryItems = m_dataStore.getInventoryItems(); + inventoryItemFileManager.save(inventoryItems); +} + +/* +Function: loadObservers +Description: Loads observer IDs from persistent storage and attaches corresponding + users as observers to the InventoryManagementService. +Parameters: + - None +Returns: + - void +*/ +void InventoryManagementService::loadObservers() +{ + util::loadObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this, m_dataStore); +} + +/* +Function: saveObservers +Description: Saves the current observer IDs of the InventoryManagementService + to persistent storage for future retrieval. +Parameters: + - None +Returns: + - void +*/ +void InventoryManagementService::saveObservers() +{ + util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this); +} + +/* +Function: addInventoryItem +Description: Creates a new inventory item using the Factory and inserts it + into the DataStore. +Parameter: const std::string& partName - name of the part + int quantity - initial quantity of the part + double price - price of the part +Return type: void +*/ +void InventoryManagementService::addInventoryItem(const std::string& partName, int quantity, double price) +{ + InventoryItem* newItem = Factory::getObject(partName, quantity, price); + m_dataStore.getInventoryItems().insert(newItem->getId(), newItem); +} + +/* +Function: addInventoryItemStock +Description: Increases the stock quantity of an existing inventory item. +Parameter: const std::string& selectedItemId - ID of the inventory item + int quantity - quantity to add +Return type: void +*/ +void InventoryManagementService::addInventoryItemStock(const std::string& selectedItemId, int quantity) +{ + int index = m_dataStore.getInventoryItems().find(selectedItemId); + if (index != -1) + { + InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index); + if (item != nullptr) + { + int totalQuantity = item->getQuantity() + quantity; + item->setQuantity(totalQuantity); + } + } +} + +/* +Function: getInventoryItems +Description: Retrieves all inventory items stored in the DataStore. +Parameter: None +Return type: util::Map +*/ +util::Map InventoryManagementService::getInventoryItems() +{ + return m_dataStore.getInventoryItems(); +} + +/* +Function: removeInventoryItem +Description: Marks an inventory item as inactive instead of deleting it. +Parameter: const std::string& inventoryItemID - ID of the inventory item +Return type: void +*/ +void InventoryManagementService::removeInventoryItem(const std::string& inventoryItemID) +{ + int index = m_dataStore.getInventoryItems().find(inventoryItemID); + if (index != -1) + { + InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index); + if (item != nullptr) + { + item->setState(util::State::INACTIVE); + } + } +} + +/* +Function: getInventoryItem +Description: Retrieves a specific inventory item by its ID from the DataStore. +Parameter: const std::string& inventoryItemID - ID of the inventory item +Return type: InventoryItem* +*/ +InventoryItem* InventoryManagementService::getInventoryItem(const std::string& inventoryItemID) +{ + int index = m_dataStore.getInventoryItems().find(inventoryItemID); + if (index != -1) + { + return m_dataStore.getInventoryItems().getValueAt(index); + } + return nullptr; +} + +/* +Function: attach +Description: Adds a user to the observer list for receiving inventory notifications. +Parameters: + - user: User*, pointer to the user to be attached as an observer +Returns: + - None +*/ +void InventoryManagementService::attach(User* user) +{ + if (user) + { + const std::string& userID = user->getId(); + if (m_observers.find(userID) == -1) + { + m_observers[userID] = user; + } + } +} + +/* +Function: detach +Description: Removes a user from the observer list so they no longer receive inventory notifications. +Parameters: + - user: User*, pointer to the user to be detached from the observer list +Returns: + - None +*/ +void InventoryManagementService::detach(User* user) +{ + if (user) + { + const std::string& userID = user->getId(); + if (m_observers.find(userID) != -1) + { + m_observers.remove(userID); + } + } +} + +/* +Function: sendNotification +Description: Sends a notification to a user if they are subscribed as an observer. +Parameters: + - user: User*, pointer to the user receiving the notification + - title: std::string, title of the notification + - message: std::string, body/content of the notification +Returns: + - None +Throws: + - std::runtime_error if notification creation fails +*/ +void InventoryManagementService::sendNotification(User* user, const std::string& title, const std::string& message) +{ + if (user) + { + if (m_observers.find(user->getId()) != -1) + { + Notification* notification = + Factory::getObject( + user->getId(), + user, + title, + message, + util::Timestamp() + ); + if (notification) + { + user->addNotification(notification); + } + else + { + throw std::runtime_error("Failed to create notification"); + } + } + } +} + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.h index 099b964..f5db383 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/InventoryManagementService.h @@ -1,6 +1,16 @@ +/* +File: InventoryManagementService.h +Description: Header file declaring the InventoryManagementService class, + which manages inventory items, stock updates, and notifications + related to low stock alerts. Inherits from NotificationManagementService. +Author: Trenser +Date:19-May-2026 +*/ + #pragma once #include #include "Map.h" +#include "Vector.h" #include "NotificationManagementService.h" #include "DataStore.h" @@ -11,14 +21,20 @@ class InventoryManagementService : public NotificationManagementService private: DataStore& m_dataStore; static util::Map m_observers; + util::Vector getObserverIDs() override; public: InventoryManagementService() : m_dataStore(DataStore::getInstance()) {} util::Map getInventoryItems(); InventoryItem* getInventoryItem(const std::string& inventoryItemID); void addInventoryItem(const std::string& partName, int quantity, double price); void removeInventoryItem(const std::string& inventoryItemID); + void addInventoryItemStock(const std::string& selectedItemId, int quantity); void sendLowStockAlerts(); void sendNotification(User* user, const std::string& title, const std::string& message) override; void attach(User* user) override; void detach(User* user) override; + void loadInventoryItems(); + void saveInventoryItems(); + void loadObservers(); + void saveObservers(); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/NotificationManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/NotificationManagementService.h index b193b1d..33d214a 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/NotificationManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/NotificationManagementService.h @@ -1,6 +1,15 @@ +/* +File: NotificationManagementService.h +Description: Declares the NotificationManagementService abstract class which defines the contract for managing notifications in the Vehicle Service Management System. + Implements the Subject interface and provides pure virtual methods for sending notifications and managing user subscriptions (attach/detach). +Author: Trenser +Date: 19-May-2026 +*/ + #pragma once #include #include "Subject.h" +#include "Notification.h" #include "User.h" class NotificationManagementService : public Subject @@ -10,4 +19,5 @@ public: virtual void sendNotification(User* recipient, const std::string& title, const std::string& message) = 0; virtual void attach(User* user) = 0; virtual void detach(User* user) = 0; + virtual util::Vector getObserverIDs() = 0; }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp index 786ebcf..2733577 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.cpp @@ -1 +1,387 @@ +/* +File: PaymentManagementService.cpp +Description: Implements the PaymentManagementService class which manages payment-related operations + in the Vehicle Service Management System. Provides functionality for attaching/detaching observers, + sending notifications, and issuing payment reminders based on invoice status and thresholds. +Author: Trenser +Date: 20-May-2026 +*/ + +#include +#include "Config.h" +#include "Enums.h" +#include "Factory.h" +#include "FileManager.h" +#include "InventoryItem.h" +#include "Invoice.h" +#include "JobCard.h" #include "PaymentManagementService.h" +#include "Service.h" +#include "ServiceBooking.h" +#include "Timestamp.h" +#include "User.h" +#include "Utility.h" + +util::Map PaymentManagementService::m_observers{}; + +/* +Function: attach +Description: Attaches a user as an observer to the PaymentManagementService for receiving notifications. +Parameters: + - user: Pointer to the User object to be attached. +Returns: + - void +*/ +void PaymentManagementService::attach(User* user) +{ + if (user) + { + const std::string& userID = user->getId(); + if (m_observers.find(userID) == -1) + { + m_observers[userID] = user; + } + } +} + +/* +Function: detach +Description: Detaches a user from the observer list of the PaymentManagementService. +Parameters: + - user: Pointer to the User object to be detached. +Returns: + - void +*/ +void PaymentManagementService::detach(User* user) +{ + if (user) + { + const std::string& userID = user->getId(); + if (m_observers.find(userID) != -1) + { + m_observers.remove(userID); + } + } +} + +/* +Function: sendNotification +Description: Sends a notification to a user if they are registered as an observer. +Parameters: + - user: Pointer to the User object to receive the notification. + - title: Title of the notification. + - message: Message content of the notification. +Returns: + - void +Throws: + - std::runtime_error if notification creation fails. +*/ +void PaymentManagementService::sendNotification(User* user, const std::string& title, const std::string& message) +{ + if (user) + { + if (m_observers.find(user->getId()) != -1) + { + Notification* notification = + Factory::getObject( + user->getId(), + user, + title, + message, + util::Timestamp() + ); + if (notification) + { + user->addNotification(notification); + } + else + { + throw std::runtime_error("Failed to create notification"); + } + } + } +} + +/* +Function: sendPaymentReminders +Description: Iterates through all invoices in the datastore and sends payment reminders to customers + whose invoices are pending beyond the configured threshold duration. +Parameters: + - None +Returns: + - void +*/ +void PaymentManagementService::sendPaymentReminders() +{ + auto& invoicesMap = m_dataStore.getInvoices(); + int invoicesMapSize = invoicesMap.getSize(); + for (int index = 0; index < invoicesMapSize; index++) + { + const Invoice* invoice = invoicesMap.getValueAt(index); + if (invoice && invoice->getStatus() == util::PaymentStatus::PENDING) + { + util::Timestamp invoiceCreationTimestamp = invoice->getInvoiceDate(); + util::Timestamp currentTimestamp; + if (util::Timestamp::getDurationInHours(invoiceCreationTimestamp, currentTimestamp) >= config::threshold::PAYMENT_REMINDER_THRESHOLD_HOURS) + { + const ServiceBooking* serviceBooking = invoice->getBooking(); + if (serviceBooking) + { + User* customer = serviceBooking->getCustomer(); + if (customer) + { + std::string title = "Payment Reminder"; + std::string message = "Your payment for Invoice ID " + invoice->getId() + " is still pending. Please complete the payment."; + sendNotification(customer, title, message); + } + } + } + } + } +} + +/* +Function: getObserverIDs +Description: Retrieves the IDs of all observers currently attached to the + PaymentManagementService. +Parameters: + - None +Returns: + - util::Vector: Vector of observer user IDs +*/ +util::Vector PaymentManagementService::getObserverIDs() +{ + util::Vector observerIDs; + int numberOfObservers = m_observers.getSize(); + for (int index = 0; index < numberOfObservers; index++) + { + User* observer = m_observers.getValueAt(index); + if (observer) + { + observerIDs.push_back(observer->getId()); + } + } + return observerIDs; +} + +/* +Function: loadInvoices +Description: Loads invoices from persistent storage into the datastore. + Validates associated service bookings and inventory parts before + attaching them to each invoice. Throws exceptions if invalid IDs + are encountered. +Parameters: + - None +Returns: + - void +Throws: + - std::runtime_error if a booking ID or part ID is invalid +*/ +void PaymentManagementService::loadInvoices() +{ + util::FileManager invoiceFileManager(config::file::INVOICE_FILE); + auto& invoices = m_dataStore.getInvoices(); + auto& serviceBookings = m_dataStore.getServiceBookings(); + auto& inventoryItems = m_dataStore.getInventoryItems(); + auto invoicesMap = invoiceFileManager.load(); + for (int invoiceIndex = 0; invoiceIndex < invoicesMap.getSize(); invoiceIndex++) + { + Invoice* invoice = invoicesMap.getValueAt(invoiceIndex); + int bookingIndex = serviceBookings.find(invoice->getBookingId()); + if (bookingIndex == -1) + { + throw std::runtime_error("Invalid Booking ID"); + } + ServiceBooking* booking = serviceBookings.getValueAt(bookingIndex); + invoice->setBooking(booking); + util::Map invoiceParts; + auto& partIDs = invoice->getPartIDs(); + for (int partIndex = 0; partIndex < partIDs.getSize(); partIndex++) + { + const std::string& partID = partIDs[partIndex]; + int inventoryIndex = inventoryItems.find(partID); + if (inventoryIndex == -1) + { + throw std::runtime_error("Invalid Part ID"); + } + invoiceParts[partID] = inventoryItems.getValueAt(inventoryIndex); + } + invoice->setParts(invoiceParts); + invoices[invoice->getId()] = invoice; + } +} + +/* +Function: saveInvoices +Description: Saves invoices from the datastore to persistent storage. + Uses FileManager to serialize invoices into the configured file. +Parameters: + - None +Returns: + - void +*/ +void PaymentManagementService::saveInvoices() +{ + util::FileManager invoiceFileManager(config::file::INVOICE_FILE); + auto& invoices = m_dataStore.getInvoices(); + invoiceFileManager.save(invoices); +} + +/* +Function: loadObservers +Description: Loads observer IDs from persistent storage and attaches corresponding + users as observers to the PaymentManagementService. +Parameters: + - None +Returns: + - void +Throws: + - std::runtime_error if an observer ID is invalid (not found in datastore) +*/ +void PaymentManagementService::loadObservers() +{ + util::loadObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this, m_dataStore); +} + +/* +Function: saveObservers +Description: Saves the current observer IDs of the PaymentManagementService + to persistent storage for future retrieval. +Parameters: + - None +Returns: + - void +*/ +void PaymentManagementService::saveObservers() +{ + util::saveObservers(config::file::PAYMENTMANAGEMENTOBSERVERS, this); +} + +/* +Function: createInventoryItemsMap (static helper) +Description: Builds a map of inventory items required for a given service and adds them to the booking’s inventory map. +Parameters: + - completeInventoryItemMapOfBooking: util::Map&, map to store inventory items for the booking + - currentService: const Service*, pointer to the current service +Returns: + - void +*/ +static void createInventoryItemsMap(util::Map& 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 totalLaborCost = 0, totalPartsCost = 0, totalServiceCost = 0; + double discountPercentage = booking->getDiscountPercentage(); + std::string bookingID = booking->getId(); + util::Map servicesInTheBookedService = booking->getServices(); + util::Map completeInventoryItemMapOfBooking; + util::Map currentJobCards = m_dataStore.getJobCards(); + for (int iterator = 0; iterator < currentJobCards.getSize(); iterator++) + { + JobCard* currentJobCard = currentJobCards.getValueAt(iterator); + 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 + "'."); + } + } + for (int iterator = 0; iterator < servicesInTheBookedService.getSize(); iterator++) + { + Service* currentService = servicesInTheBookedService.getValueAt(iterator); + if (currentService) + { + createInventoryItemsMap(completeInventoryItemMapOfBooking, currentService); + totalLaborCost += currentService->getLaborCost(); + totalPartsCost += util::calculatePartsCost(currentService); + } + } + totalServiceCost = totalLaborCost + totalPartsCost; + totalServiceCost -= (totalServiceCost * (discountPercentage / 100)); + 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); +} + +/* +Function: getInvoices +Description: Retrieves all invoices associated with a specific customer. +Parameters: + - customerID: std::string, ID of the customer +Returns: + - util::Map containing the customer’s invoices +*/ +util::Map PaymentManagementService::getInvoices(const std::string& customerID) +{ + util::Map& currentInvoices = m_dataStore.getInvoices(); + util::Map 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); + if (invoice && invoice->getStatus() != util::PaymentStatus::COMPLETED) + { + 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."); + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.h index 56a2fd2..14b8c11 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/PaymentManagementService.h @@ -1,3 +1,12 @@ +/* +File: PaymentManagementService.h +Description: Declares the PaymentManagementService class which manages payment operations in the Vehicle Service Management System. + Provides functionality to generate invoices, retrieve customer invoices, complete payments, send payment reminders, + and handle notifications using the Observer pattern. +Author: Trenser +Date: 19-May-2026 +*/ + #pragma once #include #include "Map.h" @@ -13,6 +22,7 @@ class PaymentManagementService : public NotificationManagementService private: DataStore& m_dataStore; static util::Map m_observers; + util::Vector getObserverIDs() override; public: PaymentManagementService() : m_dataStore(DataStore::getInstance()) {} void generateInvoice(ServiceBooking* booking); @@ -22,4 +32,8 @@ public: void sendNotification(User* user, const std::string& title, const std::string& message) override; void attach(User* user) override; void detach(User* user) override; + void loadInvoices(); + void saveInvoices(); + void loadObservers(); + void saveObservers(); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp index 156c12b..5cd870b 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.cpp @@ -1 +1,1151 @@ +/* +File: ServiceManagementService.cpp +Description: Implementation file containing the method definitions of the + ServiceManagementService class, including service and combo package + purchasing logic, booking creation, and notification handling. +Author: Trenser +Date:19-May-2026 +*/ + +#include +#include "AuthenticationManagementService.h" +#include "ComboPackage.h" +#include "Config.h" +#include "DataStore.h" +#include "Enums.h" +#include "Factory.h" +#include "FileManager.h" +#include "InventoryItem.h" +#include "JobCard.h" +#include "NotificationManagementService.h" +#include "PaymentManagementService.h" +#include "Service.h" +#include "ServiceBooking.h" #include "ServiceManagementService.h" +#include "Timestamp.h" +#include "User.h" +#include "UserManagementService.h" +#include "Utility.h" + +/* +Function: purchaseService +Description: Creates a new service booking for the authenticated user. Validates + service IDs, retrieves services from the DataStore, and generates a + booking. Sends a notification upon successful booking. +Parameter: const util::Vector& serviceIDs - IDs of services to purchase + const std::string& vehicleNumber - vehicle registration number + const std::string& vehicleBrand - brand of the vehicle + const std::string& vehicleModel - model of the vehicle +Return type: void +*/ +void ServiceManagementService::purchaseService(const util::Vector& serviceIDs, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel) +{ + AuthenticationManagementService m_authenticationManagementService; + auto authenticatedUser = m_authenticationManagementService.getAuthenticatedUser(); + if (authenticatedUser == nullptr) + { + throw std::runtime_error("No user is currently logged in!"); + } + auto& servicesMap = m_dataStore.getServices(); + auto& serviceBookingMap = m_dataStore.getServiceBookings(); + util::Map selectedServices; + int selectedServicesCount = serviceIDs.getSize(); + for (int index = 0; index < selectedServicesCount; index++) + { + int serviceIndex = servicesMap.find(serviceIDs[index]); + if (serviceIndex == -1) + { + throw std::runtime_error("Service not found!"); + } + Service* service = servicesMap.getValueAt(serviceIndex); + selectedServices[service->getId()] = service; + } + ServiceBooking* serviceBooking = Factory::getObject(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, 0); + if (serviceBooking == nullptr) + { + throw std::runtime_error("Failed to create service booking"); + } + serviceBookingMap[serviceBooking->getId()] = serviceBooking; + std::string title = "Service Booking succeeded"; + std::string message = "Your service booking has been successfully placed with ID " + serviceBooking->getId(); + sendNotification(authenticatedUser, title, message); +} + +/* +Function: purchaseComboPackage +Description: Creates a new service booking for a combo package. Validates the combo + package ID, retrieves services from the package, and generates a booking + with the applicable discount. Sends a notification upon successful booking. +Parameter: const std::string& comboPackageID - ID of the combo package + const std::string& vehicleNumber - vehicle registration number + const std::string& vehicleBrand - brand of the vehicle + const std::string& vehicleModel - model of the vehicle +Return type: void +*/ +void ServiceManagementService::purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel) +{ + AuthenticationManagementService m_authenticationManagementService; + auto authenticatedUser = m_authenticationManagementService.getAuthenticatedUser(); + if (authenticatedUser == nullptr) + { + throw std::runtime_error("No user is currently logged in!"); + } + auto& comboPackagesMap = m_dataStore.getComboPackages(); + auto& serviceBookingMap = m_dataStore.getServiceBookings(); + int comboPackageIndex = comboPackagesMap.find(comboPackageID); + if (comboPackageIndex == -1) + { + throw std::runtime_error("Combo Package not found!"); + } + const ComboPackage* comboPackage = comboPackagesMap[comboPackageID]; + util::Map selectedServices = comboPackage->getServices(); + ServiceBooking* serviceBooking = Factory::getObject(util::ServiceJobStatus::PENDING, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, comboPackage->getDiscountPercentage()); + if (serviceBooking == nullptr) + { + throw std::runtime_error("Failed to create combo package service booking"); + } + serviceBookingMap[serviceBooking->getId()] = serviceBooking; + std::string title = "Combo Package Service Booking succeeded"; + std::string message = "Your service booking for the combo package has been successfully placed with ID " + serviceBooking->getId(); + sendNotification(authenticatedUser, title, message); +} + +util::Map ServiceManagementService::m_observers{}; + +/* +Function: attach +Description: Attaches a user as an observer to the ServiceManagementService for receiving notifications. +Parameters: + - user: Pointer to the User object to be attached. +Returns: + - void +*/ +void ServiceManagementService::attach(User* user) +{ + if (user) + { + const std::string& userID = user->getId(); + if (m_observers.find(userID) == -1) + { + m_observers[userID] = user; + } + } +} + +/* +Function: detach +Description: Detaches a user from the observer list of the ServiceManagementService. +Parameters: + - user: Pointer to the User object to be detached. +Returns: + - void +*/ +void ServiceManagementService::detach(User* user) +{ + if (user) + { + const std::string& userID = user->getId(); + if (m_observers.find(userID) != -1) + { + m_observers.remove(userID); + } + } +} + +/* +Function: sendNotification +Description: Sends a notification to a user if they are registered as an observer. +Parameters: + - user: Pointer to the User object to receive the notification. + - title: Title of the notification. + - message: Message content of the notification. +Returns: + - void +Throws: + - std::runtime_error if notification creation fails. +*/ +void ServiceManagementService::sendNotification(User* user, const std::string& title, const std::string& message) +{ + if (user) + { + if (m_observers.find(user->getId()) != -1) + { + Notification* notification = + Factory::getObject( + user->getId(), + user, + title, + message, + util::Timestamp() + ); + if (notification) + { + user->addNotification(notification); + } + else + { + throw std::runtime_error("Failed to create notification"); + } + } + } +} + +/* +Function: getObserverIDs +Description: Retrieves the IDs of all observers currently attached to the + ServiceManagementService. +Parameters: + - None +Returns: + - util::Vector: Vector of observer user IDs +*/ +util::Vector ServiceManagementService::getObserverIDs() +{ + util::Vector observerIDs; + int numberOfObservers = m_observers.getSize(); + for (int index = 0; index < numberOfObservers; index++) + { + User* observer = m_observers.getValueAt(index); + if (observer) + { + observerIDs.push_back(observer->getId()); + } + } + return observerIDs; +} + +/* +Function: loadServices +Description: Loads services from persistent storage into the datastore. + Validates required inventory items and attaches them to each service. +Parameters: + - None +Returns: + - void +Throws: + - std::runtime_error if an inventory item ID is invalid +*/ +void ServiceManagementService::loadServices() +{ + util::FileManager serviceFileManager(config::file::SERVICE_FILE); + auto& services = m_dataStore.getServices(); + auto& inventoryItems = m_dataStore.getInventoryItems(); + auto servicesMap = serviceFileManager.load(); + for (int serviceIndex = 0; serviceIndex < servicesMap.getSize(); serviceIndex++) + { + Service* service = servicesMap.getValueAt(serviceIndex); + services[service->getId()] = service; + util::Map inventoryItemsMap; + auto& inventoryItemIDs = service->getRequiredInventoryItemIDs(); + for (int inventoryItemIndex = 0; inventoryItemIndex < inventoryItemIDs.getSize(); inventoryItemIndex++) + { + const std::string& inventoryItemID = inventoryItemIDs[inventoryItemIndex]; + int index = inventoryItems.find(inventoryItemID); + if (index == -1) + { + throw std::runtime_error("Invalid Inventory Item ID"); + } + inventoryItemsMap[inventoryItemID] = inventoryItems.getValueAt(index); + } + service->setRequiredInventoryItems(inventoryItemsMap); + } +} + +/* +Function: saveServices +Description: Saves services from the datastore to persistent storage. + Uses FileManager to serialize services into the configured file. +Parameters: + - None +Returns: + - void +*/ +void ServiceManagementService::saveServices() +{ + util::FileManager serviceFileManager(config::file::SERVICE_FILE); + auto& services = m_dataStore.getServices(); + serviceFileManager.save(services); +} + +/* +Function: loadComboPackages +Description: Loads combo packages from persistent storage into the datastore. + Validates associated services and attaches them to each package. +Parameters: + - None +Returns: + - void +Throws: + - std::runtime_error if a service ID is invalid +*/ +void ServiceManagementService::loadComboPackages() +{ + util::FileManager comboPackageFileManager(config::file::COMBOPACKAGE_FILE); + auto& comboPackages = m_dataStore.getComboPackages(); + auto& services = m_dataStore.getServices(); + auto comboPackagesMap = comboPackageFileManager.load(); + for (int packageIndex = 0; packageIndex < comboPackagesMap.getSize(); packageIndex++) + { + ComboPackage* comboPackage = comboPackagesMap.getValueAt(packageIndex); + util::Map packageServices; + auto& serviceIDs = comboPackage->getServiceIDs(); + for (int serviceIndex = 0; serviceIndex < serviceIDs.getSize(); serviceIndex++) + { + const std::string& serviceID = serviceIDs[serviceIndex]; + int serviceMapIndex = services.find(serviceID); + if (serviceMapIndex == -1) + { + throw std::runtime_error("Invalid Service ID"); + } + packageServices[serviceID] = services.getValueAt(serviceMapIndex); + } + comboPackage->setServices(packageServices); + comboPackages[comboPackage->getId()] = comboPackage; + } +} + +/* +Function: saveComboPackages +Description: Saves combo packages from the datastore to persistent storage. + Uses FileManager to serialize combo packages into the configured file. +Parameters: + - None +Returns: + - void +*/ +void ServiceManagementService::saveComboPackages() +{ + util::FileManager comboPackageFileManager(config::file::COMBOPACKAGE_FILE); + auto& comboPackages = m_dataStore.getComboPackages(); + comboPackageFileManager.save(comboPackages); +} + +/* +Function: loadServiceBookings +Description: Loads service bookings from persistent storage into the datastore. + Validates associated services, customers, and technicians before + attaching them to each booking. +Parameters: + - None +Returns: + - void +Throws: + - std::runtime_error if a service ID, customer ID, or technician ID is invalid + - std::runtime_error if a user is not of the expected type (customer/technician) +*/ +void ServiceManagementService::loadServiceBookings() +{ + util::FileManager bookingFileManager(config::file::SERVICEBOOKING_FILE); + auto& serviceBookings = m_dataStore.getServiceBookings(); + auto& services = m_dataStore.getServices(); + auto& users = m_dataStore.getUsers(); + auto bookingsMap = bookingFileManager.load(); + for (int bookingIndex = 0; bookingIndex < bookingsMap.getSize(); bookingIndex++) + { + ServiceBooking* booking = bookingsMap.getValueAt(bookingIndex); + util::Map bookingServices; + auto& serviceIDs = booking->getServiceIDs(); + for (int serviceIndex = 0; serviceIndex < serviceIDs.getSize(); serviceIndex++) + { + const std::string& serviceID = serviceIDs[serviceIndex]; + int serviceMapIndex = services.find(serviceID); + if (serviceMapIndex == -1) + { + throw std::runtime_error("Invalid Service ID"); + } + + bookingServices[serviceID] = services.getValueAt(serviceMapIndex); + } + booking->setServices(bookingServices); + int customerIndex = users.find(booking->getCustomerId()); + if (customerIndex == -1) + { + throw std::runtime_error("Invalid Customer ID"); + } + User* customer = users.getValueAt(customerIndex); + if (customer->getUserType() != util::UserType::CUSTOMER) + { + throw std::runtime_error("User is not a customer"); + } + booking->setCustomer(customer); + const std::string& technicianId = booking->getAssignedTechnicianId(); + if (!technicianId.empty()) + { + int technicianIndex = users.find(technicianId); + if (technicianIndex == -1) + { + throw std::runtime_error("Invalid Technician ID"); + } + User* technician = users.getValueAt(technicianIndex); + if (technician->getUserType() != util::UserType::TECHNICIAN) + { + throw std::runtime_error("User is not a technician"); + } + booking->setAssignedTechnician(technician); + } + serviceBookings[booking->getId()] = booking; + } +} + +/* +Function: saveServiceBookings +Description: Saves service bookings from the datastore to persistent storage. + Uses FileManager to serialize bookings into the configured file. +Parameters: + - None +Returns: + - void +*/ +void ServiceManagementService::saveServiceBookings() +{ + util::FileManager bookingFileManager(config::file::SERVICEBOOKING_FILE); + auto& serviceBookings = m_dataStore.getServiceBookings(); + bookingFileManager.save(serviceBookings); +} + +/* +Function: loadJobCards +Description: Loads job cards from persistent storage into the datastore. + Validates associated bookings, services, and technicians before + attaching them to each job card. +Parameters: + - None +Returns: + - void +Throws: + - std::runtime_error if a booking ID, service ID, or technician ID is invalid + - std::runtime_error if a service does not belong to the booking + - std::runtime_error if a user is not a technician +*/ +void ServiceManagementService::loadJobCards() +{ + util::FileManager jobCardFileManager(config::file::JOBCARD_FILE); + auto& jobCards = m_dataStore.getJobCards(); + auto& serviceBookings = m_dataStore.getServiceBookings(); + auto& services = m_dataStore.getServices(); + auto& users = m_dataStore.getUsers(); + auto jobCardsMap = jobCardFileManager.load(); + for (int jobCardIndex = 0; jobCardIndex < jobCardsMap.getSize(); jobCardIndex++) + { + JobCard* jobCard = jobCardsMap.getValueAt(jobCardIndex); + int bookingIndex = serviceBookings.find(jobCard->getBookingId()); + if (bookingIndex == -1) + { + throw std::runtime_error("Invalid Booking ID"); + } + ServiceBooking* booking = serviceBookings.getValueAt(bookingIndex); + jobCard->setBooking(booking); + int serviceIndex = services.find(jobCard->getServiceId()); + if (serviceIndex == -1) + { + throw std::runtime_error("Invalid Service ID"); + } + Service* service = services.getValueAt(serviceIndex); + if (booking->getServices().find(jobCard->getServiceId()) == -1) + { + throw std::runtime_error("Service does not belong to booking"); + } + jobCard->setService(service); + int technicianIndex = users.find(jobCard->getTechnicianId()); + if (technicianIndex == -1) + { + throw std::runtime_error("Invalid Technician ID"); + } + User* technician = users.getValueAt(technicianIndex); + if (technician->getUserType() != util::UserType::TECHNICIAN) + { + throw std::runtime_error("User is not a technician"); + } + jobCard->setTechnician(technician); + jobCards[jobCard->getId()] = jobCard; + } +} + +/* +Function: saveJobCards +Description: Saves job cards from the datastore to persistent storage. + Uses FileManager to serialize job cards into the configured file. +Parameters: + - None +Returns: + - void +*/ +void ServiceManagementService::saveJobCards() +{ + util::FileManager jobCardFileManager(config::file::JOBCARD_FILE); + auto& jobCards = m_dataStore.getJobCards(); + jobCardFileManager.save(jobCards); +} + +/* +Function: loadObservers +Description: Loads observer IDs from persistent storage and attaches corresponding + users as observers to the ServiceManagementService. +Parameters: + - None +Returns: + - void +Throws: + - std::runtime_error if an observer ID is invalid (not found in datastore) +*/ +void ServiceManagementService::loadObservers() +{ + util::loadObservers(config::file::SERVICEMANAGEMENTOBSERVERS, this, m_dataStore); +} + +/* +Function: saveObservers +Description: Saves the current observer IDs of the ServiceManagementService + to persistent storage for future retrieval. +Parameters: + - None +Returns: + - void +*/ +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. + Updates booking status, resets customer/technician assignments, sends notifications, + and restocks inventory items. +Parameter: const std::string& userID - ID of the customer or technician +Return type: void +*/ +void ServiceManagementService::cancelCustomerServiceBookings(const std::string& customerID) +{ + auto& users = m_dataStore.getUsers(); + int userIndex = users.find(customerID); + if (userIndex == -1) + { + throw std::runtime_error("User not found: " + customerID); + } + User* customer = users.getValueAt(userIndex); + if (!customer) + { + throw std::runtime_error("User not found: " + customerID); + } + 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) + { + 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 + ); + } +} + +/* +Function: cancelTechnicianJobs +Description: Cancels all jobs assigned to a technician. Updates job status, sends notifications, + and restocks inventory items used in the service. +Parameter: const std::string& technicianID - ID of the technician +Return type: void +*/ +void ServiceManagementService::cancelTechnicianJobs(const std::string& technicianID) +{ + auto& users = m_dataStore.getUsers(); + int userIndex = users.find(technicianID); + if (userIndex == -1) + { + 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) + { + 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 + ); + } +} + +/* +Function: createComboPackage +Description: Creates a new combo package with two services and a discount percentage. + Validates service IDs, ensures uniqueness, and inserts the new package into the DataStore. +Parameter: const std::string& packageName - name of the combo package + const util::Vector& serviceIDsInNewCombo - list of service IDs + double discountPercentage - discount percentage for the package +Return type: void +*/ +void ServiceManagementService::createComboPackage(const std::string& packageName, const util::Vector& serviceIDsInNewCombo, double discountPercentage) +{ + if (packageName.empty()) + { + throw std::invalid_argument("The Combo Package Name cannot be empty.\n"); + } + if (serviceIDsInNewCombo.getSize() < 2 || serviceIDsInNewCombo.getSize() > 2) + { + throw std::invalid_argument("Combo package must contain only two services."); + } + if (discountPercentage < 0.0 || discountPercentage > 100.0) + { + throw std::invalid_argument("Discount percentage must be between 0 and 100."); + } + auto& servicesMap = m_dataStore.getServices(); + for (int index = 0; index < serviceIDsInNewCombo.getSize(); index++) + { + const std::string serviceid = serviceIDsInNewCombo[index]; + if (servicesMap.find(serviceid) == -1) + { + throw std::runtime_error("Service ID not found: " + serviceid); + } + } + auto& comboPackageMap = m_dataStore.getComboPackages(); + for (int iterator = 0; iterator < comboPackageMap.getSize(); iterator++) + { + ComboPackage* existingCombos = comboPackageMap.getValueAt(iterator); + const util::Map& servicesInsideExistingCombos = existingCombos->getServices(); + if (servicesInsideExistingCombos.getSize() == serviceIDsInNewCombo.getSize()) + { + bool isIdentical = true; + for (int serviceIterator = 0; serviceIterator < serviceIDsInNewCombo.getSize(); serviceIterator++) + { + const std::string& id = serviceIDsInNewCombo[serviceIterator]; + if (servicesInsideExistingCombos.find(id) == -1) + { + isIdentical = false; + break; + } + } + if (isIdentical) + { + throw std::runtime_error("A combo package with the same services already exists."); + } + } + } + util::Map selectedServices; + for (int iteratorOne = 0; iteratorOne < serviceIDsInNewCombo.getSize(); iteratorOne++) + { + const std::string& serviceId = serviceIDsInNewCombo[iteratorOne]; + int serviceIndex = servicesMap.find(serviceId); + if (serviceIndex == -1) + { + throw std::runtime_error("Service ID not found: " + serviceId); + } + selectedServices.insert(serviceId, servicesMap.getValueAt(serviceIndex)); + } + ComboPackage* newComboPackage = Factory::getObject(packageName, discountPercentage, selectedServices); + comboPackageMap.insert(newComboPackage->getId(), newComboPackage); +} + +/* +Function: getComboPackages +Description: Retrieves all combo packages stored in the DataStore. +Parameter: None +Return type: util::Map +*/ +util::Map ServiceManagementService::getComboPackages() +{ + return m_dataStore.getComboPackages(); +} + +/* +Function: removeComboPackage +Description: Removes a combo package by marking it inactive. Throws an exception if the package ID is not found. +Parameter: const std::string& comboPackageID - ID of the combo package +Return type: void +*/ +void ServiceManagementService::removeComboPackage(const std::string& comboPackageID) +{ + bool removed = false; + util::Map& currentComboPackages = m_dataStore.getComboPackages(); + for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++) + { + ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator); + if (currentComboPackage && currentComboPackage->getId() == comboPackageID) + { + currentComboPackage->setState(util::State::INACTIVE); + removed = true; + break; + } + } + if (!removed) + { + throw std::runtime_error("Combo package with ID '" + comboPackageID + "' not found."); + } +} + +/* +Function: getServiceBookings +Description: Retrieves all service bookings from the datastore. +Parameters: + - None +Returns: + - util::Map containing all service bookings +*/ +util::Map ServiceManagementService::getServiceBookings() +{ + return m_dataStore.getServiceBookings(); +} + +/* +Function: getServiceBooking +Description: Retrieves a specific service booking by its ID. +Parameters: + - serviceID: std::string, ID of the service booking +Returns: + - ServiceBooking*: Pointer to the service booking, or nullptr if not found +*/ +ServiceBooking* ServiceManagementService::getServiceBooking(const std::string& serviceID) +{ + auto currentServiceBookings = getServiceBookings(); + for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++) + { + if (currentServiceBookings.getValueAt(iterator)->getId() == serviceID) + { + return currentServiceBookings.getValueAt(iterator); + } + } + return nullptr; +} + +/* +Function: createJobCard +Description: Creates a job card for a given service booking, service, and technician. + Validates booking, service, technician, and inventory availability before creation. +Parameters: + - bookingID: std::string, ID of the service booking + - technicianID: std::string, ID of the technician + - serviceID: std::string, ID of the service +Returns: + - void +Throws: + - std::runtime_error if booking, service, technician, or inventory validation fails +*/ +void ServiceManagementService::createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID) +{ + UserManagementService m_userManagementService; + ServiceBooking* currentBooking = getServiceBooking(bookingID); + auto& currentJobCards = m_dataStore.getJobCards(); + if (currentBooking == nullptr) + { + throw std::runtime_error("Service Booking not available"); + } + auto& currentServices = currentBooking->getServices(); + if (currentServices.find(serviceID) == -1) + { + throw std::runtime_error("Invalid service Id"); + } + Service* currentService = currentServices.getValueAt(currentServices.find(serviceID)); + User* selectedTechnician = m_userManagementService.getUser(technicianID); + if (selectedTechnician == nullptr) + { + throw std::runtime_error("Technician not available"); + } + auto& inventoryItems = currentService->getRequiredInventoryItems(); + for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++) + { + InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator); + if (currentInventoryItem && currentInventoryItem->getQuantity() == 0) + { + std::string errorMessage = "Failed to create job card, " + currentInventoryItem->getPartName() + " is out of stock."; + throw std::runtime_error(errorMessage); + } + } + for (int iterator = 0; iterator < inventoryItems.getSize(); iterator++) + { + InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iterator); + if (currentInventoryItem) + { + int currentStockQuantity = currentInventoryItem->getQuantity(); + currentInventoryItem->setQuantity(currentStockQuantity - 1); + } + } + currentBooking->setAssignedTechnician(selectedTechnician); + currentBooking->setAssignedTechnicianId(selectedTechnician->getId()); + if (currentBooking->getStatus() == util::ServiceJobStatus::PENDING) + { + currentBooking->setStatus(util::ServiceJobStatus::STARTED); + } + std::string title = "Job card created"; + std::string message = "Job card created for the service and you are assigned for that."; + JobCard* jobCard = Factory::getObject(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::Timestamp(), util::ServiceJobStatus::STARTED, util::Timestamp()); + if (jobCard) + { + currentJobCards.insert(jobCard->getId(), jobCard); + sendNotification(selectedTechnician, title, message); + } + else + { + 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); +} + +/* +Function: createService +Description: Creates a new service with associated inventory items and labor cost. + Validates inventory items before creation. +Parameters: + - name: std::string, name of the service + - inventoryItemIDs: util::Vector, IDs of required inventory items + - laborCost: double, labor cost for the service +Returns: + - void +Throws: + - std::runtime_error if inventory items are not found or service creation fails +*/ +void ServiceManagementService::createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost) +{ + util::Map currentServiceInventoryItems; + auto inventoryItems = m_dataStore.getInventoryItems(); + for (int iteratorOne =0; iteratorOne < inventoryItemIDs.getSize(); iteratorOne++) + { + std::string currentItemID = inventoryItemIDs[iteratorOne]; + bool itemFound = false; + for (int iteratorTwo = 0; iteratorTwo < inventoryItems.getSize(); iteratorTwo++) + { + InventoryItem* currentInventoryItem = inventoryItems.getValueAt(iteratorTwo); + if (currentInventoryItem && currentInventoryItem->getId() == currentItemID) + { + itemFound = true; + currentServiceInventoryItems.insert(currentInventoryItem->getId(), currentInventoryItem); + break; + } + } + if (!itemFound) + { + throw std::runtime_error("Inventory item with ID '" + currentItemID + "' not found."); + } + } + Service* newService = Factory::getObject(name, currentServiceInventoryItems, laborCost); + if (newService == nullptr) + { + throw std::runtime_error("Unable to create new service."); + } + util::Map& currentServices = m_dataStore.getServices(); + if (currentServices.find(newService->getId()) != -1) + { + throw std::runtime_error("Service with this ID Already exists."); + } + currentServices.insert(newService->getId(), newService); +} + +/* +Function: getServices +Description: Retrieves all services from the datastore. +Parameters: + - None +Returns: + - util::Map containing all services +*/ +util::Map ServiceManagementService::getServices() +{ + return m_dataStore.getServices(); +} + +/* +Function: removeService +Description: Marks a service as inactive by its ID. +Parameters: + - serviceID: std::string, ID of the service +Returns: + - void +Throws: + - std::runtime_error if the service is not found +*/ +void ServiceManagementService::removeService(const std::string& serviceID) +{ + util::Map& currentServices = m_dataStore.getServices(); + util::Map& currentComboPackages = m_dataStore.getComboPackages(); + if (currentServices.find(serviceID) != -1) + { + currentServices.getValueAt(currentServices.find(serviceID))->setState(util::State::INACTIVE); + for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++) + { + ComboPackage* currentComboPackage = currentComboPackages.getValueAt(iterator); + if (currentComboPackage && currentComboPackage->getState() == util::State::ACTIVE) + { + util::Map currentServices = currentComboPackage->getServices(); + for (int iterator = 0; iterator < currentServices.getSize(); iterator++) + { + auto currentService = currentServices.getValueAt(iterator); + if (currentService->getId() == serviceID) + { + currentComboPackage->setState(util::State::INACTIVE); + break; + } + } + } + } + } + else + { + throw std::runtime_error("Service not found."); + } +} + +/* +Function: getServiceBookings (overloaded) +Description: Retrieves all service bookings for a specific customer. +Parameters: + - customerID: std::string, ID of the customer +Returns: + - util::Map containing bookings for the customer +*/ +util::Map ServiceManagementService::getServiceBookings(const std::string& customerID) +{ + util::Map currentServiceBookings = getServiceBookings(); + util::Map currentUserServiceBookings; + if (currentServiceBookings.getSize() != 0) + { + for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++) + { + auto currentServiceBooking = currentServiceBookings.getValueAt(iterator); + if (currentServiceBooking->getCustomerId() == customerID) + { + currentUserServiceBookings.insert(currentServiceBooking->getId(), currentServiceBooking); + } + } + } + return currentUserServiceBookings; +} + +/* +Function: getJobCards +Description: Retrieves all job cards assigned to a specific technician. +Parameters: + - technicianID: std::string, ID of the technician +Returns: + - util::Map containing job cards assigned to the technician +*/ +util::Map ServiceManagementService::getJobCards(const std::string& technicianID) +{ + util::Map jobCards = m_dataStore.getJobCards(); + util::Map technicianJobCards; + for (int iterator = 0; iterator < jobCards.getSize(); iterator++) + { + JobCard* currentJobCard = jobCards.getValueAt(iterator); + if (currentJobCard->getTechnicianId() == technicianID) + { + technicianJobCards.insert(currentJobCard->getId(), currentJobCard); + } + } + return technicianJobCards; +} + +/* +Function: hasCompletedAllJobs (static helper) +Description: Checks if all job cards for a given service booking are completed. +Parameters: + - bookingId: std::string, ID of the service booking + - currentAssignedJobs: util::Map&, map of assigned job cards +Returns: + - bool: True if all job cards are completed, False otherwise +*/ +static bool hasCompletedAllJobs(std::string bookingId, util::Map& currentAssignedJobs) +{ + for (int iterator = 0; iterator < currentAssignedJobs.getSize(); iterator++) + { + JobCard* currentJob = currentAssignedJobs.getValueAt(iterator); + if (currentJob->getBookingId() == bookingId) + { + if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) + { + return false; + } + } + } + return true; +} + +/* +Function: completeJob +Description: Marks a job card as completed for the authenticated technician. + If all job cards in the booking are completed, marks the booking as completed + and generates an invoice. +Parameters: + - jobID: std::string, ID of the job card +Returns: + - void +Throws: + - std::runtime_error if technician is not authenticated, job card not found, or job already completed +*/ +void ServiceManagementService::completeJob(const std::string& jobID) +{ + AuthenticationManagementService authenticationManagementService; + PaymentManagementService paymentManagementService; + bool jobStatusUpdated = false, serviceBookingCompleted; + JobCard* currentJob; + User* currentTechnician = authenticationManagementService.getAuthenticatedUser(); + if (currentTechnician == nullptr) + { + throw std::runtime_error("Unable to fetch current technician."); + } + util::Map currentAssignedJobs = getJobCards(currentTechnician->getId()); + if (currentAssignedJobs.getSize() == 0) + { + throw std::runtime_error("No job cards assigned to the technician."); + } + if (currentAssignedJobs.find(jobID) != -1) + { + currentJob = currentAssignedJobs.getValueAt(currentAssignedJobs.find(jobID)); + if (currentJob == nullptr) + { + throw std::runtime_error("Unable to fetch current job."); + } + if (currentJob->getStatus() == util::ServiceJobStatus::STARTED) + { + currentJob->setStatus(util::ServiceJobStatus::COMPLETED); + jobStatusUpdated = true; + } + } + else + { + throw std::runtime_error("Failed to complete the job, some error occurred or job already completed."); + } + if (!jobStatusUpdated) + { + throw std::runtime_error("Failed to complete the job, some error occurred or job already completed."); + } + + serviceBookingCompleted = hasCompletedAllJobs(currentJob->getBookingId(), currentAssignedJobs); + if (serviceBookingCompleted) + { + currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED); + paymentManagementService.generateInvoice(currentJob->getBooking()); + 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); + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.h index 85e05ed..2fdcc93 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/ServiceManagementService.h @@ -1,3 +1,12 @@ +/* +File: ServiceManagementService.h +Description: Header file declaring the ServiceManagementService class, which manages + services, combo packages, job cards, and service bookings. Inherits from + NotificationManagementService to handle notifications. +Author: Trenser +Date:19-May-2026 +*/ + #pragma once #include #include "Map.h" @@ -14,6 +23,7 @@ class ServiceManagementService : public NotificationManagementService private: DataStore& m_dataStore; static util::Map m_observers; + util::Vector getObserverIDs() override; public: ServiceManagementService() : m_dataStore(DataStore::getInstance()) {} util::Map getServices(); @@ -22,6 +32,7 @@ public: void purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel); util::Map getServiceBookings(); util::Map getServiceBookings(const std::string& customerID); + ServiceBooking* getServiceBooking(const std::string& serviceID); void createJobCard(const std::string& bookingID, const std::string& technicianID, const std::string& serviceID); void createService(const std::string& name, const util::Vector& inventoryItemIDs, double laborCost); void removeService(const std::string& serviceID); @@ -29,9 +40,19 @@ public: void completeJob(const std::string& jobID); void cancelCustomerServiceBookings(const std::string& customerID); void cancelTechnicianJobs(const std::string& technicianID); - void createComboPackage(const std::string& name, const util::Vector& serviceIDs, double discountPercentage); + void createComboPackage(const std::string& packageName, const util::Vector& serviceIDs, double discountPercentage); void removeComboPackage(const std::string& comboPackageID); void sendNotification(User* user, const std::string& title, const std::string& message) override; void attach(User* user) override; void detach(User* user) override; + void loadServices(); + void saveServices(); + void loadComboPackages(); + void saveComboPackages(); + void loadServiceBookings(); + void saveServiceBookings(); + void loadJobCards(); + void saveJobCards(); + void loadObservers(); + void saveObservers(); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 2a5bd9e..8ba68d0 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -1 +1,338 @@ +/* +File: UserManagementService.cpp +Description: Implementation file containing the method definitions of the + UserManagementService class, including user creation, updates, + and ensuring an admin account exists. +Author: Trenser +Date:19-May-2026 +*/ + +#include +#include "Config.h" +#include "Enums.h" +#include "Factory.h" +#include "FileManager.h" +#include "InventoryManagementService.h" +#include "Notification.h" +#include "PaymentManagementService.h" +#include "ServiceManagementService.h" +#include "User.h" #include "UserManagementService.h" +#include "Vector.h" +#include "Validator.h" + +/* +Function: ensureAdminExists +Description: Ensures that at least one admin user exists in the system. + If no admin is found, creates a default admin user using + configuration constants. +Parameter: None +Return type: void +*/ +void UserManagementService::ensureAdminExists() +{ + auto& usersMap = m_dataStore.getUsers(); + int usersMapSize = usersMap.getSize(); + bool isAdminFound = false; + for (int index = 0; index < usersMapSize; index++) + { + User* user = usersMap.getValueAt(index); + if (user && user->getUserType() == util::UserType::ADMIN) + { + isAdminFound = true; + break; + } + } + if (!isAdminFound) + { + createUser( + config::admin::DEFAULT_ADMIN_USERNAME, + config::admin::DEFAULT_ADMIN_NAME, + config::admin::DEFAULT_ADMIN_PASSWORD, + config::admin::DEFAULT_ADMIN_EMAIL, + config::admin::DEFAULT_ADMIN_PHONE, + util::UserType::ADMIN); + } +} + +/* +Function: createUser +Description: Creates a new user with the provided details. Validates that + the username is unique, then attaches the user to relevant + management services (payment, service, inventory). +Parameter: const std::string& username - user’s username + const std::string& name - user’s name + const std::string& password - user’s password + const std::string& email - user’s email address + const std::string& phone - user’s phone number + util::UserType type - type of user (ADMIN, CUSTOMER, TECHNICIAN) +Return type: void +*/ +void UserManagementService::createUser(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone, util::UserType type) +{ + InventoryManagementService inventoryManagementService; + PaymentManagementService paymentManagementService; + ServiceManagementService serviceManagementService; + auto& usersMap = m_dataStore.getUsers(); + if (util::isUsernameDuplicate(username, usersMap)) + { + throw std::runtime_error("Username already exists"); + } + if (util::isEmailDuplicate(email, usersMap)) + { + throw std::runtime_error("Email already exists"); + } + if (util::isPhoneDuplicate(phone, usersMap)) + { + throw std::runtime_error("Phone already exists"); + } + User* newUser = Factory::getObject(username, password, name, phone, email, type); + usersMap.insert(newUser->getId(), newUser); + paymentManagementService.attach(newUser); + serviceManagementService.attach(newUser); + if (newUser->getUserType() == util::UserType::ADMIN) + { + inventoryManagementService.attach(newUser); + } +} + +/* +Function: updateUserDetails +Description: Updates the email and phone details of an existing user. + Throws an exception if the user does not exist. +Parameter: const std::string& userID - ID of the user to update + const std::string& email - new email address + const std::string& phone - new phone number +Return type: void +*/ +void UserManagementService::updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone) +{ + auto& usersMap = m_dataStore.getUsers(); + int index = usersMap.find(userID); + if (index == -1) + { + throw std::runtime_error("User does not exist!\n"); + } + User* user = usersMap.getValueAt(index); + if (email != user->getEmail()) + { + if (util::isEmailDuplicate(email, usersMap)) + { + throw std::runtime_error("Email already exists!\n"); + } + } + if (phone != user->getPhone()) + { + if (util::isPhoneDuplicate(phone, usersMap)) + { + throw std::runtime_error("Phone number already exists!\n"); + } + } + user->setEmail(email); + user->setPhone(phone); +} + +/* +Function: getUserNotifications +Description: Retrieves all notifications associated with a given user ID. +Parameters: + - userID: The unique ID of the user whose notifications are to be retrieved. +Returns: + - util::Vector containing all notifications for the user. +Throws: + - std::runtime_error if no user is found with the given UserID or if the User object is invalid. +*/ +util::Vector UserManagementService::getUserNotifications(const std::string& userID) +{ + auto& usersMap = m_dataStore.getUsers(); + if (usersMap.find(userID) == -1) + { + throw std::runtime_error("No user found with given UserID"); + } + User* user = usersMap[userID]; + if (user) + { + auto& notifications = user->getNotifications(); + int numberOfNotifications = notifications.getSize(); + util::Vector notificationsVector; + for (int index = 0; index < numberOfNotifications; index++) + { + notificationsVector.push_back(notifications.getValueAt(index)); + } + return notificationsVector; + } + else + { + throw std::runtime_error("Invalid User object"); + } +} + +/* +Function: deleteNotification +Description: Deletes a specific notification associated with a given user ID. +Parameters: + - notificationID: The unique ID of the notification to be deleted. + - userID: The unique ID of the user whose notification is to be deleted. +Returns: + - void +Throws: + - std::runtime_error if no user is found with the given UserID or if no notification is found with the given NotificationID. +*/ +void UserManagementService::deleteNotification(const std::string& notificationID, const std::string& userID) +{ + auto& usersMap = m_dataStore.getUsers(); + if (usersMap.find(userID) == -1) + { + throw std::runtime_error("No user found with given UserID"); + } + User* user = usersMap[userID]; + auto& notifications = user->getNotifications(); + if (notifications.find(notificationID) == -1) + { + throw std::runtime_error("No notification found with given NotificationID"); + } + notifications.remove(notificationID); +} + +/* +Function: loadUsers +Description: Loads users and notifications from persistent storage into the datastore. + Validates that each notification’s recipient exists and attaches the + notification to the corresponding user. +Parameters: + - None +Returns: + - void +Throws: + - std::runtime_error if a notification recipient user ID is invalid +*/ +void UserManagementService::loadUsers() +{ + util::FileManager userFileManager(config::file::USER_FILE); + util::FileManager notificationFileManager(config::file::NOTIFICATION_FILE); + auto& users = m_dataStore.getUsers(); + auto usersMap = userFileManager.load(); + auto notificationsMap = notificationFileManager.load(); + int numberOfUsers = usersMap.getSize(); + int numberOfNotifications = notificationsMap.getSize(); + for (int index = 0; index < numberOfUsers; index++) + { + users[usersMap.getKeyAt(index)] = usersMap.getValueAt(index); + } + for (int index = 0; index < numberOfNotifications; index++) + { + Notification* notification = notificationsMap.getValueAt(index); + const std::string& recipientUserId = notification->getRecipientUserId(); + int userIndex = users.find(recipientUserId); + if (userIndex == -1) + { + throw std::runtime_error("Invalid recipient user ID"); + } + User* user = users.getValueAt(userIndex); + user->addNotification(notification); + } +} + +/* +Function: saveUsers +Description: Saves users and their notifications from the datastore to persistent storage. + Collects notifications from all users into a single map before saving. +Parameters: + - None +Returns: + - void +*/ +void UserManagementService::saveUsers() +{ + util::FileManager userFileManager(config::file::USER_FILE); + util::FileManager notificationFileManager(config::file::NOTIFICATION_FILE); + auto& users = m_dataStore.getUsers(); + util::Map notifications; + for (int userIndex = 0; userIndex < users.getSize(); userIndex++) + { + User* user = users.getValueAt(userIndex); + auto& userNotifications = user->getNotifications(); + for (int notificationIndex = 0; notificationIndex < userNotifications.getSize(); notificationIndex++) + { + notifications[userNotifications.getKeyAt(notificationIndex)] = + userNotifications.getValueAt(notificationIndex); + } + } + userFileManager.save(users); + notificationFileManager.save(notifications); +} + +/* +Function: getUsers +Description: Retrieves all users stored in the DataStore. +Parameter: None +Return type: util::Map +*/ +util::Map UserManagementService::getUsers() +{ + return m_dataStore.getUsers(); +} + +/* +Function: getUser +Description: Retrieves a specific user by ID from the DataStore. +Parameter: const std::string& userID - ID of the user +Return type: User* +*/ +User* UserManagementService::getUser(const std::string& userID) +{ + int index = m_dataStore.getUsers().find(userID); + if (index != -1) + { + return m_dataStore.getUsers().getValueAt(index); + } + return nullptr; +} + +/* +Function: removeUser +Description: Marks a user as inactive in the DataStore instead of deleting them. +Parameter: const std::string& userID - ID of the user to remove +Return type: void +*/ +void UserManagementService::removeUser(const std::string& userID) +{ + InventoryManagementService inventoryManagementService; + PaymentManagementService paymentManagementService; + ServiceManagementService serviceManagementService; + int index = m_dataStore.getUsers().find(userID); + if (index != -1) + { + 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); + serviceManagementService.detach(user); + } + } +} + +util::Map UserManagementService::getUsers(util::UserType type) +{ + util::Map& currentUsers = m_dataStore.getUsers(); + util::Map filteredUsersMap; + for (int iterator = 0; iterator < currentUsers.getSize(); iterator++) + { + User* currentUser = currentUsers.getValueAt(iterator); + if (currentUser && currentUser->getState() == util::State::ACTIVE && currentUser->getUserType() == type) + { + filteredUsersMap.insert(currentUser->getId(), currentUser); + } + } + return filteredUsersMap; +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h index bb7a85a..6b9f518 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h @@ -1,3 +1,11 @@ +/* +File: UserManagementService.h +Description: Header file declaring the UserManagementService class, which manages + user creation, updates, retrieval, removal, notifications, and ensures + the existence of an admin account. +Author: Trenser +Date:19-May-2026 +*/ #pragma once #include #include "Map.h" @@ -13,12 +21,15 @@ private: DataStore& m_dataStore; public: UserManagementService() : m_dataStore(DataStore::getInstance()) {} - void createUser(const std::string& username, const std::string& password, const std::string& email, const std::string& phone, util::UserType type); + void createUser(const std::string& username, const std::string& name, const std::string& password, const std::string& email, const std::string& phone, util::UserType type); void updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone); util::Map getUsers(); util::Map getUsers(util::UserType type); - User* getUser(const std::string& userID); + User* getUser (const std::string& userID); void removeUser(const std::string& userID); util::Vector getUserNotifications(const std::string& userID); void deleteNotification(const std::string& notificationID, const std::string& userID); + void ensureAdminExists(); + void loadUsers(); + void saveUsers(); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Config.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Config.h new file mode 100644 index 0000000..b0bd19d --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Config.h @@ -0,0 +1,43 @@ +/* +File: Config.h +Description: Header file declaring configuration constants for the Vehicle Service System. + Includes default admin account details such as username, name, password, + email, and phone number. +Author: Trenser +Date: 21-May-2026 +*/ + +#pragma once + +namespace config +{ + namespace admin + { + constexpr const char* DEFAULT_ADMIN_USERNAME = "admin"; + constexpr const char* DEFAULT_ADMIN_NAME = "admin"; + constexpr const char* DEFAULT_ADMIN_PASSWORD = "admin"; + constexpr const char* DEFAULT_ADMIN_EMAIL = "admin@vss"; + constexpr const char* DEFAULT_ADMIN_PHONE = "0000000000"; + } + + namespace threshold + { + constexpr int INVENTORY_LOW_STOCK_THRESHOLD = 5; + constexpr int PAYMENT_REMINDER_THRESHOLD_HOURS = 168; + } + + namespace file + { + constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.csv"; + constexpr const char* USER_FILE = "files/User.csv"; + constexpr const char* NOTIFICATION_FILE = "files/Notification.csv"; + constexpr const char* SERVICE_FILE = "files/Service.csv"; + constexpr const char* COMBOPACKAGE_FILE = "files/ComboPackage.csv"; + constexpr const char* SERVICEBOOKING_FILE = "files/ServiceBooking.csv"; + constexpr const char* JOBCARD_FILE = "files/JobCard.csv"; + constexpr const char* INVOICE_FILE = "files/Invoice.csv"; + constexpr const char* SERVICEMANAGEMENTOBSERVERS = "files/ServiceManagementObservers.csv"; + constexpr const char* PAYMENTMANAGEMENTOBSERVERS = "files/PaymentManagementObservers.csv"; + constexpr const char* INVENTORYMANAGEMENTOBSERVERS = "files/InventoryManagementObservers.csv"; + } +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h index 24bbdcd..16490f1 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Enums.h @@ -1,3 +1,12 @@ +/* +File: Enums.h +Description: Declares enumerations and utility functions for user types, payment modes, payment status, + service job status, and state management in the Vehicle Service Management System. + Provides string conversion and parsing functions for each enum type. +Author: Trenser +Date: 19-May-2026 +*/ + #pragma once #include @@ -13,7 +22,8 @@ namespace util enum class PaymentMode { ONLINE, - OFFLINE + OFFLINE, + NOTSET }; enum class PaymentStatus @@ -24,8 +34,10 @@ namespace util enum class ServiceJobStatus { + PENDING, STARTED, - COMPLETED + COMPLETED, + CANCELLED }; enum class State @@ -34,6 +46,14 @@ namespace util INACTIVE }; + /* + Function: getUserTypeString + Description: Converts a UserType enum value to its corresponding string representation. + Parameters: + - type: UserType enum value. + Returns: + - std::string representing the UserType. + */ inline std::string getUserTypeString(UserType type) { switch (type) @@ -48,6 +68,16 @@ namespace util throw std::invalid_argument("Invalid UserType"); } + /* + Function: getUserType + Description: Converts a string value to its corresponding UserType enum. + Parameters: + - value: std::string representing the UserType. + Returns: + - UserType enum value. + Throws: + - std::invalid_argument if the string does not match a valid UserType. + */ inline UserType getUserType(const std::string& value) { if (value == "ADMIN") @@ -65,6 +95,14 @@ namespace util throw std::invalid_argument("Invalid UserType string"); } + /* + Function: getPaymentModeString + Description: Converts a PaymentMode enum value to its corresponding string representation. + Parameters: + - mode: PaymentMode enum value. + Returns: + - std::string representing the PaymentMode. + */ inline std::string getPaymentModeString(PaymentMode mode) { switch (mode) @@ -73,10 +111,22 @@ namespace util return "ONLINE"; case PaymentMode::OFFLINE: return "OFFLINE"; + case PaymentMode::NOTSET: + return "NOTSET"; } throw std::invalid_argument("Invalid PaymentMode"); } + /* + Function: getPaymentMode + Description: Converts a string value to its corresponding PaymentMode enum. + Parameters: + - value: std::string representing the PaymentMode. + Returns: + - PaymentMode enum value. + Throws: + - std::invalid_argument if the string does not match a valid PaymentMode. + */ inline PaymentMode getPaymentMode(const std::string& value) { if (value == "ONLINE") @@ -87,9 +137,21 @@ namespace util { return PaymentMode::OFFLINE; } + if (value == "NOTSET") + { + return PaymentMode::NOTSET; + } throw std::invalid_argument("Invalid PaymentMode string"); } + /* + Function: getPaymentStatusString + Description: Converts a PaymentStatus enum value to its corresponding string representation. + Parameters: + - status: PaymentStatus enum value. + Returns: + - std::string representing the PaymentStatus. + */ inline std::string getPaymentStatusString(PaymentStatus status) { switch (status) @@ -102,6 +164,16 @@ namespace util throw std::invalid_argument("Invalid PaymentStatus"); } + /* + Function: getPaymentStatus + Description: Converts a string value to its corresponding PaymentStatus enum. + Parameters: + - value: std::string representing the PaymentStatus. + Returns: + - PaymentStatus enum value. + Throws: + - std::invalid_argument if the string does not match a valid PaymentStatus. + */ inline PaymentStatus getPaymentStatus(const std::string& value) { if (value == "PENDING") @@ -117,18 +189,40 @@ namespace util throw std::invalid_argument("Invalid PaymentStatus string"); } + /* + Function: getServiceJobStatusString + Description: Converts a ServiceJobStatus enum value to its corresponding string representation. + Parameters: + - status: ServiceJobStatus enum value. + Returns: + - std::string representing the ServiceJobStatus. + */ inline std::string getServiceJobStatusString(ServiceJobStatus status) { switch (status) { + case ServiceJobStatus::PENDING: + return "PENDING"; case ServiceJobStatus::STARTED: return "STARTED"; case ServiceJobStatus::COMPLETED: return "COMPLETED"; + case ServiceJobStatus::CANCELLED: + return "CANCELLED"; } throw std::invalid_argument("Invalid ServiceJobStatus"); } + /* + Function: getServiceJobStatus + Description: Converts a string value to its corresponding ServiceJobStatus enum. + Parameters: + - value: std::string representing the ServiceJobStatus. + Returns: + - ServiceJobStatus enum value. + Throws: + - std::invalid_argument if the string does not match a valid ServiceJobStatus. + */ inline ServiceJobStatus getServiceJobStatus(const std::string& value) { if (value == "STARTED") @@ -139,31 +233,57 @@ namespace util { return ServiceJobStatus::COMPLETED; } + if (value == "PENDING") + { + return ServiceJobStatus::PENDING; + } + if (value == "CANCELLED") + { + return ServiceJobStatus::CANCELLED; + } throw std::invalid_argument("Invalid ServiceJobStatus string"); } + /* + Function: getStateString + Description: Converts a State enum value to its corresponding string representation. + Parameters: + - status: State enum value. + Returns: + - std::string representing the State. + */ inline std::string getStateString(State status) { switch (status) { case State::ACTIVE: - return "STARTED"; + return "ACTIVE"; case State::INACTIVE: - return "COMPLETED"; + return "INACTIVE"; } throw std::invalid_argument("Invalid State"); } + /* + Function: getState + Description: Converts a string value to its corresponding State enum. + Parameters: + - value: std::string representing the State. + Returns: + - State enum value. + Throws: + - std::invalid_argument if the string does not match a valid State. + */ inline State getState(const std::string& value) { if (value == "ACTIVE") { return State::ACTIVE; } - if (value == "COMPLETED") + if (value == "INACTIVE") { return State::INACTIVE; } throw std::invalid_argument("Invalid State string"); } -} +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileHelper.h new file mode 100644 index 0000000..2b3e94a --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileHelper.h @@ -0,0 +1,109 @@ +/* +File: FileHelper.h +Description: Provides utility functions for loading and saving records + from and to CSV-like text files. Ensures files are created + if missing and supports simple record persistence. +Author: Trenser +Date: 22-May-2026 +*/ + +#pragma once +#include +#include +#include +#include +#include "Vector.h" + +namespace util +{ + /* + Function: ensureDirectoryExists + Description: Creates all missing directories present in the given file path. + Iteratively parses the path and creates each directory level + using _mkdir() before file operations are performed. + Parameters: + - filePath: const std::string&, relative or absolute file path + Returns: + - void + Throws: + - None (_mkdir failures are intentionally ignored if directory already exists) + */ + inline void ensureDirectoryExists(const std::string& filePath) + { + size_t position = 0; + + while ((position = filePath.find('/', position)) != std::string::npos) + { + std::string directory = filePath.substr(0, position); + + if (!directory.empty()) + { + (void)_mkdir(directory.c_str()); + } + position++; + } + } + + /* + Function: loadRecords + Description: Loads records from a given file path into a vector of strings. + Skips the header line if present. Creates the file if it does not exist. + Parameters: + - filePath: const std::string&, path to the file + Returns: + - util::Vector: Vector containing all records (excluding header) + Throws: + - None (creates file if missing) + */ + inline util::Vector loadRecords(const std::string& filePath) + { + util::Vector records; + std::ifstream file(filePath); + if (!file.is_open()) + { + ensureDirectoryExists(filePath); + std::ofstream newFile(filePath); + newFile.close(); + file.open(filePath); + } + std::string line; + bool isHeader = true; + while (std::getline(file, line)) + { + if (isHeader) + { + isHeader = false; + continue; + } + records.push_back(line); + } + return records; + } + + /* + Function: saveRecords + Description: Saves records to a given file path. Overwrites existing content + and writes a header line followed by all records. + Parameters: + - filePath: const std::string&, path to the file + - records: const util::Vector&, vector of records to save + Returns: + - void + Throws: + - std::runtime_error if the file cannot be opened for writing + */ + inline void saveRecords(const std::string& filePath, const util::Vector& records) + { + std::ofstream file(filePath, std::ios::trunc); + if (!file.is_open()) + { + throw std::runtime_error("Failed to open file " + filePath); + } + file << "Values" << '\n'; + int numberOfRecords = records.getSize(); + for (int index = 0; index < numberOfRecords; index++) + { + file << records[index] << '\n'; + } + } +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileManager.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileManager.h new file mode 100644 index 0000000..1ea66c7 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/FileManager.h @@ -0,0 +1,119 @@ +/* +File: FileManager.h +Description: Declares and implements a generic FileManager template class for + loading and saving objects to and from files. Uses serialization + and deserialization methods defined in the object type T. + Provides persistence support for system entities such as Users, + Services, InventoryItems, etc. +Author: Trenser +Date: 22-May-2026 +*/ + +#pragma once +#include +#include +#include +#include "Vector.h" +#include "Map.h" +#include "FileHelper.h" + +namespace util +{ + template using objects = util::Map; + + template + class FileManager + { + private: + std::string m_filePath; + public: + FileManager() : m_filePath("") {} + FileManager(const std::string& filePath) : m_filePath(filePath) {} + objects load(); + void save(const objects&); + }; + + /* + Function: load + Description: Loads records from the file into a map of objects. + Skips the header line, deserializes each record into an object of type T, + and stores them in a map keyed by object ID. + Parameters: + - None + Returns: + - util::Map containing deserialized objects + Throws: + - std::runtime_error if deserialization fails for any record + */ + template + objects FileManager::load() + { + objects records; + std::ifstream file(m_filePath); + if (!file.is_open()) + { + ensureDirectoryExists(m_filePath); + std::ofstream newFile(m_filePath); + newFile.close(); + file.open(m_filePath); + } + util::Vector lines; + std::string line; + while (std::getline(file, line)) + { + lines.push_back(line); + } + int numberOfLines = lines.getSize(); + bool isHeader = true; + for (int lineIndex = 0; lineIndex < numberOfLines; lineIndex++) + { + const auto& record = lines[lineIndex]; + if (isHeader) + { + isHeader = false; + continue; + } + auto object = T::deserialize(record); + if (!object) + { + throw std::runtime_error("Failed to deserialize record"); + } + records[object->getId()] = object; + } + return records; + } + + /* + Function: save + Description: Saves records to the file. Serializes each object of type T into a string, + writes a header line, and then writes all serialized records to the file. + Parameters: + - records: const util::Map&, map of objects to save + Returns: + - void + Throws: + - std::runtime_error if the file cannot be opened for writing + */ + template + void FileManager::save(const objects& records) + { + util::Vector lines; + lines.push_back(T::getHeaders()); + int numberOfRecords = records.getSize(); + for (int recordIndex = 0; recordIndex < numberOfRecords; recordIndex++) + { + const auto& record = records.getValueAt(recordIndex); + lines.push_back(record->serialize()); + } + std::ofstream file(m_filePath, std::ios::trunc); + if (!file.is_open()) + { + throw std::runtime_error("Failed to open file " + m_filePath); + } + int numberOfLines = lines.getSize(); + for (int lineIndex = 0; lineIndex < numberOfLines; lineIndex++) + { + file << lines[lineIndex] << '\n'; + } + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/InputHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/InputHelper.h index d8fee08..75d8bbc 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/InputHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/InputHelper.h @@ -34,7 +34,7 @@ namespace util /* * Function: read - * Description: Reads a line of text input from console into a string. + * Description: Reads a line of text input from console into a string and cleans it up. * Parameters: * value - reference to a string where the input will be stored * Returns: @@ -43,6 +43,15 @@ namespace util inline void read(std::string& value) { std::getline(std::cin >> std::ws, value); + std::string cleanedValue; + for (int index = 0; index < value.length(); index++) + { + if (value[index] != ',') + { + cleanedValue += value[index]; + } + } + value = cleanedValue; } /* @@ -53,6 +62,7 @@ namespace util */ inline void pressEnter() { + std::cout << std::endl; system("pause"); } } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/OutputHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/OutputHelper.h index 12b61a3..e763ffd 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/OutputHelper.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/OutputHelper.h @@ -21,4 +21,28 @@ namespace util { 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) + "..."; + } } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/StringHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/StringHelper.h new file mode 100644 index 0000000..0d7839a --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/StringHelper.h @@ -0,0 +1,36 @@ +/* +File: StringHelper.h +Description: Provides utility functions for extracting numeric values from strings. + Useful for parsing IDs, codes, or mixed alphanumeric inputs where + digits need to be isolated and converted into integers. +Author: Trenser +Date: 22-May-2026 +*/ + +#include +#include + +namespace util +{ + /* + Function: extractNumber + Description: Extracts all digits from the given string and converts them into an integer. + Ignores non-digit characters. For example, "abc123xyz" returns 123. + Parameters: + - input: const std::string&, the input string containing digits and/or other characters + Returns: + - int: The integer value formed by concatenating all digits in the string + */ + inline int extractNumber(const std::string& input) + { + int result = 0; + for (char character : input) + { + if (std::isdigit(static_cast(character))) + { + result = result * 10 + (character - '0'); + } + } + return result; + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h new file mode 100644 index 0000000..300d5c4 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Utility.h @@ -0,0 +1,102 @@ +/* +File: Utility.h +Description: Header file declaring utility functions used across the system +Author: Trenser +Date:19-May-2026 +*/ + +#pragma once +#include "ComboPackage.h" +#include "DataStore.h" +#include "FileHelper.h" +#include "InventoryItem.h" +#include "NotificationManagementService.h" +#include "Service.h" + +namespace util +{ + /* + Function: calculatePartsCost + Description: Calculates the total cost of parts required for a given service + by summing the prices of all associated inventory items. + Parameter: const Service* service - pointer to the service object + Return type: double - total cost of required parts + */ + 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; + } + + /* + Function: calculateComboServiceEstimatedCost + Description: Calculates the estimated total cost of a combo package by summing + the labor and parts costs of all services included in the package. + Parameter: const ComboPackage* comboPackage - pointer to the combo package object + Return type: double - estimated total cost of the combo package + */ + inline double calculateComboServiceEstimatedCost(const ComboPackage* comboPackage) + { + double cost = 0; + auto& services = comboPackage->getServices(); + int servicesSize = services.getSize(); + for (int index = 0; index < servicesSize; index++) + { + const Service* service = services.getValueAt(index); + cost += calculatePartsCost(service) + service->getLaborCost(); + } + return cost; + } + + /* + Function: loadObservers + Description: Loads observer IDs from a file and attaches the corresponding users + to the notification management service. Validates that each observer ID + exists in the datastore before attaching. + Parameters: + - filePath: const std::string&, path to the file containing observer IDs + - service: NotificationManagementService*, pointer to the notification service + - dataStore: DataStore&, reference to the datastore containing users + Returns: + - void + Throws: + - std::runtime_error if an observer ID is invalid (not found in datastore) + */ + inline void loadObservers(const std::string& filePath, NotificationManagementService* service, DataStore& dataStore) + { + auto observerIDs = util::loadRecords(filePath); + auto& users = dataStore.getUsers(); + for (int index = 0; index < observerIDs.getSize(); index++) + { + const std::string& observerID = observerIDs[index]; + int userIndex = users.find(observerID); + if (userIndex == -1) + { + throw std::runtime_error("Invalid Observer ID"); + } + service->attach(users.getValueAt(userIndex)); + } + } + + /* + Function: saveObservers + Description: Saves the current observer IDs from the notification management service + to a file for persistence. + Parameters: + - filePath: const std::string&, path to the file where observer IDs will be saved + - service: NotificationManagementService*, pointer to the notification service + Returns: + - void + */ + inline void saveObservers(const std::string& filePath, NotificationManagementService* service) + { + auto observerIDs = service->getObserverIDs(); + util::saveRecords(filePath, observerIDs); + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.cpp index b2ed37d..f56d660 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.cpp @@ -106,4 +106,70 @@ bool util::isPasswordValid(const std::string& password) } return hasUpper && hasLower && hasDigit && hasSpecial; +} + +/* + * Function: isUsernameDuplicate + * Description: Checks if the given username already exists among active users. + * Parameters: + * username - string containing the username to validate + * usersMap - map of user objects keyed by identifier + * Returns: + * 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& usersMap) +{ + int index = usersMap.findIf( + [&](const std::string&, User* user) + { + return (user->getUserName() == username && user->getState() == util::State::ACTIVE); + } + ); + return index != -1; +} + +/* + * Function: isPhoneDuplicate + * Description: Checks if the given phone number already exists among active users. + * Parameters: + * phone - string containing the phone number to validate + * usersMap - map of user objects keyed by identifier + * Returns: + * bool - true if the phone number is already in use by an active user, false otherwise + * Notes: + * - Only considers users with state util::State::ACTIVE + */ +bool util::isPhoneDuplicate(const std::string& phone, const util::Map& usersMap) +{ + int index = usersMap.findIf( + [&](const std::string&, User* user) + { + return (user->getPhone() == phone && user->getState() == util::State::ACTIVE); + } + ); + return index != -1; +} + +/* + * Function: isEmailDuplicate + * Description: Checks if the given email address already exists among active users. + * Parameters: + * email - string containing the email address to validate + * usersMap - map of user objects keyed by identifier + * Returns: + * bool - true if the email address is already in use by an active user, false otherwise + * Notes: + * - Only considers users with state util::State::ACTIVE + */ +bool util::isEmailDuplicate(const std::string& email, const util::Map& usersMap) +{ + int index = usersMap.findIf( + [&](const std::string&, User* user) + { + return (user->getEmail() == email && user->getState() == util::State::ACTIVE); + } + ); + return index != -1; } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.h index 8602e4e..aa7b526 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/utilities/Validator.h @@ -9,10 +9,15 @@ #include #include #include +#include "Map.h" +#include "User.h" namespace util { bool isPhoneNumberValid(const std::string&); bool isEmailValid(const std::string&); bool isPasswordValid(const std::string&); + bool isUsernameDuplicate(const std::string&, const util::Map&); + bool isPhoneDuplicate(const std::string&, const util::Map&); + bool isEmailDuplicate(const std::string&, const util::Map&); } \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp index 0432f3c..e7ee48a 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.cpp @@ -1,89 +1,706 @@ -#include "AdminMenu.h" -#include "InputHelper.h" -#include "OutputHelper.h" +/* +File: AdminMenu.cpp +Description: Implements the AdminMenu class which provides the administrator’s console interface + in the Vehicle Service Management System. Handles menu display, user input, and + admin-specific operations such as inventory management, technician management, + service creation, combo package management, job assignment, and notifications. +Author: Trenser +Date: 19-May-2026 +*/ +#include +#include +#include "AdminMenu.h" +#include "Enums.h" +#include "InputHelper.h" +#include "InventoryItem.h" +#include "MenuHelper.h" +#include "OutputHelper.h" +#include "Service.h" +#include "ServiceBooking.h" +#include "User.h" +#include "Utility.h" +#include "Validator.h" + +/* +Function: showMenu +Description: Displays the admin menu and handles user input until logout is selected. +Parameter: None +Return type: void +*/ void AdminMenu::showMenu() { - bool isMenuActive = true; - while (isMenuActive) - { - try - { - int choice; - util::clear(); - std::cout << "" << std::endl; - util::read(choice); - if (!handleOperation(choice)) - { - isMenuActive = false; - } - } - catch (const std::exception& e) - { - std::cout << "Exception: " << e.what() << std::endl; - util::pressEnter(); - } - } + while (true) + { + try + { + int choice; + util::clear(); + std::cout << "Admin Menu" + << "\n1. View Stock Levels" + << "\n2. Add Inventory Item" + << "\n3. Remove Inventory Item" + << "\n4. Check Stock Availability" + << "\n5. Assign Job to Technician" + << "\n6. Display Users" + << "\n7. Add Technician" + << "\n8. Remove Customer/Technician" + << "\n9. Display Services" + << "\n10. Create Service" + << "\n11. Remove Service" + << "\n12. Display Combo Packages" + << "\n13. Create Combo Package" + << "\n14. Remove Combo Package" + << "\n15. View Notifications" + << "\n16. Change Password" + << "\n17. Logout" + << "\nEnter a choice: "; + util::read(choice); + if (!handleOperation(choice)) + { + break; + } + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << std::endl; + util::pressEnter(); + } + } } +/* +Function: handleOperation +Description: Executes the corresponding admin operation based on the selected menu choice. +Parameter: int choice - selected menu option +Return type: bool - true if menu continues, false if logout +*/ bool AdminMenu::handleOperation(int choice) { - return false; + switch (choice) + { + case 1: + viewStockLevels(); + break; + case 2: + addInventoryItem(); + break; + case 3: + removeInventoryItem(); + break; + case 4: + checkStockAvailability(); + break; + case 5: + assignJob(); + break; + case 6: + displayUsers(); + break; + case 7: + addTechnician(); + break; + case 8: + removeUser(); + break; + case 9: + displayServices(); + break; + case 10: + createService(); + break; + case 11: + removeService(); + break; + case 12: + displayComboPackages(); + break; + case 13: + createComboPackages(); + break; + case 14: + removeComboPackage(); + break; + case 15: + viewNotifications(); + break; + case 16: + changePassword(); + break; + case 17: + logout(); + return false; + default: + std::cout << "Enter a valid choice!" << std::endl; + util::pressEnter(); + } + return true; } - +/* +Function: logout +Description: Logs out the currently authenticated admin user. +Parameter: None +Return type: void +*/ void AdminMenu::logout() { + m_controller.logout(); } +/* +Function: changePassword +Description: Allows the admin to change their password after validation. +Parameter: None +Return type: void +*/ void AdminMenu::changePassword() { + changePasswordHelper(m_controller); } +/* +Function: viewStockLevels +Description: Displays all active inventory items with their details + including ID, part name, quantity, and price. +Parameter: None +Return type: void +*/ void AdminMenu::viewStockLevels() { + util::clear(); + auto inventoryItems = m_controller.getInventoryItems(); + bool hasActiveItems = false; + std::cout << "View Stock Levels" << std::endl; + if (inventoryItems.isEmpty()) + { + std::cout << "No items found in Inventory.\n"; + util::pressEnter(); + return; + } + for (int index = 0; index < inventoryItems.getSize(); index++) + { + const InventoryItem* item = inventoryItems.getValueAt(index); + if (item->getState() == util::State::ACTIVE) + { + hasActiveItems = true; + break; + } + } + if (!hasActiveItems) + { + std::cout << "No active Inventory Item found.\n"; + util::pressEnter(); + return; + } + std::cout << std::left << std::setw(15) << "Item ID" + << std::setw(25) << "Part Name" + << std::setw(15) << "Quantity" + << std::setw(15) << "Price" + << std::endl; + for (int iterator = 0; iterator < inventoryItems.getSize(); ++iterator) + { + const InventoryItem* item = inventoryItems.getValueAt(iterator); + if (item != nullptr) + { + if (item->getState() != util::State::INACTIVE) + { + std::cout << std::left << std::setw(15) << item->getId() + << std::setw(25) << item->getPartName() + << std::setw(15) << item->getQuantity() + << std::setw(15) << item->getPrice() + << std::endl; + } + } + } + std::cout << "\n"; + util::pressEnter(); } +/* +Function: addInventoryItem +Description: Allows the admin to either add a new inventory item + or increase the quantity of an existing item. +Parameter: None +Return type: void +*/ void AdminMenu::addInventoryItem() { + util::clear(); + int choice, quantity; + double price; + std::string partName; + std::cout << "Add Inventory Item\n"; + std::cout << "1. Add new item \n2. Restock Item\n\nEnter your choice : "; + util::read(choice); + switch (choice) + { + case 1: + { + util::clear(); + std::cout << "Enter Item Details\n"; + std::cout << "Part Name : "; + util::read(partName); + std::cout << "Quantity : "; + util::read(quantity); + std::cout << "Price : "; + util::read(price); + m_controller.addInventoryItem(partName, quantity, price); + std::cout << "\nNew Item " << partName << " added to the Inventory.\n\n"; + break; + } + case 2: + { + util::clear(); + std::cout << "Select Item to Restock\n"; + auto inventoryItems = m_controller.getInventoryItems(); + addQuantityToItem(inventoryItems, m_controller); + break; + } + default: + { + std::cout << "\nEnter a valid choice.\n\n"; + } + } + util::pressEnter(); } +/* +Function: removeInventoryItem +Description: Removes an active inventory item by marking it inactive + after user selection. +Parameter: None +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(); + if (activeItemsSize == 0) + { + std::cout << "No items available in Inventory." << std::endl; + util::pressEnter(); + return; + } + displayInventoryWithItems(activeItems); + int itemIndex; + std::cout << "Enter the index of the item to remove: "; + util::read(itemIndex); + if (itemIndex < 1 || itemIndex > activeItemsSize) + { + std::cout << "Invalid index selected." << std::endl; + util::pressEnter(); + return; + } + const InventoryItem* selectedItem = activeItems.getValueAt(itemIndex - 1); + if (selectedItem != nullptr) + { + if(selectedItem->getState() != util::State::INACTIVE) + { + std::string selectedItemId = selectedItem->getId(); + m_controller.removeInventoryItem(selectedItemId); + std::cout << "Item " << selectedItem->getPartName() << " removed successfully." << std::endl; + } + } + util::pressEnter(); } +/* +Function: checkStockAvailability +Description: Checks if a specific inventory item is available + and displays its details if active. +Parameter: None +Return type: void +*/ void AdminMenu::checkStockAvailability() { + util::clear(); + std::string itemId; + std::cout << "Check Stock Availability \n"; + std::cout << "Enter the Item ID : "; + util::read(itemId); + util::clear(); + const InventoryItem* selectedItem = m_controller.getInventoryItem(itemId); + if (selectedItem != nullptr) + { + if (selectedItem->getState() != util::State::INACTIVE) + { + std::cout << "Item Details\n"; + std::cout << "---------------------------------------------\n"; + std::cout << "Item ID : " << selectedItem->getId() << "\n"; + std::cout << "Part Name : " << selectedItem->getPartName() << "\n"; + std::cout << "Quantity : " << selectedItem->getQuantity() << "\n"; + } + } + else + { + std::cout << "Item not Found" << std::endl; + } + util::pressEnter(); } +/* +Function: assignJob +Description: Allows the admin to assign pending service bookings to available technicians. + Creates job cards for selected services. +Parameters: + - None +Returns: + - void +*/ void AdminMenu::assignJob() { + util::clear(); + std::cout << "Assign Job to Technician\n"; + std::string selectedService; + bool hasPendingService = false; + auto currentBookings = m_controller.getServiceBookings(); + auto pendingServiceBookings = filterActiveServiceBookings(currentBookings); + auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN); + int bookingsSize = pendingServiceBookings.getSize(); + util::Map serviceBookingsMap; + util::Map currentAvailableTechniciansMap; + if (listServiceBookings(pendingServiceBookings, bookingsSize, serviceBookingsMap)) + { + const ServiceBooking* selectedService = selectPendingServiceBookings(serviceBookingsMap); + if (selectedService) + { + if (availableTechnicians.getSize() != 0) + { + listAvailableTechnicians(availableTechnicians, availableTechnicians.getSize(), currentAvailableTechniciansMap); + const User* selectedTechnician = selectTechnician(currentAvailableTechniciansMap); + if (selectedTechnician) + { + auto& servicesInBooking = selectedService->getServices(); + for (int iterator = 0; iterator < servicesInBooking.getSize(); iterator++) + { + m_controller.createJobCard(selectedService->getId(), selectedTechnician->getId(), servicesInBooking.getValueAt(iterator)->getId()); + } + std::cout << "Job card created for each service and technician successfully assigned.\n\n"; + } + } + else + { + std::cout << "No technicians are currently available.\n\n"; + } + } + } + else + { + std::cout << "No pending service bookings available.\n\n"; + } + util::pressEnter(); } +/* +Function: displayServices() +Description: Display all active services +Parameters: + - None +Returns: + - void +*/ +void AdminMenu::displayServices() +{ + util::clear(); + std::cout << "List of all Services\n"; + util::Map currentServices = m_controller.getServices(); + util::Map currentActiveServices = filterActiveServices(currentServices); + displayAllServices(currentActiveServices); + util::pressEnter(); +} + +/* +Function: createService +Description: Allows the admin to create a new service by selecting inventory items and specifying labor cost. +Parameters: + - None +Returns: + - void +*/ void AdminMenu::createService() { + util::clear(); + std::cout << "Create Service\n"; + std::string serviceName; + double labourCost; + std::cout << "Enter the service name: "; + util::read(serviceName); + util::Map currentInventoryItems = m_controller.getInventoryItems(); + 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); + std::cout << "\nService created sucessfully.\n\n"; + util::pressEnter(); } +/* +Function: removeService +Description: Allows the admin to remove an existing service by selecting from available services. +Parameters: + - None +Returns: + - void +*/ void AdminMenu::removeService() { + util::clear(); + std::cout << "Remove Service\n"; + std::string selectedServiceID; + util::Map currentServices = m_controller.getServices(); + util::Map currentActiveServices = filterActiveServices(currentServices); + selectedServiceID = selectServicesToRemove(currentActiveServices); + if (selectedServiceID != "") + { + m_controller.removeService(selectedServiceID); + std::cout << "Service removed successfully.\n\n"; + } + else + { + std::cout << "Failed to remove service.\n\n"; + } + util::pressEnter(); } +/* +Function: displayUsers +Description: Displays all users. +Parameter: None +Return type: void +*/ +void AdminMenu::displayUsers() +{ + util::clear(); + auto listOfUsers = m_controller.getUsers(); + auto listOfActiveUsers = filterActiveUsers(listOfUsers); + int activeUserCount = listOfActiveUsers.getSize(); + std::cout << "List of all Users\n"; + if (activeUserCount < 1) + { + std::cout << "No Active users." << std::endl; + util::pressEnter(); + return; + } + displayAllUsers(listOfActiveUsers); + util::pressEnter(); +} + +/* +Function: addTechnician +Description: Adds a new technician after validating username, password, email, and phone number. +Parameter: None +Return type: void +*/ void AdminMenu::addTechnician() { + util::clear(); + std::string username, name, password, email, phoneNumber; + std::cout << "Add Technician\n"; + std::cout << "Enter Technician Username: "; + util::read(username); + std::cout << "Enter Technician Name: "; + util::read(name); + std::cout << "Enter Technician Password: "; + util::read(password); + if(!util::isPasswordValid(password)) + { + std::cout << "\nError: Password is invalid!\n\n"; + util::pressEnter(); + return; + } + std::cout << "Enter Technician Email: "; + util::read(email); + if(!util::isEmailValid(email)) + { + std::cout << "\nError: Email is invalid!\n\n"; + util::pressEnter(); + return; + } + std::cout << "Enter Technician Phone: "; + util::read(phoneNumber); + if(!util::isPhoneNumberValid(phoneNumber)) + { + std::cout << "\nError: Phone Number is invalid!\n\n"; + util::pressEnter(); + return; + } + m_controller.createTechnician(username, name, password, email, phoneNumber); + std::cout << "\nTechnician Added Successfully.\n\n"; + util::pressEnter(); } +/* +Function: removeUser +Description: Removes a selected active user (customer or technician) from the system. +Parameter: None +Return type: void +*/ void AdminMenu::removeUser() { + util::clear(); + int indexChoice; + auto listOfUsers = m_controller.getUsers(); + auto listOfActiveUsers = filterActiveUsers(listOfUsers); + int activeUserCount = listOfActiveUsers.getSize(); + std::cout << "Remove User \n"; + if (activeUserCount < 1) + { + std::cout << "No Active users." << std::endl; + util::pressEnter(); + return; + } + displayAllUsers(listOfActiveUsers); + std::cout << "Enter the index of the user to delete : "; + util::read(indexChoice); + if (indexChoice < 1 || indexChoice > activeUserCount) + { + std::cout << "Error invalid index.\n" << std::endl; + util::pressEnter(); + return; + } + const User* userToRemove = listOfActiveUsers.getValueAt(indexChoice - 1); + if (userToRemove != nullptr) + { + std::string userIdToRemove = userToRemove->getId(); + m_controller.removeUser(userIdToRemove); + std::cout << userToRemove->getUserName() << " removed Successfully.\n"; + } + util::pressEnter(); } +/* +Function: displayComboPackages() +Description: Display all active combo packages +Parameters: + - None +Returns: + - void +*/ +void AdminMenu::displayComboPackages() +{ + util::clear(); + std::cout << "List of all Combo Packages\n"; + util::Map currentComboPackages = m_controller.getComboPackages(); + util::Map currentActiveComboPackages = filterComboPackages(currentComboPackages); + displayAllComboPackages(currentActiveComboPackages); + util::pressEnter(); +} + +/* +Function: createComboPackages +Description: Creates a new combo package by selecting two active services and applying a discount. +Parameter: None +Return type: void +*/ void AdminMenu::createComboPackages() { + util::clear(); + std::cout << "Create Combo Packages\n"; + auto serviceList = m_controller.getServices(); + auto activeServices = filterActiveServices(serviceList); + int currentActiveServicesCount = activeServices.getSize(); + const int NUMBER_OF_SERVICE_PER_PACKAGE = 2; + util::Vector selectedServiceID; + for (int iterator = 0; iterator < NUMBER_OF_SERVICE_PER_PACKAGE; iterator++) + { + const Service* chosenService = nullptr; + while (true) + { + chosenService = selectServiceFromServices(activeServices); + if (!chosenService) + { + std::cout << "Failed to create combo package!\n\n"; + util::pressEnter(); + return; + } + bool alreadyChosen = false; + for (int iteratorOne = 0; iteratorOne < selectedServiceID.getSize(); iteratorOne++) + { + if (selectedServiceID[iteratorOne] == chosenService->getId()) + { + alreadyChosen = true; + break; + } + } + if (alreadyChosen) + { + if (currentActiveServicesCount < 2) + { + break; + } + std::cout << "Service already selected. Please choose a different one." << std::endl; + continue; + } + selectedServiceID.push_back(chosenService->getId()); + break; + } + if (currentActiveServicesCount < 2) + { + std::cout << "All the available services selected\n\n"; + break; + } + } + std::string packageName; + double discountPercentage; + std::cout << "Enter combo package name: "; + util::read(packageName); + std::cout << "Enter discount percentage: "; + util::read(discountPercentage); + if (discountPercentage < 0.0 || discountPercentage > 100.0) + { + std::cout << "Error: Discount percentage must be between 0 and 100." << std::endl; + util::pressEnter(); + return; + } + m_controller.createComboPackage(packageName, selectedServiceID, discountPercentage); + std::cout << "Combo package '" << packageName << "' created successfully." << std::endl; + util::pressEnter(); } +/* +Function: removeComboPackage +Description: Removes a selected combo package from the system. +Parameter: None +Return type: void +*/ void AdminMenu::removeComboPackage() { + util::clear(); + std::cout << "Remove Combo Package\n"; + util::Map currentComboPackages = m_controller.getComboPackages(); + std::string selectedComboPackageID = selectComboPackage(currentComboPackages); + if (!selectedComboPackageID.empty()) + { + m_controller.removeComboPackage(selectedComboPackageID); + std::cout << "Combo Package removed successfully.\n\n"; + } + else + { + std::cout << "Combo package removal failed.\n\n"; + } + util::pressEnter(); } +/* +Function: viewNotifications +Description: Displays notifications for the admin and allows deletion of notifications. +Parameters: + - None +Returns: + - void +*/ void AdminMenu::viewNotifications() { + viewAndDeleteNotification(m_controller); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h index 05fdd84..2fe2283 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/AdminMenu.h @@ -1,3 +1,12 @@ +/* +File: AdminMenu.h +Description: Header file declaring the AdminMenu class, which provides + administrative operations such as inventory management, + user management, service configuration, and notifications. +Author: Trenser +Date:19-May-2026 +*/ + #pragma once #include "Controller.h" @@ -15,10 +24,13 @@ public: void removeInventoryItem(); void checkStockAvailability(); void assignJob(); + void displayServices(); void createService(); void removeService(); + void displayUsers(); void addTechnician(); void removeUser(); + void displayComboPackages(); void createComboPackages(); void removeComboPackage(); void viewNotifications(); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp index 047f471..022885f 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.cpp @@ -1,72 +1,401 @@ +/* +File: CustomerMenu.cpp +Description: Implementation file containing the method definitions of the + CustomerMenu class, including menu handling, service selection, + combo package booking, profile updates, and password management. +Author: Trenser +Date:19-May-2026 +*/ + +#include +#include "ComboPackage.h" #include "CustomerMenu.h" +#include "MenuHelper.h" +#include "Enums.h" #include "InputHelper.h" #include "OutputHelper.h" +#include "InventoryItem.h" +#include "Invoice.h" +#include "Map.h" +#include "Service.h" +#include "ServiceBooking.h" +#include "Timestamp.h" +#include "User.h" +#include "Validator.h" +#include "Vector.h" + +/* +Function: showMenu +Description: Displays the customer menu and handles user input until logout is selected. +Parameter: None +Return type: void +*/ void CustomerMenu::showMenu() { - bool isMenuActive = true; - while (isMenuActive) - { - try - { - int choice; - util::clear(); - std::cout << "" << std::endl; - util::read(choice); - if (!handleOperation(choice)) - { - isMenuActive = false; - } - } - catch (const std::exception& e) - { - std::cout << "Exception: " << e.what() << std::endl; - util::pressEnter(); - } - } + while (true) + { + try + { + int choice; + util::clear(); + std::cout << "Customer Menu" + << "\n1. Select a service" + << "\n2. Select a combo package" + << "\n3. Update Profile" + << "\n4. Change Password" + << "\n5. View Service History" + << "\n6. Complete Payments" + << "\n7. View Invoices" + << "\n8. View Notifications" + << "\n9. Configure Notifications" + << "\n10. Logout" + << "\nEnter a choice: "; + util::read(choice); + if (!handleOperation(choice)) + { + break; + } + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << std::endl; + util::pressEnter(); + } + } } +/* +Function: handleOperation +Description: Executes the corresponding customer operation based on the selected menu choice. +Parameter: int choice - selected menu option +Return type: bool - true if menu continues, false if logout +*/ bool CustomerMenu::handleOperation(int choice) { - return false; + switch (choice) + { + case 1: + selectService(); + break; + case 2: + selectComboPackage(); + break; + case 3: + updateDetails(); + break; + case 4: + changePassword(); + break; + case 5: + viewServiceHistory(); + break; + case 6: + completePayments(); + break; + case 7: + viewInvoices(); + break; + case 8: + viewNotifications(); + break; + case 9: + configureNotifications(); + break; + case 10: + logout(); + return false; + default: + std::cout << "Enter a valid choice!" << std::endl; + util::pressEnter(); + } + return true; } +/* +Function: logout +Description: Logs out the currently authenticated customer user. +Parameter: None +Return type: void +*/ void CustomerMenu::logout() { + m_controller.logout(); } +/* +Function: changePassword +Description: Allows the customer to change their password after validation. +Parameter: None +Return type: void +*/ void CustomerMenu::changePassword() { + changePasswordHelper(m_controller); } +/* +Function: updateDetails +Description: Allows the customer to update their email and phone number after validation. +Parameter: None +Return type: void +*/ void CustomerMenu::updateDetails() { + std::string email, phone; + util::clear(); + std::cout << "Update Details\n"; + std::cout << "Enter new email: "; + util::read(email); + if (!util::isEmailValid(email)) + { + std::cout << "Error: Email is invalid!\n"; + util::pressEnter(); + return; + } + std::cout << "Enter new phone: "; + util::read(phone); + if (!util::isPhoneNumberValid(phone)) + { + std::cout << "Error: Phone number is invalid!\n"; + util::pressEnter(); + return; + } + m_controller.updateUserDetails(email, phone); + std::cout << "Profile details updated successfully\n"; + util::pressEnter(); } +/* +Function: selectService +Description: Allows the customer to select a service, provide vehicle details, + and book the service through the controller. +Parameter: None +Return type: void +*/ void CustomerMenu::selectService() { + std::string vehicleNumber, vehicleBrand, vehicleModel; + util::clear(); + std::cout << "Select a Service\n"; + auto services = m_controller.getServices(); + if (services.isEmpty()) + { + std::cout << "No services available!"; + util::pressEnter(); + return; + } + util::Vector selectedServices; + const Service* selectedService = selectServiceFromServices(services); + if (selectedService == nullptr) + { + std::cout << "Failed to book service!"; + util::pressEnter(); + return; + } + selectedServices.push_back(selectedService->getId()); + util::clear(); + std::cout << "Enter Vehicle Details\n"; + std::cout << "Enter vehicle number: "; + util::read(vehicleNumber); + std::cout << "Enter vehicle brand: "; + util::read(vehicleBrand); + std::cout << "Enter vehicle model: "; + util::read(vehicleModel); + m_controller.purchaseService(selectedServices, vehicleNumber, vehicleBrand, vehicleModel); + std::cout << "Service has been booked successfully"; + util::pressEnter(); } +/* +Function: selectComboPackage +Description: Allows the customer to select a combo package, provide vehicle details, + and book the package through the controller. +Parameter: None +Return type: void +*/ void CustomerMenu::selectComboPackage() { + std::string vehicleNumber, vehicleBrand, vehicleModel; + util::clear(); + std::cout << "Select a Combo Package\n"; + auto comboPackages = m_controller.getComboPackages(); + util::Map activeComboPackages = filterComboPackages(comboPackages); + if (activeComboPackages.isEmpty()) + { + std::cout << "No combo packages available!\n\n"; + util::pressEnter(); + return; + } + const ComboPackage* selectedComboPackage = selectComboPackageFromPackages(activeComboPackages); + if (selectedComboPackage == nullptr) + { + std::cout << "Failed to book combo package!\n\n"; + util::pressEnter(); + return; + } + std::cout << "Combo Package selected\n"; + util::pressEnter(); + util::clear(); + std::cout << "Enter the vehicle details\n"; + std::cout << "Enter vehicle number: "; + util::read(vehicleNumber); + std::cout << "Enter vehicle brand: "; + util::read(vehicleBrand); + std::cout << "Enter vehicle model: "; + util::read(vehicleModel); + m_controller.purchaseComboPackage(selectedComboPackage->getId(), vehicleNumber, vehicleBrand, vehicleModel); + std::cout << "Combo Package has been booked successfully\n\n"; + util::pressEnter(); } +/* +Function: viewServiceHistory +Description: Displays the customer’s past service bookings in tabular format, + including booking ID, technician, vehicle details, discount percentage, and status. +Parameters: + - None +Returns: + - void +*/ void CustomerMenu::viewServiceHistory() { + util::clear(); + bool hasServiceHistory = false; + const User* currentUser = m_controller.getAuthenticatedUser(); + std::string currentUserID = currentUser->getId(); + util::Map serviceBookingsByCurrentUser = m_controller.getServiceBookingsByUser(currentUserID); + std::cout << "View Service History" << std::endl; + if (serviceBookingsByCurrentUser.getSize() != 0) + { + std::cout << std::left + << std::setw(15) << "Booking ID" + << std::setw(20) << "Technician" + << std::setw(20) << "Vehicle Brand" + << std::setw(20) << "Vehicle Number" + << std::setw(20) << "Vehicle Model" + << std::setw(20) << "Discount %" + << std::setw(20) << "Status" + << std::endl; + for (int iterator = 0; iterator < serviceBookingsByCurrentUser.getSize(); iterator++) + { + const ServiceBooking* currentBooking = serviceBookingsByCurrentUser.getValueAt(iterator); + std::string technicianName = currentBooking->getAssignedTechnician() == nullptr + ? "Not Assigned" + : currentBooking->getAssignedTechnician()->getName(); + std::cout << std::left + << std::setw(15) << currentBooking->getId() + << std::setw(20) << technicianName + << std::setw(20) << currentBooking->getVehicleBrand() + << std::setw(20) << currentBooking->getVehicleNumber() + << std::setw(20) << currentBooking->getVehicleModel() + << std::setw(20) << currentBooking->getDiscountPercentage() + << std::setw(20) << util::getServiceJobStatusString(currentBooking->getStatus()) + << std::endl; + hasServiceHistory = true; + } + } + if (!hasServiceHistory) + { + std::cout << "No history available." << std::endl; + } + util::pressEnter(); } +/* +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(); + std::cout << "Complete Payments\n"; + util::Map currentInvoices = m_controller.getInvoicesByUser(); + if (currentInvoices.isEmpty()) + { + std::cout << "No pending invoices available for payment.\n"; + util::pressEnter(); + return; + } + bool hasPending = false; + for (int index = 0; index < currentInvoices.getSize(); ++index) + { + const Invoice* invoice = currentInvoices.getValueAt(index); + if (invoice && invoice->getStatus() == util::PaymentStatus::PENDING) + { + hasPending = true; + break; + } + } + if (!hasPending) + { + std::cout << "No pending invoices available for payment.\n"; + util::pressEnter(); + return; + } + std::string selectedID = selectInvoiceFromUserForPayment(currentInvoices); + if (selectedID == "") + { + std::cout << "Payment failed.\n"; + util::pressEnter(); + return; + } + util::PaymentMode paymentMode = selectPaymentMode(); + m_controller.completePayment(selectedID, paymentMode); + std::cout << "Payment completed successfully.\n"; + util::pressEnter(); } +/* +Function: viewInvoices +Description: Displays invoices associated with the customer by calling displayInvoices. +Parameters: + - None +Returns: + - void +*/ void CustomerMenu::viewInvoices() { + util::clear(); + std::cout << "View Invoices\n"; + util::Map currentUserInvoices = m_controller.getInvoicesByUser(); + displayInvoices(currentUserInvoices); + util::pressEnter(); } +/* +Function: viewNotifications +Description: Displays notifications for the customer and allows deletion of notifications. +Parameters: + - None +Returns: + - void +*/ void CustomerMenu::viewNotifications() { + viewAndDeleteNotification(m_controller); } + +/* +Function: configureNotifications +Description: Allows the customer to configure notification preferences for payment and service management. +Parameters: + - None +Returns: + - void +*/ void CustomerMenu::configureNotifications() { -} + bool paymentServiceNotifications = getNotificationPreference("Payment Management Service"); + bool serviceManagementNotifications = getNotificationPreference("Service Management Service"); + m_controller.configureNotifications(paymentServiceNotifications, serviceManagementNotifications); + util::clear(); + std::cout << "Notification preferences updated successfully.\n"; + util::pressEnter(); +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h index 886cf62..d491720 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/CustomerMenu.h @@ -1,3 +1,13 @@ +/* +File: CustomerMenu.h +Description: Header file declaring the CustomerMenu class, which provides + customer operations such as selecting services, booking combo + packages, updating profile details, managing payments, viewing + invoices, and configuring notifications. +Author: Trenser +Date:19-May-2026 +*/ + #pragma once #include "Controller.h" diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h new file mode 100644 index 0000000..f65c1f4 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/MenuHelper.h @@ -0,0 +1,1360 @@ +/* +File: MenuHelper.h +Description: Header file declaring the MenuHelper class, which provides + utility functions for menu-driven operations such as + notification selection and display. +Author: Trenser +Date: 21-May-2026 +*/ + +#pragma once +#include +#include +#include +#include "ComboPackage.h" +#include "Controller.h" +#include "Enums.h" +#include "InputHelper.h" +#include "InventoryItem.h" +#include "Invoice.h" +#include "JobCard.h" +#include "Map.h" +#include "Notification.h" +#include "OutputHelper.h" +#include "Service.h" +#include "ServiceBooking.h" +#include "Timestamp.h" +#include "User.h" +#include "Utility.h" +#include "Validator.h" +#include "Vector.h" + +/* +Function: displayAllServices +Description: Displays all active services +Parameters: + - currentServices: util::Map, available services +Returns: + - void; +*/ +inline void displayAllServices(util::Map currentServices) +{ + if (currentServices.getSize() == 0) + { + std::cout << "No Services Currently Available.\n"; + return; + } + std::cout << std::left + << std::setw(12) << "Service ID" + << std::setw(35) << "Name" + << std::setw(10) << "Labor Cost" + << std::endl; + for (int iterator = 0; iterator < currentServices.getSize(); iterator++) + { + const Service* currentService = currentServices.getValueAt(iterator); + if (currentService == nullptr || currentService->getState() == util::State::INACTIVE) + { + continue; + } + std::cout << std::left + << std::setw(12) << currentService->getId() + << std::setw(35) << util::truncateString(currentService->getName(), 30) + << std::setw(10) << currentService->getLaborCost() + << std::endl; + } +} + +/* +Function: selectServicesToRemove +Description: Allows selection of a service to remove by index. +Parameters: + - currentServices: util::Map, available services +Returns: + - std::string: ID of the selected service, or empty string if invalid +*/ +inline std::string selectServicesToRemove(util::Map currentServices) +{ + if (currentServices.getSize() == 0) + { + std::cout << "No Services Currently Available.\n"; + return ""; + } + util::Map currentServicesMap; + int currentIndex = 1, choice; + std::cout << std::left + << std::setw(6) << "Index" + << std::setw(12) << "Service ID" + << std::setw(35) << "Name" + << std::setw(10) << "Labor Cost" + << std::endl; + for (int iterator = 0; iterator < currentServices.getSize(); iterator++) + { + const Service* currentService = currentServices.getValueAt(iterator); + if (currentService == nullptr || currentService->getState() == util::State::INACTIVE) + { + continue; + } + std::cout << std::left + << std::setw(6) << currentIndex + << std::setw(12) << currentService->getId() + << std::setw(35) << util::truncateString(currentService->getName(), 30) + << std::setw(10) << currentService->getLaborCost() + << std::endl; + currentServicesMap.insert(currentIndex++, currentService); + } + std::cout << "Enter your choice: "; + util::read(choice); + if (currentServicesMap.find(choice) != -1) + { + return currentServicesMap.getValueAt(currentServicesMap.find(choice))->getId(); + } + else +{ + std::cout << "Invalid index." << std::endl; + return ""; + } +} + +/* +Function: selectInventoryItems +Description: Allows selection of inventory items by index for creating a service. +Parameters: + - currentInventoryItems: util::Map&, available inventory items + - selectedInventoryItems: util::Vector&, vector to store selected item IDs +Returns: + - void +*/ +inline void selectInventoryItems(util::Map& currentInventoryItems, util::Vector& selectedInventoryItems) +{ + bool doRun = true; + util::Map currentInventoryMap; + int choice; + 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; + currentInventoryMap.clear(); + std::cout << std::left + << std::setw(6) << "Index" + << std::setw(12) << "Item ID" + << std::setw(20) << "Part Name" + << std::setw(10) << "Price" + << std::setw(10) << "Quantity" + << std::endl; + for (int iterator = 0; iterator < currentInventoryItems.getSize(); iterator++) + { + const InventoryItem* currentInventoryItem = currentInventoryItems.getValueAt(iterator); + if (currentInventoryItem == nullptr || currentInventoryItem->getState() == util::State::INACTIVE) + { + 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() + << std::setw(20) << currentInventoryItem->getPartName() + << std::setw(10) << currentInventoryItem->getPrice() + << std::setw(10) << currentInventoryItem->getQuantity() + << std::endl; + currentInventoryMap.insert(currentIndex++, currentInventoryItem); + hasInventoryItems = true; + } + if (!hasInventoryItems) + { + break; + } + std::cout << "Select the item (Index) or enter 0 to exit: "; + util::read(choice); + if (choice == 0) + { + doRun = false; + } + else if (currentInventoryMap.find(choice) != -1) + { + selectedInventoryItems.push_back(currentInventoryMap.getValueAt(currentInventoryMap.find(choice))->getId()); + std::cout << "Item added successfully.\n" << std::endl; + util::pressEnter(); + } + else + { + std::cout << "Enter a valid integer.\n" << std::endl; + } + } +} + +/* +Function: filterActiveServiceBookings +Description: Filters the given service bookings and returns only bookings with PENDING status. +Parameters: + - currentBookings: util::Map, collection of current service bookings +Returns: + - util::Map: map containing only active (PENDING) service bookings +*/ +inline util::Map filterActiveServiceBookings(util::Map& currentBookings) +{ + util::Map activeServiceBookings; + for (int iterator = 0; iterator < currentBookings.getSize(); iterator++) + { + const ServiceBooking* currentServiceBooking = currentBookings.getValueAt(iterator); + if (currentServiceBooking && currentServiceBooking->getStatus() == util::ServiceJobStatus::PENDING) + { + activeServiceBookings.insert(currentServiceBooking->getId(), currentServiceBooking); + } + } + return activeServiceBookings; +} + +/* +Function: listServiceBookings +Description: Lists all pending service bookings and maps them to indices for selection. +Parameters: + - currentBookings: util::Map&, current bookings + - bookingsSize: int&, number of bookings + - serviceBookingsMap: util::Map&, map of indexed bookings +Returns: + - bool: True if pending services exist, False otherwise +*/ +inline bool listServiceBookings(util::Map& currentBookings, int& bookingsSize, util::Map& serviceBookingsMap) +{ + if (currentBookings.getSize() == 0) + { + return false; + } + int currentIndex = 1; + std::cout << "\nSelect Service Booking" << std::endl; + std::cout << std::left + << std::setw(10) << "Index" + << std::setw(10) << "ID" + << std::setw(12) << "Status" + << std::setw(12) << "CustID" + << std::setw(20) << "Customer" + << std::setw(15) << "VehicleNo" + << std::setw(15) << "Brand" + << std::setw(15) << "Model" + << std::endl; + for (int iterator = 0; iterator < bookingsSize; iterator++) + { + const ServiceBooking* currentBooking = currentBookings.getValueAt(iterator); + if (currentBooking && currentBooking->getStatus() == util::ServiceJobStatus::PENDING) + { + const User* currentAssignedTechnician = currentBooking->getAssignedTechnician(); + std::cout << std::left + << std::setw(10) << currentIndex + << std::setw(10) << currentBooking->getId() + << std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus()) + << std::setw(12) << currentBooking->getCustomerId() + << std::setw(20) << currentBooking->getCustomer()->getName() + << std::setw(15) << currentBooking->getVehicleNumber() + << std::setw(15) << currentBooking->getVehicleBrand() + << std::setw(15) << currentBooking->getVehicleModel() + << std::endl; + serviceBookingsMap.insert(currentIndex++, currentBooking); + } + } + return true; +} + +/* +Function: selectPendingServiceBookings +Description: Allows selection of a pending service booking by index. +Parameters: + - serviceBookingsMap: util::Map&, map of indexed bookings +Returns: + - const ServiceBooking*: Pointer to the selected booking, or nullptr if invalid +*/ +inline const ServiceBooking* selectPendingServiceBookings(util::Map& serviceBookingsMap) +{ + int userInputIndex; + std::cout << "\nEnter a service index: "; + util::read(userInputIndex); + if (serviceBookingsMap.find(userInputIndex) != -1) + { + return serviceBookingsMap.getValueAt(serviceBookingsMap.find(userInputIndex)); + } + else + { + std::cout << "Enter a valid index.\n\n"; + return nullptr; + } +} + +/* +Function: listAvailableTechnicians +Description: Lists all available technicians and maps them to indices for selection. +Parameters: + - currentAvailableTechnicians: util::Map, available technicians + - numberOfTechnicians: int, number of technicians + - currentAvailableTechniciansMap: util::Map&, map of indexed technicians +Returns: + - void +*/ +inline void listAvailableTechnicians(util::Map currentAvailableTechnicians, int numberOfTechnicians, util::Map& currentAvailableTechniciansMap) +{ + bool hasTechnicians = false; + int currentIndex = 1; + std::cout << "\nSelect Technician\n"; + std::cout << std::left + << std::setw(6) << "Index" + << std::setw(15) << "Technician ID" + << std::setw(20) << "Name" + << std::endl; + for (int iterator = 0; iterator < numberOfTechnicians; iterator++) + { + const User* currentTechnician = currentAvailableTechnicians.getValueAt(iterator); + if (currentTechnician->getState() == util::State::INACTIVE) + { + continue; + } + hasTechnicians = true; + std::cout << std::left + << std::setw(6) << currentIndex + << std::setw(15) << currentTechnician->getId() + << std::setw(20) << currentTechnician->getName() + << std::endl; + currentAvailableTechniciansMap.insert(currentIndex++, currentTechnician); + } + if (!hasTechnicians) + { + std::cout << "No technicians currently available.\n\n"; + } +} + +/* +Function: selectTechnician +Description: Allows selection of a technician by index. +Parameters: + - currentAvailableTechniciansMap: util::Map&, map of indexed technicians +Returns: + - const User*: Pointer to the selected technician, or nullptr if invalid +*/ +inline const User* selectTechnician(util::Map& currentAvailableTechniciansMap) +{ + int userInputIndex; + std::cout << "\nEnter technician index: "; + util::read(userInputIndex); + if (currentAvailableTechniciansMap.find(userInputIndex) != -1) + { + return currentAvailableTechniciansMap.getValueAt(currentAvailableTechniciansMap.find(userInputIndex)); + } + else + { + std::cout << "Enter a valid index.\n\n"; + return nullptr; + } +} + +/* +Function: selectInvoiceFromUserForPayment +Description: Lists all pending invoices for the customer and allows selection by index. +Parameters: + - currentInvoices: util::Map&, map of customer invoices +Returns: + - std::string: ID of the selected invoice, or empty string if none selected +*/ +inline std::string selectInvoiceFromUserForPayment(const util::Map& currentInvoices) +{ + int currentIndex = 1, choice; + util::Map pendingInvoicesForPayment; + std::cout << std::left + << std::setw(8) << "Index" + << std::setw(15) << "Booking ID" + << std::setw(20) << "Vehicle Brand" + << std::setw(20) << "Vehicle Number" + << std::setw(18) << "Technician ID" + << std::setw(25) << "Technician Name" + << std::setw(15) << "Discount(%)" + << std::setw(15) << "TotalAmount" + << std::setw(22) << "Invoice Timestamp" + << std::endl; + for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++) + { + const Invoice* currentInvoice = currentInvoices.getValueAt(iterator); + if (currentInvoice && currentInvoice->getStatus() == util::PaymentStatus::PENDING) +{ + const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician(); + std::cout << std::left + << std::setw(8) << currentIndex + << std::setw(15) << currentInvoice->getBookingId() + << std::setw(20) << currentInvoice->getBooking()->getVehicleBrand() + << std::setw(20) << currentInvoice->getBooking()->getVehicleNumber() + << std::setw(18) << ((currentTechnician != nullptr && currentTechnician->getId() != "") ? + currentTechnician->getId() : "Null") + << std::setw(25) << ((currentTechnician != nullptr && currentTechnician->getName() != "") ? + currentTechnician->getName() : "Null") + << std::setw(15) << currentInvoice->getDiscountPercentage() + << std::setw(15) << currentInvoice->getTotalAmount() + << std::setw(22) << 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 index.\n"; + return ""; + } +} + +/* +Function: selectPaymentMode +Description: Allows the customer to select a payment mode (ONLINE or OFFLINE). +Parameters: + - None +Returns: + - util::PaymentMode: Selected payment mode +*/ +inline util::PaymentMode selectPaymentMode() +{ + int choice; + while (true) + { + util::clear(); + 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. Try again.\n"; + util::pressEnter(); + } + } +} + +/* +Function: displayInvoicesInTabularForm +Description: + Displays all invoices in a tabular format. Each row shows booking details, + vehicle info, technician details, discount, total amount, invoice date, + and payment status. If inventory items exist for an invoice, they are + displayed in a separate table below the invoice row. +Parameters: + - currentInvoices: util::Map + Map of invoice IDs to Invoice pointers. +Returns: + - void +*/ +inline const Invoice* selectInvoiceToDisplay(util::Map& currentInvoices) +{ + int currentIndex = 1, choice; + util::Map currentInvoicesIndexMap; + if (currentInvoices.isEmpty()) + { + std::cout << "No invoices available.\n\n"; + return nullptr; + } + std::cout + << std::left + << std::setw(10) << "Index" + << std::setw(12) << "BookingID" + << std::setw(20) << "Vehicle Number" + << std::setw(20) << "Technician Name" + << std::setw(15) << "Total Amount" + << std::setw(25) << "Invoice Date" + << std::setw(20) << "Payment Status" + << std::setw(15) << "Payment Mode" + << std::endl; + for (int iterator = 0; iterator < currentInvoices.getSize(); iterator++) + { + const Invoice* currentInvoice = currentInvoices.getValueAt(iterator); + if (!currentInvoice) + { + continue; + } + const User* currentTechnician = currentInvoice->getBooking()->getAssignedTechnician(); + std::cout << std::left + << std::setw(10) << currentIndex + << std::setw(12) << currentInvoice->getBookingId() + << std::setw(20) << currentInvoice->getBooking()->getVehicleNumber() + << std::setw(20) << ((currentTechnician && !currentTechnician->getName().empty()) ? currentTechnician->getName() : "NULL") + << std::setw(15) << currentInvoice->getTotalAmount() + << std::setw(25) << currentInvoice->getInvoiceDate().toString() + << std::setw(20) << util::getPaymentStatusString(currentInvoice->getStatus()) + << std::setw(15) << util::getPaymentModeString(currentInvoice->getPaymentMethod()) + << std::endl; + currentInvoicesIndexMap.insert(currentIndex++, currentInvoice); + } + std::cout << "Enter an index: "; + util::read(choice); + int currentSelectedIndex = currentInvoicesIndexMap.find(choice); + if (currentSelectedIndex != -1) + { + return currentInvoicesIndexMap.getValueAt(currentSelectedIndex); + } + else + { + std::cout << "Enter a valid index.\n"; + return nullptr; + } +} + +/* +Function: displayInvoices +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, customer’s invoices +Returns: + - void +Throws: + - std::runtime_error if a null invoice is encountered +*/ +inline void displayInvoices(util::Map currentUserInvoices) +{ + std::cout << std::endl; + if (currentUserInvoices.getSize() == 0) + { + std::cout << "No invoices found for this account.\n\n"; + return; + } + else + { + bool doRun = true; + do + { + const Invoice* selectedInvoice; + int choice; + selectedInvoice = selectInvoiceToDisplay(currentUserInvoices); + if (selectedInvoice) + { + const User* currentTechnician = selectedInvoice->getBooking()->getAssignedTechnician(); + util::clear(); + std::cout << "Invoice Details\n"; + std::cout << std::left << std::setw(20) << "Booking ID:" + << selectedInvoice->getBookingId() << std::endl; + std::cout << std::left << std::setw(20) << "Vehicle Brand:" + << selectedInvoice->getBooking()->getVehicleBrand() << std::endl; + std::cout << std::left << std::setw(20) << "Vehicle Number:" + << selectedInvoice->getBooking()->getVehicleNumber() << std::endl; + std::cout << std::left << std::setw(20) << "Technician ID:" + << ((currentTechnician != nullptr && !currentTechnician->getId().empty()) + ? currentTechnician->getId() : "NULL") << std::endl; + std::cout << std::left << std::setw(20) << "Technician Name:" + << ((currentTechnician != nullptr && !currentTechnician->getName().empty()) + ? currentTechnician->getName() : "NULL") << std::endl; + std::cout << std::left << std::setw(20) << "Discount(%):" + << selectedInvoice->getDiscountPercentage() << std::endl; + std::cout << std::left << std::setw(20) << "Total Amount:" + << selectedInvoice->getTotalAmount() << std::endl; + std::cout << std::left << std::setw(20) << "Invoice Date:" + << selectedInvoice->getInvoiceDate().toString() << std::endl; + std::cout << std::left << std::setw(20) << "Payment Status:" + << util::getPaymentStatusString(selectedInvoice->getStatus()) << std::endl; + std::cout << std::left << std::setw(20) << "Payment Mode:" + << util::getPaymentModeString(selectedInvoice->getPaymentMethod()) << std::endl; + auto inventoryItemsInInvoice = selectedInvoice->getParts(); + if (inventoryItemsInInvoice.isEmpty()) + { + std::cout << "No inventory items used.\n\n"; + continue; + } + 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; + } + std::cout << "\n\nDo you want to display another Invoice (1-Yes, 2-No): "; + util::read(choice); + if (choice == 1) + { + doRun = true; + util::clear(); + } + else if (choice == 2) + { + doRun = false; + } + else + { + std::cout << "Invalid choice\n"; + doRun = false; + } + } + else + { + std::cout << "Unable to fetch the selected invoice\n"; + doRun = false; + } + + } while (doRun); + } +} + +/* +Function: filterStartedJobCards +Description: Filters the given list of job cards and returns only those with status STARTED. +Parameters: + - assignedJobCards: Map of job card IDs to JobCard pointers. +Returns: + - util::Map containing only job cards with status STARTED. +*/ +inline util::Map filterStartedJobCards(util::Map& assignedJobCards) +{ + util::Map startedJobCards; + for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++) + { + const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator); + if (currentJobCard && currentJobCard->getStatus() == util::ServiceJobStatus::STARTED) + { + startedJobCards.insert(currentJobCard->getId(), currentJobCard); + } + } + return startedJobCards; +} + +/* +Function: displayAllJobs +Description: Displays all Jobs assigned to a Technician +Parameters: + - assignedJobCards: util::Map&, job cards assigned to the technician +Returns: + - std::string: ID of the selected job card, or empty string if none selected +*/ +inline void displayAllJobs(util::Map& assignedJobCards) +{ + if (assignedJobCards.getSize() == 0) + { + std::cout << "No active jobs assigned.\n"; + return; + } + std::cout << std::endl; + std::cout << std::left + << std::setw(12) << "BookingID" + << std::setw(12) << "JobID" + << std::setw(20) << "ServiceName" + << std::setw(12) << "ServiceID" + << std::endl; + for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++) + { + const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator); + if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED)) + { + std::cout << std::left << std::setw(12) << currentJobCard->getBookingId() + << std::setw(12) << currentJobCard->getId() + << std::setw(20) << currentJobCard->getService()->getName() + << std::setw(12) << currentJobCard->getServiceId() + << std::endl; + } + } +} + +/* +Function: selectJobCardToComplete +Description: Lists all incomplete job cards assigned to the technician and allows selection by index. +Parameters: + - assignedJobCards: util::Map&, job cards assigned to the technician +Returns: + - std::string: ID of the selected job card, or empty string if none selected +*/ +inline std::string selectJobCardToComplete(util::Map& assignedJobCards) +{ + util::Map incompleteJobCards; + if (assignedJobCards.getSize() == 0) + { + std::cout << "No started jobs available to complete.\n"; + return ""; + } + int currentIndex = 1; + int choice; + std::cout << std::endl; + std::cout << std::left + << std::setw(6) << "Index" + << std::setw(12) << "BookingID" + << std::setw(12) << "JobID" + << std::setw(20) << "ServiceName" + << std::setw(12) << "ServiceID" + << std::endl; + for (int iterator = 0; iterator < assignedJobCards.getSize(); iterator++) + { + const JobCard* currentJobCard = assignedJobCards.getValueAt(iterator); + if (currentJobCard && (currentJobCard->getStatus() == util::ServiceJobStatus::STARTED)) + { + std::cout << std::left << std::setw(6) << currentIndex + << std::setw(12) << currentJobCard->getBookingId() + << std::setw(12) << currentJobCard->getId() + << std::setw(20) << currentJobCard->getService()->getName() + << std::setw(12) << currentJobCard->getServiceId() + << std::endl; + incompleteJobCards.insert(currentIndex++, currentJobCard); + } + } + std::cout << "Select the Job Card to complete (Index): "; + util::read(choice); + int selectedJobCardIndex = incompleteJobCards.find(choice); + if (selectedJobCardIndex != -1) + { + const JobCard* selectedJobCard = incompleteJobCards.getValueAt(selectedJobCardIndex); + return selectedJobCard->getId(); + } + else + { + std::cout << "Invalid index.\n"; + std::cout << "Failed to complete jobs.\n\n"; + return ""; + } +} + +/* +Function: selectNotification +Description: Displays a list of notifications with index, ID, title, and timestamp. + Allows the user to select a notification by index. Returns the selected + notification or nullptr if the selection is invalid. +Parameter: const util::Vector& notifications - list of notifications +Return type: const Notification* - pointer to the selected notification +*/ +inline const Notification* selectNotification(const util::Vector& notifications) +{ + util::Map indexedNotifications; + std::cout << std::left + << std::setw(10) << "Index" + << std::setw(15) << "ID" + << std::setw(35) << "Title" + << std::setw(25) << "Timestamp" + << std::endl; + int currentIndex = 1; + for (int index = 0; index < notifications.getSize(); index++) + { + const Notification* currentNotification = notifications[index]; + if (currentNotification) + { + std::cout << std::left + << std::setw(10) << currentIndex + << std::setw(15) << currentNotification->getId() + << std::setw(35) << util::truncateString(currentNotification->getTitle(), 30) + << std::setw(25) << currentNotification->getCreatedAt().toString() + << std::endl; + indexedNotifications.insert(currentIndex, currentNotification); + currentIndex++; + } + } + int selectedIndex; + std::cout << "Select notification: "; + util::read(selectedIndex); + if (!indexedNotifications.containsKey(selectedIndex)) + { + std::cout << "Invalid index." << std::endl; + return nullptr; + } + return indexedNotifications[selectedIndex]; +} + +/* +Function: displayNotification +Description: Displays detailed information about a single notification, including ID, title, timestamp, and message. +Parameters: + - notification: Pointer to the Notification object to be displayed. +Returns: + - void +*/ +inline void displayNotification(const Notification* notification) +{ + util::clear(); + if (!notification) + { + std::cout << "Notification not found." << std::endl; + return; + } + std::cout << "Notification Details" << std::endl; + std::cout << "ID : " << notification->getId() << std::endl; + std::cout << "Title : " << notification->getTitle() << std::endl; + std::cout << "Timestamp : " << notification->getCreatedAt().toString() << std::endl; + std::cout << "Message : " << notification->getMessage() << std::endl; +} + +/* +Function: viewAndDeleteNotification +Description: Allows the user to view a notification and then delete it from the system using the controller. +Parameters: + - controller: Reference to the Controller object used to manage notifications. +Returns: + - void +*/ +inline void viewAndDeleteNotification(Controller& controller) +{ + util::clear(); + auto notifications = controller.getNotifications(); + std::cout << "View and Delete Notification" << std::endl; + if (notifications.getSize() == 0) + { + std::cout << "No notifications available." << std::endl; + util::pressEnter(); + return; + } + const Notification* selectedNotification = selectNotification(notifications); + if (!selectedNotification) + { + std::cout << "Failed to display notification!"; + util::pressEnter(); + return; + } + displayNotification(selectedNotification); + controller.deleteNotification(selectedNotification->getId()); + util::pressEnter(); +} + +/* +Function: changePassword +Description: Helper function to change password +Parameter: controller: Reference to the Controller object used to manage notifications. +Return type: void +*/ +inline void changePasswordHelper(Controller& controller) +{ + util::clear(); + const User* authenticatedUser = controller.getAuthenticatedUser(); + if (!authenticatedUser) + { + throw std::runtime_error("No user is currently logged in!"); + } + std::string newPassword, confirmedPassword; + while (true) + { + util::clear(); + std::cout << "Change Password\n"; + std::cout << "Enter new password: "; + util::read(newPassword); + if (!util::isPasswordValid(newPassword)) + { + std::cout << "Error: Password is not strong enough!\n"; + util::pressEnter(); + continue; + } + if (newPassword == authenticatedUser->getPassword()) + { + std::cout << "New password cannot be same as old password. Try again\n"; + util::pressEnter(); + continue; + } + std::cout << "Confirm new password: "; + util::read(confirmedPassword); + if (confirmedPassword != newPassword) + { + std::cout << "Passwords are different. Try again\n"; + util::pressEnter(); + continue; + } + controller.changePassword(newPassword); + std::cout << "Password changed successfully\n"; + util::pressEnter(); + break; + } +} + +/* +Function: filterActiveUsers +Description: Filters out inactive users and returns a map of active users. +Parameter: const util::Map& listOfUsers - all users +Return type: util::Map +*/ +inline util::Map filterActiveUsers(const util::Map& listOfUsers) +{ + util::Map activeUsers; + int inventorySize = listOfUsers.getSize(); + for (int index = 0; index < inventorySize; index++) + { + const User* user = listOfUsers.getValueAt(index); + if (user != nullptr && user->getState() != util::State::INACTIVE && user->getUserType() != util::UserType::ADMIN) + { + activeUsers.insert(user->getId(), user); + } + } + return activeUsers; +} + +/* +Function: displayAllUsers +Description: Displays all active users in a tabular format with index, ID, username, and type. +Parameter: util::Map& activeUsers - active users list +Return type: void +*/ +inline void displayAllUsers(util::Map& activeUsers) +{ + int activeUserCount = activeUsers.getSize(); + 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++) + { + const User* user = activeUsers.getValueAt(iterator); + if (user != nullptr) + { + 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; + } + else + { + std::cout << "No users found.\n"; + util::pressEnter(); + return; + } + } +} + +/* +Function: filterActiveServices +Description: Filters the given list of services and returns only those that are active. +Parameters: + - serviceList: Map of service IDs to Service pointers. +Returns: + - util::Map containing only active services. +*/ +inline util::Map filterActiveServices(util::Map& serviceList) +{ + util::Map activeServices; + for (int iterator = 0; iterator < serviceList.getSize(); iterator++) + { + const Service* currentService = serviceList.getValueAt(iterator); + if (currentService && currentService->getState() == util::State::ACTIVE) + { + activeServices.insert(currentService->getId(), currentService); + } + } + return activeServices; +} + +/* +Function: selectServiceFromServices +Description: Displays active services and allows the customer to select one by index. +Parameter: const util::Map& services - list of services +Return type: const Service* - selected service +*/ +inline const Service* selectServiceFromServices(const util::Map& services) +{ + if (services.getSize() == 0) + { + std::cout << "No active services available." << std::endl; + return nullptr; + } + std::cout << std::endl; + util::Map activeServicesMap; + int currentIndex = 1; + int userInputIndex; + std::cout << std::left + << std::setw(10) << "Index" + << std::setw(15) << "Service ID" + << std::setw(25) << "Service Name" + << std::setw(15) << "Estimated Cost" + << std::endl; + for (int index = 0; index < services.getSize(); index++) + { + const Service* currentService = services.getValueAt(index); + if (currentService == nullptr) + { + throw std::runtime_error("Warning: Encountered a null service\n"); + continue; + } + if (currentService->getState() != util::State::ACTIVE) + { + continue; + } + activeServicesMap.insert(currentIndex, currentService); + double partsCost = util::calculatePartsCost(currentService); + std::cout << std::left + << std::setw(10) << currentIndex + << std::setw(15) << currentService->getId() + << std::setw(25) << currentService->getName() + << std::setw(15) << (currentService->getLaborCost() + partsCost) + << std::endl; + currentIndex++; + } + if (activeServicesMap.getSize() == 0) + { + std::cout << "No active services available." << std::endl; + return nullptr; + } + std::cout << "Enter service index: "; + util::read(userInputIndex); + if (activeServicesMap.find(userInputIndex) == -1) + { + std::cout << "Invalid service index." << std::endl; + return nullptr; + } + return activeServicesMap[userInputIndex]; +} + +/* +Function: filterComboPackages +Description: + Filters the given list of combo packages and returns only those that are ACTIVE. +Parameters: + - comboPackages: util::Map& + Map of combo package IDs to ComboPackage pointers. +Returns: + - util::Map + Map containing only active combo packages. +*/ +inline util::Map filterComboPackages(util::Map& comboPackages) +{ + util::Map activeComboPackages; + for (int iterator = 0; iterator < comboPackages.getSize(); iterator++) + { + const ComboPackage* currentComboPackage = comboPackages.getValueAt(iterator); + if (currentComboPackage && currentComboPackage->getState() == util::State::ACTIVE) + { + activeComboPackages.insert(currentComboPackage->getId(), currentComboPackage); + } + } + return activeComboPackages; +} + +/* +Function: displayAllComboPackages +Description: Displays all active combo packages +Parameters: + - currentComboPackages: util::Map, available combo packages +Returns: + - void; +*/ +inline void displayAllComboPackages(util::Map comboPackages) +{ + std::cout << std::endl; + if (comboPackages.getSize() == 0) + { + std::cout << "No active combo packages available." << std::endl; + return; + } + std::cout << std::left + << std::setw(15) << "Combo ID" + << std::setw(35) << "Combo Name" + << std::setw(15) << "Estimate Cost" + << std::endl; + for (int index = 0; index < comboPackages.getSize(); index++) + { + const ComboPackage* currentComboPackage = comboPackages.getValueAt(index); + if (currentComboPackage && currentComboPackage->getState() != util::State::ACTIVE) + { + continue; + } + std::cout << std::left + << std::setw(15) << currentComboPackage->getId() + << std::setw(35) << util::truncateString(currentComboPackage->getPackageName(), 30) + << std::setw(15) << util::calculateComboServiceEstimatedCost(currentComboPackage) + << std::endl; + } +} + + +/* +Function: selectComboPackageFromPackages +Description: Displays active combo packages and allows the customer to select one by index. +Parameter: const util::Map& comboPackages - list of combo packages +Return type: const ComboPackage* - selected combo package +*/ +inline const ComboPackage* selectComboPackageFromPackages(const util::Map& comboPackages) +{ + util::Map activeComboPackages; + int currentIndex = 1; + int userInputIndex; + std::cout << std::endl; + std::cout << std::left + << std::setw(10) << "Index" + << std::setw(15) << "Combo ID" + << std::setw(35) << "Combo Name" + << std::setw(15) << "Estimate Cost" + << std::endl; + for (int index = 0; index < comboPackages.getSize(); index++) + { + const ComboPackage* currentComboPackage = comboPackages.getValueAt(index); + if (currentComboPackage && currentComboPackage->getState() != util::State::ACTIVE) + { + continue; + } + activeComboPackages.insert(currentIndex, currentComboPackage); + std::cout << std::left + << std::setw(10) << currentIndex + << std::setw(15) << currentComboPackage->getId() + << std::setw(35) << util::truncateString(currentComboPackage->getPackageName(), 30) + << std::setw(15) << util::calculateComboServiceEstimatedCost(currentComboPackage) + << std::endl; + currentIndex++; + } + if (activeComboPackages.getSize() == 0) + { + std::cout << "No active combo packages available." << std::endl; + return nullptr; + } + std::cout << "Enter combo package index: "; + util::read(userInputIndex); + if (activeComboPackages.find(userInputIndex) == -1) + { + std::cout << "Invalid combo package index." << std::endl; + return nullptr; + } + return activeComboPackages[userInputIndex]; +} + +/* +Function: getNotificationPreference +Description: Helper function to configure notification preferences for a specific service. +Parameters: + - serviceName: Name of the service for which notifications are being configured. +Returns: + - bool: True if notifications are enabled, False if disabled. +*/ +inline bool getNotificationPreference(const std::string& serviceName) +{ + int choice; + while (true) + { + util::clear(); + std::cout << "Configure Notification Preferences\n"; + std::cout << "\n" << serviceName << " Notifications\n"; + std::cout << "1. Enable Notifications\n"; + std::cout << "2. Disable Notifications\n"; + std::cout << "Enter your choice: "; + util::read(choice); + if (choice == 1) + { + return true; + } + if (choice == 2) + { + return false; + } + std::cout << "\nInvalid choice. Please enter 1 or 2.\n"; + util::pressEnter(); + } +} + +/* +Function: filterActiveItems +Description: Filters out inactive inventory items and returns a map + containing only active items. +Parameter: const util::Map& inventoryItems - + map of all inventory items +Return type: util::Map +*/ +inline util::Map filterActiveItems(const util::Map& inventoryItems) +{ + util::Map activeItems; + int inventorySize = inventoryItems.getSize(); + for (int index = 0; index < inventorySize; index++) + { + const InventoryItem* item = inventoryItems.getValueAt(index); + if (item && item->getState() != util::State::INACTIVE) + { + activeItems.insert(item->getId(), item); + } + } + return activeItems; +} + +/* +Function: displayInventoryWithItems +Description: Displays inventory items in a tabular format with index, ID, + part name, quantity, and price. +Parameter: util::Map& inventoryItems - + map of inventory items to display +Return type: void +*/ +inline void displayInventoryWithItems(util::Map& inventoryItems) +{ + int inventorySize = inventoryItems.getSize(); + std::cout << std::left << std::setw(10) << "Index" + << std::setw(15) << "Item ID" + << std::setw(25) << "Part Name" + << std::setw(10) << "Quantity" + << std::setw(10) << "Price" + << std::endl; + for (int iterator = 0; iterator < inventorySize; iterator++) + { + const InventoryItem* item = inventoryItems.getValueAt(iterator); + if (item != nullptr) + { + std::cout << std::left << std::setw(10) << (iterator + 1) + << std::setw(15) << item->getId() + << std::setw(25) << item->getPartName() + << std::setw(10) << item->getQuantity() + << std::setw(10) << item->getPrice() + << std::endl; + } + } + std::cout << std::endl; +} + +/* +Function: addQuantityToItem +Description: Allows the admin to select an active inventory item and + increase its stock quantity. +Parameter: util::Map& inventoryItems - + map of inventory items + Controller& m_controller - controller instance to update stock +Return type: void +*/ +inline void addQuantityToItem(util::Map& inventoryItems, Controller& m_controller) +{ + int itemIndex; + int quantity; + auto activeItems = filterActiveItems(inventoryItems); + int activeSize = activeItems.getSize(); + if (activeSize == 0) + { + std::cout << "\nNo active items available in Inventory" << std::endl << std::endl; + return; + } + displayInventoryWithItems(activeItems); + std::cout << "Enter the index of the item to update: "; + util::read(itemIndex); + if (itemIndex < 1 || itemIndex > activeSize) + { + std::cout << "\nInvalid index selected." << std::endl << std::endl; + return; + } + std::cout << "Enter quantity to add: "; + util::read(quantity); + if (quantity < 0) + { + std::cout << "The quantity should be Greater than 0." << std::endl; + return; + } + const InventoryItem* selectedItem = activeItems.getValueAt(itemIndex - 1); + if (selectedItem != nullptr) + { + std::string selectedItemId = selectedItem->getId(); + m_controller.addInventoryItemStock(selectedItemId, quantity); + std::cout << "\nUpdated " << selectedItem->getPartName() + << " stock. New quantity: " << selectedItem->getQuantity() + << std::endl + << std::endl; + } + else + { + std::cout << "\nError: Selected item could not be found." << std::endl << std::endl; + } +} + +/* +Function: displayComboPackagesWithIndex +Description: Displays combo packages with index, ID, name, and discount percentage. +Parameter: util::Map& currentComboPackageIndexMap - combo packages map +Return type: void +*/ +inline void displayComboPackagesWithIndex(util::Map& currentComboPackageIndexMap) +{ + for (int iterator = 0; iterator < currentComboPackageIndexMap.getSize(); iterator++) + { + const ComboPackage* currentComboPackage = currentComboPackageIndexMap.getValueAt(iterator); + if (currentComboPackage == nullptr) + { + 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(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(35) << util::truncateString(currentComboPackage->getPackageName(), 30) + << std::setw(15) << currentComboPackage->getDiscountPercentage() + << "\n"; + } +} + +/* +Function: selectComboPackage +Description: Allows the admin to select an active combo package by index. +Parameter: util::Map& currentComboPackages - combo packages list +Return type: std::string - ID of the selected combo package +*/ +inline std::string selectComboPackage(util::Map& currentComboPackages) +{ + util::Map currentComboPackageIndexMap; + if (currentComboPackages.getSize() == 0) + { + std::cout << "No combo packages are available.\n"; + return ""; + } + int currentIndex = 1, choice, selectedIndex; + for (int iterator = 0; iterator < currentComboPackages.getSize(); iterator++) + { + if (currentComboPackages.getValueAt(iterator)->getState() == util::State::INACTIVE) + { + continue; + } + currentComboPackageIndexMap.insert(currentIndex++, currentComboPackages.getValueAt(iterator)); + } + if (currentComboPackageIndexMap.getSize() == 0) + { + std::cout << "No combo packages currently active.\n"; + return ""; + } + displayComboPackagesWithIndex(currentComboPackageIndexMap); + std::cout << "Enter your choice(Index): "; + util::read(choice); + selectedIndex = currentComboPackageIndexMap.find(choice); + if (selectedIndex != -1) + { + std::string selectedComboPackageID = currentComboPackageIndexMap.getValueAt(selectedIndex)->getId(); + return selectedComboPackageID; + } + else + { + std::cout << "Enter a valid choice.\n"; + return ""; + } +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp index d6c4d57..9ee3402 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.cpp @@ -1,40 +1,165 @@ -#include "TechnicianMenu.h" -#include "InputHelper.h" -#include "OutputHelper.h" +/* +File: TechnicianMenu.cpp +Description: Implementation file containing the method definitions of the + TechnicianMenu class, including menu handling, job completion, + notification viewing, password management, and logout logic. +Author: Trenser +Date:19-May-2026 +*/ +#include "Enums.h" +#include "InputHelper.h" +#include "JobCard.h" +#include "MenuHelper.h" +#include "OutputHelper.h" +#include "Service.h" +#include "TechnicianMenu.h" +#include "Validator.h" + +/* +Function: showMenu +Description: Displays the technician menu in a loop until the user chooses to logout. + Handles exceptions and ensures smooth user interaction. +Parameters: + - None +Returns: + - void +*/ void TechnicianMenu::showMenu() { - bool isMenuActive = true; - while (isMenuActive) - { - try - { - int choice; - util::clear(); - std::cout << "" << std::endl; - util::read(choice); - if (!handleOperation(choice)) - { - isMenuActive = false; - } - } - catch (const std::exception& e) - { - std::cout << "Exception: " << e.what() << std::endl; - util::pressEnter(); - } - } + while (true) + { + try + { + int choice; + util::clear(); + std::cout << "Technician Menu" + << "\n1. Display My Jobs" + << "\n2. Mark Job as Completed" + << "\n3. View Notifications" + << "\n4. Change Password" + << "\n5. Logout" + << "\nEnter a choice: "; + util::read(choice); + if (!handleOperation(choice)) + { + break; + } + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << std::endl; + util::pressEnter(); + } + } } +/* +Function: handleOperation +Description: Executes the corresponding technician operation based on the selected menu choice. +Parameter: int choice - selected menu option +Return type: bool - true if menu continues, false if logout +*/ bool TechnicianMenu::handleOperation(int choice) { - return false; + switch (choice) + { + case 1: + displayJobs(); + break; + case 2: + completeJob(); + break; + case 3: + viewNotifications(); + break; + case 4: + changePassword(); + break; + case 5: + logout(); + return false; + default: + std::cout << "Enter a valid choice!" << std::endl; + util::pressEnter(); + } + return true; } +/* +Function: displayJobs +Description: Displays all Jobs assigned to a Technician +Parameters: + - None +Returns: + - void +*/ +void TechnicianMenu::displayJobs() +{ + util::clear(); + std::cout << "My Jobs\n"; + util::Map assignedJobCards = m_controller.getJobCardsByUser(); + util::Map startedJobCards = filterStartedJobCards(assignedJobCards); + displayAllJobs(startedJobCards); + util::pressEnter(); +} + +/* +Function: completeJob +Description: Allows the technician to mark a selected job card as completed. + Validates selection and updates job status through the controller. +Parameters: + - None +Returns: + - void +*/ void TechnicianMenu::completeJob() { + util::clear(); + std::cout << "Complete Job\n"; + util::Map assignedJobCards = m_controller.getJobCardsByUser(); + util::Map startedJobCards = filterStartedJobCards(assignedJobCards); + std::string selectedJobID = selectJobCardToComplete(startedJobCards); + if (!selectedJobID.empty()) + { + m_controller.completeJob(selectedJobID); + std::cout << "\nJob marked as completed.\n\n"; + } + util::pressEnter(); } +/* +Function: viewNotifications +Description: Displays notifications for the technician and allows deletion of notifications. +Parameters: + - None +Returns: + - void +*/ void TechnicianMenu::viewNotifications() { + viewAndDeleteNotification(m_controller); } + +/* +Function: logout +Description: Logs out the currently authenticated technician user. +Parameter: None +Return type: void +*/ +void TechnicianMenu::logout() +{ + m_controller.logout(); +} + +/* +Function: changePassword +Description: Allows the technician to change their password after validation. +Parameter: None +Return type: void +*/ + +void TechnicianMenu::changePassword() +{ + changePasswordHelper(m_controller); +} \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h index c366d9b..d0c5ca9 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/TechnicianMenu.h @@ -1,3 +1,12 @@ +/* +File: TechnicianMenu.h +Description: Header file declaring the TechnicianMenu class, which provides + technician operations such as job completion, notification viewing, + password management, and logout functionality. +Author: Trenser +Date:19-May-2026 +*/ + #pragma once #include "Controller.h" @@ -8,6 +17,9 @@ private: bool handleOperation(int choice); public: void showMenu(); + void displayJobs(); void completeJob(); void viewNotifications(); + void logout(); + void changePassword(); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp index 122f9a8..841e2ea 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp @@ -1,31 +1,76 @@ -#include "UserInterface.h" +/* +File: UserInterface.cpp +Description: Implementation file containing the method definitions of the + UserInterface class, including system run loop, login handling, + and customer registration logic. +Author: Trenser +Date:19-May-2026 +*/ + +#include +#include +#include "Enums.h" #include "InputHelper.h" #include "OutputHelper.h" +#include "User.h" +#include "UserInterface.h" +#include "Validator.h" +/* +Function: run +Description: Runs the main system loop, displaying the initial menu for login, + customer registration, or exit. Handles exceptions gracefully. +Parameter: None +Return type: void +*/ void UserInterface::run() { - bool isMenuActive = true; - while (isMenuActive) + try { - try + m_controller.loadSystemData(); + m_controller.runSystemChecks(); + bool isMenuActive = true; + while (isMenuActive) { - int choice; - util::clear(); - std::cout << "Vehicle Service System\n1. Login\n2. Register Customer\n3. Exit\nEnter your Choice: "; - util::read(choice); - if (!handleOperation(choice)) + try { - isMenuActive = false; + int choice; + util::clear(); + std::cout << "Vehicle Service System\n1. Login\n2. Register Customer\n3. Exit\nEnter your Choice: "; + util::read(choice); + if (!handleOperation(choice)) + { + isMenuActive = false; + } + } + catch (const std::exception& e) + { + std::cout << "Exception: " << e.what() << std::endl; + util::pressEnter(); } } - catch (const std::exception& e) - { - std::cout << "Exception: " << e.what() << std::endl; - util::pressEnter(); - } + 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; } } +/* +Function: handleOperation +Description: Executes the corresponding system operation based on the selected menu choice. +Parameter: int choice - selected menu option +Return type: bool - true if menu continues, false if exit +*/ bool UserInterface::handleOperation(int choice) { switch (choice) @@ -46,12 +91,98 @@ bool UserInterface::handleOperation(int choice) return true; } +/* +Function: login +Description: Handles user login by validating credentials. Based on the authenticated + user type, navigates to the appropriate menu (Admin, Technician, Customer). +Parameter: None +Return type: void +*/ void UserInterface::login() { - + std::string username, password; + util::clear(); + std::cout << "Login\n"; + std::cout << "Enter username: "; + util::read(username); + std::cout << "Enter password: "; + util::read(password); + if (m_controller.login(username, password)) + { + const User* authenticatedUser = m_controller.getAuthenticatedUser(); + if (authenticatedUser && authenticatedUser->getState() != util::State::INACTIVE) + { + switch (authenticatedUser->getUserType()) + { + case util::UserType::ADMIN: + m_adminMenu.showMenu(); + break; + case util::UserType::TECHNICIAN: + m_technicianMenu.showMenu(); + break; + case util::UserType::CUSTOMER: + m_customerMenu.showMenu(); + break; + default: + std::cout << "\nError: Unknown user type"; + break; + } + } + else if (authenticatedUser && authenticatedUser->getState() == util::State::INACTIVE) + { + std::cout << "\nError: Your account has been disabled. Please contact your Administrator."; + util::pressEnter(); + } + } + else + { + std::cout << "\nError: Invalid Username or Password"; + util::pressEnter(); + } } +/* +Function: registerCustomer +Description: Registers a new customer by collecting and validating details such as + username, name, email, password, and phone number. Delegates creation + to the controller. +Parameter: None +Return type: void +*/ void UserInterface::registerCustomer() { - + std::string username, name, email, phone, password; + util::clear(); + std::cout << "Register Customer\n"; + std::cout << "Enter username: "; + util::read(username); + std::cout << "Enter name: "; + util::read(name); + std::cout << "Enter email: "; + util::read(email); + if (!util::isEmailValid(email)) + { + std::cout << "Error: Email is invalid!"; + util::pressEnter(); + return; + } + std::cout << "Enter password: "; + util::read(password); + if (!util::isPasswordValid(password)) + { + std::cout << "Error: Password is invalid!"; + util::pressEnter(); + return; + } + std::cout << "Enter phone: "; + util::read(phone); + if (!util::isPhoneNumberValid(phone)) + { + std::cout << "Error: Phone number is invalid!"; + util::pressEnter(); + return; + } + m_controller.createCustomer(username, name, password, email, phone); + std::cout << "Registration is successful"; + util::pressEnter(); } diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.h index da3862e..501cfce 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.h @@ -1,3 +1,13 @@ +/* +File: UserInterface.h +Description: Header file declaring the UserInterface class, which provides + the main entry point for the Vehicle Service System. Handles + login, customer registration, and menu navigation for different + user roles (Admin, Technician, Customer). +Author: Trenser +Date:19-May-2026 +*/ + #pragma once #include "Controller.h" #include "AdminMenu.h"