Compare commits

..

5 Commits

Author SHA1 Message Date
joelthomastrenser 972e353832 Merged PR 1152: Vehicle Service System v1.0.0.0
Features Included:

Secure access and session management with role-based authentication
Customer and technician account management
Service booking and technician assignment
Service and combo package management
Job card tracking and completion workflow
Inventory management and stock monitoring
Invoice generation and payment processing
Notification management with configurable preferences
Observer pattern based alerts for inventory, payments, and service updates
2026-06-01 16:48:25 +05:30
joelthomastrenser c5ada405e6 Merged PR 1148: Vehicle Service System
**Features Included:**
- Secure access and session management with role-based authentication
- Customer and technician account management
- Service booking and technician assignment
- Service and combo package management
- Job card tracking and completion workflow
- Inventory management and stock monitoring
- Invoice generation and payment processing
- Notification management with configurable preferences
- Observer pattern based alerts for inventory, payments, and service updates

Related work items: #1551, #1552, #1553, #1560, #1561, #1563, #1564, #1568, #1569, #1570, #1571, #1572, #1573, #1574, #1575, #1576, #1577, #1578, #1579, #1580, #1581, #1582, #1583, #1584, #1585, #1586, #1587, #1588, #1592, #1593, #1594, #1595, #1596, #1597, #1598, #1599, #1600, #1601, #1624, #1626, #1646, #1648, #1649, #1655, #1656, #1668, #1669, #1672, #1673, #1679, #1680, #1708, #1709, #1736, #1737, #1738, #1739, #1740, #1741, #1742, #1743, #1744, #1745, #1746, #1747, #1748, #1749, #1750, #1751, #1752, #1753, #1754, #1777, #1778, #1779, #1780, #1781, #1782, #1783, #1784, #1786, #1788, #1789, #1793
2026-05-29 11:50:03 +05:30
joelthomastrenser d6b4310de6 Merged PR 1142: Add display menus for users, services, combo packages and jobs
Add display menus for users, services, combo packages and jobs

Changes:
- Added display options for users, services, combo packages and technician jobs
- Updated admin and technician menu options and navigation
- Added reusable helper functions for displaying data in tabular format
- Improved user and combo package listing displays
- Fixed minor validation and error message formatting issues
2026-05-28 16:39:37 +05:30
joelthomastrenser 451085e9c2 Add display menus for users, services, combo packages and jobs
Changes:
- Added display options for users, services, combo packages and technician jobs
- Updated admin and technician menu options and navigation
- Added reusable helper functions for displaying data in tabular format
- Improved user and combo package listing displays
- Fixed minor validation and error message formatting issues
2026-05-28 16:36:34 +05:30
joelthomastrenser 4657d3e8d1 Merged PR 1139: Fix: create missing directories before file creation
Fix: create missing directories before file creation

Changes:
- Added ensureDirectoryExists() helper using _mkdir()
- Automatically create missing directories before file operations
- Added FileHelper include in FileManager
- Removed placeholder files/README.md

Fixes #1793

Related work items: #1646, #1793
2026-05-28 10:35:54 +05:30
5 changed files with 235 additions and 31 deletions
@@ -42,15 +42,18 @@ void AdminMenu::showMenu()
<< "\n3. Remove Inventory Item" << "\n3. Remove Inventory Item"
<< "\n4. Check Stock Availability" << "\n4. Check Stock Availability"
<< "\n5. Assign Job to Technician" << "\n5. Assign Job to Technician"
<< "\n6. Add Technician" << "\n6. Display Users"
<< "\n7. Remove Customer/Technician" << "\n7. Add Technician"
<< "\n8. Create Service" << "\n8. Remove Customer/Technician"
<< "\n9. Remove Service" << "\n9. Display Services"
<< "\n10. Create Combo Package" << "\n10. Create Service"
<< "\n11. Remove Combo Package" << "\n11. Remove Service"
<< "\n12. View Notifications" << "\n12. Display Combo Packages"
<< "\n13. Change Password" << "\n13. Create Combo Package"
<< "\n14. Logout" << "\n14. Remove Combo Package"
<< "\n15. View Notifications"
<< "\n16. Change Password"
<< "\n17. Logout"
<< "\nEnter a choice: "; << "\nEnter a choice: ";
util::read(choice); util::read(choice);
if (!handleOperation(choice)) if (!handleOperation(choice))
@@ -92,30 +95,39 @@ bool AdminMenu::handleOperation(int choice)
assignJob(); assignJob();
break; break;
case 6: case 6:
addTechnician(); displayUsers();
break; break;
case 7: case 7:
removeUser(); addTechnician();
break; break;
case 8: case 8:
createService(); removeUser();
break; break;
case 9: case 9:
removeService(); displayServices();
break; break;
case 10: case 10:
createComboPackages(); createService();
break; break;
case 11: case 11:
removeComboPackage(); removeService();
break; break;
case 12: case 12:
viewNotifications(); displayComboPackages();
break; break;
case 13: case 13:
changePassword(); createComboPackages();
break; break;
case 14: case 14:
removeComboPackage();
break;
case 15:
viewNotifications();
break;
case 16:
changePassword();
break;
case 17:
logout(); logout();
return false; return false;
default: default:
@@ -383,6 +395,24 @@ void AdminMenu::assignJob()
util::pressEnter(); 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<std::string, const Service*> currentServices = m_controller.getServices();
util::Map<std::string, const Service*> currentActiveServices = filterActiveServices(currentServices);
displayAllServices(currentActiveServices);
util::pressEnter();
}
/* /*
Function: createService Function: createService
Description: Allows the admin to create a new service by selecting inventory items and specifying labor cost. Description: Allows the admin to create a new service by selecting inventory items and specifying labor cost.
@@ -443,6 +473,29 @@ void AdminMenu::removeService()
util::pressEnter(); 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 Function: addTechnician
Description: Adds a new technician after validating username, password, email, and phone number. Description: Adds a new technician after validating username, password, email, and phone number.
@@ -507,12 +560,12 @@ void AdminMenu::removeUser()
util::pressEnter(); util::pressEnter();
return; return;
} }
displayAllActiveUsers(listOfActiveUsers, activeUserCount); displayAllUsers(listOfActiveUsers);
std::cout << "Enter the index of the user to delete : "; std::cout << "Enter the index of the user to delete : ";
util::read(indexChoice); util::read(indexChoice);
if (indexChoice < 1 || indexChoice > activeUserCount) if (indexChoice < 1 || indexChoice > activeUserCount)
{ {
std::cout << "Error Invaild index.\n" << std::endl; std::cout << "Error invalid index.\n" << std::endl;
util::pressEnter(); util::pressEnter();
return; return;
} }
@@ -526,6 +579,24 @@ void AdminMenu::removeUser()
util::pressEnter(); 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<std::string, const ComboPackage*> currentComboPackages = m_controller.getComboPackages();
util::Map<std::string, const ComboPackage*> currentActiveComboPackages = filterComboPackages(currentComboPackages);
displayAllComboPackages(currentActiveComboPackages);
util::pressEnter();
}
/* /*
Function: createComboPackages Function: createComboPackages
Description: Creates a new combo package by selecting two active services and applying a discount. Description: Creates a new combo package by selecting two active services and applying a discount.
@@ -24,10 +24,13 @@ public:
void removeInventoryItem(); void removeInventoryItem();
void checkStockAvailability(); void checkStockAvailability();
void assignJob(); void assignJob();
void displayServices();
void createService(); void createService();
void removeService(); void removeService();
void displayUsers();
void addTechnician(); void addTechnician();
void removeUser(); void removeUser();
void displayComboPackages();
void createComboPackages(); void createComboPackages();
void removeComboPackage(); void removeComboPackage();
void viewNotifications(); void viewNotifications();
@@ -29,6 +29,41 @@ Date: 21-May-2026
#include "Validator.h" #include "Validator.h"
#include "Vector.h" #include "Vector.h"
/*
Function: displayAllServices
Description: Displays all active services
Parameters:
- currentServices: util::Map<std::string, const Service*>, available services
Returns:
- void;
*/
inline void displayAllServices(util::Map<std::string, const Service*> 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 Function: selectServicesToRemove
Description: Allows selection of a service to remove by index. Description: Allows selection of a service to remove by index.
@@ -619,12 +654,47 @@ inline util::Map<std::string, const JobCard*> filterStartedJobCards(util::Map<st
return startedJobCards; return startedJobCards;
} }
/*
Function: displayAllJobs
Description: Displays all Jobs assigned to a Technician
Parameters:
- assignedJobCards: util::Map<std::string, const JobCard*>&, 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<std::string, const JobCard*>& 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 Function: selectJobCardToComplete
Description: Lists all incomplete job cards assigned to the technician and allows selection by index. Description: Lists all incomplete job cards assigned to the technician and allows selection by index.
Parameters: Parameters:
- assignedJobCards: util::Map<std::string, const JobCard*>&, job cards assigned to the technician - assignedJobCards: util::Map<std::string, const JobCard*>&, job cards assigned to the technician
- incompleteJobCards: util::Map<int, const JobCard*>&, map of incomplete job cards indexed for selection
Returns: Returns:
- std::string: ID of the selected job card, or empty string if none selected - std::string: ID of the selected job card, or empty string if none selected
*/ */
@@ -844,14 +914,14 @@ inline util::Map<std::string, const User*> filterActiveUsers(const util::Map<std
} }
/* /*
Function: displayAllActiveUsers Function: displayAllUsers
Description: Displays all active users in a tabular format with index, ID, username, and type. Description: Displays all active users in a tabular format with index, ID, username, and type.
Parameter: util::Map<std::string, const User*>& activeUsers - active users list Parameter: util::Map<std::string, const User*>& activeUsers - active users list
int activeUserCount - number of active users
Return type: void Return type: void
*/ */
inline void displayAllActiveUsers(util::Map<std::string, const User*>& activeUsers, int activeUserCount) inline void displayAllUsers(util::Map<std::string, const User*>& activeUsers)
{ {
int activeUserCount = activeUsers.getSize();
std::cout << std::left << std::setw(10) << "Index" std::cout << std::left << std::setw(10) << "Index"
<< std::setw(15) << "User ID" << std::setw(15) << "User ID"
<< std::setw(25) << "Username" << std::setw(25) << "Username"
@@ -986,6 +1056,43 @@ inline util::Map<std::string, const ComboPackage*> filterComboPackages(util::Map
return activeComboPackages; return activeComboPackages;
} }
/*
Function: displayAllComboPackages
Description: Displays all active combo packages
Parameters:
- currentComboPackages: util::Map<std::string, const ComboPackage*>, available combo packages
Returns:
- void;
*/
inline void displayAllComboPackages(util::Map<std::string, const ComboPackage*> 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 Function: selectComboPackageFromPackages
Description: Displays active combo packages and allows the customer to select one by index. Description: Displays active combo packages and allows the customer to select one by index.
@@ -1007,7 +1114,7 @@ inline const ComboPackage* selectComboPackageFromPackages(const util::Map<std::s
for (int index = 0; index < comboPackages.getSize(); index++) for (int index = 0; index < comboPackages.getSize(); index++)
{ {
const ComboPackage* currentComboPackage = comboPackages.getValueAt(index); const ComboPackage* currentComboPackage = comboPackages.getValueAt(index);
if (currentComboPackage->getState() != util::State::ACTIVE) if (currentComboPackage && currentComboPackage->getState() != util::State::ACTIVE)
{ {
continue; continue;
} }
@@ -34,10 +34,11 @@ void TechnicianMenu::showMenu()
int choice; int choice;
util::clear(); util::clear();
std::cout << "Technician Menu" std::cout << "Technician Menu"
<< "\n1. Mark Job as Completed" << "\n1. Display My Jobs"
<< "\n2. View Notifications" << "\n2. Mark Job as Completed"
<< "\n3. Change Password" << "\n3. View Notifications"
<< "\n4. Logout" << "\n4. Change Password"
<< "\n5. Logout"
<< "\nEnter a choice: "; << "\nEnter a choice: ";
util::read(choice); util::read(choice);
if (!handleOperation(choice)) if (!handleOperation(choice))
@@ -64,15 +65,18 @@ bool TechnicianMenu::handleOperation(int choice)
switch (choice) switch (choice)
{ {
case 1: case 1:
completeJob(); displayJobs();
break; break;
case 2: case 2:
viewNotifications(); completeJob();
break; break;
case 3: case 3:
changePassword(); viewNotifications();
break; break;
case 4: case 4:
changePassword();
break;
case 5:
logout(); logout();
return false; return false;
default: default:
@@ -82,6 +86,24 @@ bool TechnicianMenu::handleOperation(int choice)
return true; 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<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
util::Map<std::string, const JobCard*> startedJobCards = filterStartedJobCards(assignedJobCards);
displayAllJobs(startedJobCards);
util::pressEnter();
}
/* /*
Function: completeJob Function: completeJob
Description: Allows the technician to mark a selected job card as completed. Description: Allows the technician to mark a selected job card as completed.
@@ -17,6 +17,7 @@ private:
bool handleOperation(int choice); bool handleOperation(int choice);
public: public:
void showMenu(); void showMenu();
void displayJobs();
void completeJob(); void completeJob();
void viewNotifications(); void viewNotifications();
void logout(); void logout();