Compare commits

..

16 Commits

Author SHA1 Message Date
Avinash Rajesh 34cb64ab1b Add standardized documentation headers 2026-05-22 13:26:02 +05:30
joelthomastrenser 826919579c Merge branch 'feature-customer-management-menu' into feature-customer-management 2026-05-21 13:22:08 +05:30
joelthomastrenser 5e3b65fc5b Merge branch 'feature-customer-management-cus007' into feature-customer-management 2026-05-21 13:20:46 +05:30
joelthomastrenser ab2d41a942 Merge branch 'feature-customer-management-cus006' into feature-customer-management 2026-05-21 13:18:15 +05:30
joelthomastrenser de5311f9f9 Merge branch 'feature-customer-management-cus005' into feature-customer-management 2026-05-21 13:17:03 +05:30
joelthomastrenser 7ef7f02ee4 Merge branch 'feature-customer-management-cus004' into feature-customer-management 2026-05-21 13:12:47 +05:30
joelthomastrenser 5075b383d4 Merge branch 'feature-customer-management-cus003' into feature-customer-management 2026-05-21 13:07:58 +05:30
joelthomastrenser 448cb016a3 Merge branch 'feature-customer-management-cus002' into feature-customer-management 2026-05-21 13:04:35 +05:30
joelthomastrenser df39c0588b Implement Login functionality
<UserStory> CUS001:Login </UserStory>

<Changes>
    1. Added login implementation in AuthenticationManagementService to validate username and password from stored user records.
    2. Connected Controller::login() with AuthenticationManagementService login logic.
    3. Added getAuthenticatedUser() integration in Controller for retrieving the logged-in user.
    4. Implemented login flow in UserInterface to collect credentials and validate login.
    5. Added role-based menu navigation for Admin, Technician, and Customer after successful login.
    6. Added error handling to display "Invalid Username or Password" for failed login attempts.
    7. Added required includes and controller member dependency for authentication support.
    8. Added a check to create a default admin automatically if no admin exists in the system on startup
</Changes>

<Test>

Login functionality validation

Precondition:
1. System is running.
2. User records are available in the data store.
3. Valid username and password exist for a registered user.

Steps:
1. Launch the application.
2. Select the login option from the main menu.
3. Enter a valid username and password.
   - Verify that the entered credentials are validated.
   - Verify that access is granted and the correct menu is shown based on user type.
4. Enter an invalid username or password.
   - Verify that the message "Invalid Username or Password" is displayed.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-21 11:26:48 +05:30
joelthomastrenser be306781b1 Implement Customer Menu
* Added Customer Menu display with all customer options
* Added menu choice handling using switch case
* Connected menu options to corresponding customer functions
* Added invalid choice message
* Added logout option handling
2026-05-21 10:44:42 +05:30
joelthomastrenser 9533a74d87 Implement Create Customer functionality
<UserStory> CUS004: Register Customer Account </UserStory>

<Changes>
    1. Added customer registration flow in UserInterface to collect username, name, email, password, and phone inputs.
    2. Added validation for email, password, and phone number before proceeding with registration.
    3. Updated Controller::createCustomer() and UserManagementService::createUser() to support customer registration with full user details including name.
    4. Added duplicate username validation in UserManagementService using map predicate search.
    5. Added user creation and insertion logic in UserManagementService to store newly registered customer records in DataStore.
    6. Added observer attachment for newly registered users to inventory(only for admins), payment, and service notification services.
    7. Added registration confirmation message display after successful customer creation.
</Changes>

<Test>

  Precondition:
  1. Application is running and user is on the main login/register menu.
  2. DataStore is initialized and available for storing user records.
  3. Existing customer records may already be present in the system.

  Steps:
  1. Select the Register Customer option.
  2. Enter valid username, name, email, password, and phone number.
  3. Submit the registration request.
     - Verify that the system accepts valid inputs and creates the customer account.
  4. Attempt registration using an already existing username.
     - Verify that the duplicate registration is rejected.
  5. Register again with valid unique details.
     - Verify that the registration confirmation message is displayed.
  6. Re-access application data after registration.
     - Verify that the customer data is stored persistently.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-20 17:45:02 +05:30
joelthomastrenser 183a06cd2f Implement Purchase Combo functionality
<UserStory> CUS007: Purchase Combo Package </UserStory>

<Changes>
    1. Added combo package selection flow in CustomerMenu to list all active combo packages with estimated cost and allow customer selection.
    2. Implemented Controller::purchaseComboPackage to delegate combo package booking requests to ServiceManagementService.
    3. Added ServiceManagementService::purchaseComboPackage logic to validate authenticated user, fetch selected combo package, create a ServiceBooking, persist it in DataStore, and send booking confirmation notification.
    4. Added helper functions in CustomerMenu to calculate combo package estimated cost based on included services and required inventory items.
    5. Updated ServiceBooking model to use User* reference for assigned technician and simplified constructor to align booking model with object references.

</Changes>

<Test>

  Precondition:
  1. Customer account exists and is logged into the system.
  2. Active combo packages are available in the system.
  3. Combo package contains one or more active services.
  4. Service bookings and notifications can be created successfully.

  Steps:
  1. Navigate to Customer Menu and select the combo package booking option.
  2. View the list of available combo packages.
    - Verify that all active combo packages are displayed with their details.
  3. Select one combo package and enter vehicle number, vehicle brand, and vehicle model.
    - Verify that a booking request is generated successfully.
  4. Complete the booking flow.
    - Verify that a confirmation message is displayed to the customer.
  5. Check customer notifications.
    - Verify that a booking confirmation notification is received.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-20 13:56:42 +05:30
joelthomastrenser 76f13b526e Implement Purchase Individual Service functionality
<UserStory> CUS006 Purchase Individual Service </UserStory>

<Changes>
    1. Added service selection flow in CustomerMenu to display active services, allow customer to choose a service, and collect vehicle details for booking.
    2. Implemented Controller::purchaseService to delegate service booking requests to ServiceManagementService.
    3. Added ServiceManagementService::purchaseService logic to validate authenticated user, fetch selected services, create a ServiceBooking, and persist it in DataStore.
    4. Updated ServiceBooking constructor and assigned technician handling to use User* references instead of technician name strings.
    5. Integrated ServiceManagementService dependency into Controller
</Changes>

<Test>

 Validate customer service booking flow and service status tracking

  Precondition:
  1. Customer account exists and is logged into the system.
  2. Active services are available in the system.
  3. Service bookings can be created and stored in DataStore.
  4. Technician account exists to update service status.

  Steps:
  1. Navigate to Customer Menu and select the individual service booking option.
  2. View the list of active services and select a service.
  3. Enter vehicle number, vehicle brand, and vehicle model, then confirm booking.
    - Verify that the service booking is created successfully with an initial status.
  4. Technician updates the service booking status.
    - Verify that the latest status is reflected in the system.
  5. Customer refreshes or views service booking history.
    - Verify that the updated status is shown correctly in booking history.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-20 13:51:36 +05:30
joelthomastrenser 9c2663db74 Implement Update Customer Profile Details
<UserStory> CUS005: Update Customer Profile Details </UserStory>

<Changes>
    1. Added update profile flow in CustomerMenu to collect new email and phone number inputs.
    2. Added validation for updated email and phone number before saving changes.
    3. Updated Controller::updateUserDetails() to fetch the authenticated user and delegate profile update to UserManagementService.
    4. Added user existence validation in UserManagementService before updating profile details.
    5. Added logic in UserManagementService to update stored email and phone details for the selected user.
    6. Added profile update confirmation message after successful save.
</Changes>

<Test>

 Update Customer Profile Details

  Precondition:
  1. Application is running and a customer is logged into the system.
  2. Customer record exists in DataStore.
  3. Customer has existing profile details stored in the system.

  Steps:
  1. Select the Update Profile Details option.
  2. Verify that the current profile details are displayed.
     - Verify that the system shows the customer’s existing details.
  3. Enter a new valid email address and phone number.
  4. Save the updated details.
     - Verify that the system accepts the changes and displays a success message.
  5. Create or view a future booking using the same customer account.
     - Verify that the updated profile details are reflected in future bookings.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-19 20:51:34 +05:30
joelthomastrenser cc887b9bc0 Implement Change Password
<UserStory> CUS003: Implement change password functionality </UserStory>

<Changes>
    1. Connected Controller::changePassword() with AuthenticationManagementService password update logic.
    2. Added password validation before updating the user password.
    3. Added logged-in user check before allowing password changes.
    4. Implemented password update logic in AuthenticationManagementService.
    5. Added change password flow in CustomerMenu to collect new password input and trigger password update.
    6. Added success message display after password is changed successfully.
</Changes>

<Test>

Change password functionality validation

Precondition:
1. System is running.
2. A registered user exists in the data store.
3. User is logged in and customer menu is active.

Steps:
1. Launch the application and log in with valid credentials.
2. Select the Change Password option from the customer menu.
3. Enter a new password.
   - Verify that the entered password is validated.
4. If the password is valid, complete the password change.
   - Verify that the new password is saved successfully.
   - Verify that the message "Password changed successfully" is displayed.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-19 19:43:33 +05:30
joelthomastrenser 5c5a44876b Implement Logout functionality
<UserStory> CUS002: Logout</UserStory>

<Changes>
    1. Connected Controller::logout() with AuthenticationManagementService logout logic.
    2. Added logout implementation in AuthenticationManagementService to clear the authenticated user session.
    3. Added logout handling in CustomerMenu to invoke controller logout when the user selects the logout option.
    4. Added authentication service dependency in Controller for logout support.
</Changes>

<Test>

Logout functionality validation

Precondition:
1. System is running.
2. A registered user exists in the data store.
3. User is logged in and customer menu is active.

Steps:
1. Launch the application and log in with valid credentials.
   - Verify that access is granted and customer menu is displayed.
2. Select the Logout option from the customer menu.
   - Verify that the logout operation is triggered immediately.
3. Complete the logout operation.
   - Verify that the authenticated user session is cleared.
4. After logout completes.
   - Verify that the user is redirected to the login menu.

</Test>

<Review>
Sreeja Reghukumar, please review
</Review>
2026-05-19 19:42:43 +05:30
23 changed files with 1165 additions and 1021 deletions
@@ -171,15 +171,18 @@
<ClInclude Include="services\PaymentManagementService.h" />
<ClInclude Include="services\ServiceManagementService.h" />
<ClInclude Include="services\UserManagementService.h" />
<ClInclude Include="utilities\Config.h" />
<ClInclude Include="utilities\Enums.h" />
<ClInclude Include="utilities\InputHelper.h" />
<ClInclude Include="utilities\Map.h" />
<ClInclude Include="utilities\OutputHelper.h" />
<ClInclude Include="utilities\Timestamp.h" />
<ClInclude Include="utilities\Utility.h" />
<ClInclude Include="utilities\Validator.h" />
<ClInclude Include="utilities\Vector.h" />
<ClInclude Include="views\AdminMenu.h" />
<ClInclude Include="views\CustomerMenu.h" />
<ClInclude Include="views\MenuHelper.h" />
<ClInclude Include="views\TechnicianMenu.h" />
<ClInclude Include="views\UserInterface.h" />
</ItemGroup>
@@ -1,56 +1,100 @@
/*
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 <stdexcept>
#include "Controller.h"
#include "InventoryItem.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "JobCard.h"
#include "Enums.h"
#include "User.h"
/*
Function: login
Description: Authenticates a user by delegating to the authentication management service.
Parameter: const std::string& username - users username
const std::string& password - users 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 - customers username
const std::string& name - customers name
const std::string& password - customers password
const std::string& email - customers email
const std::string& phone - customers 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: 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<std::string, const Service*> containing all services
*/
util::Map<std::string, const Service*> Controller::getServices()
{
util::Map<std::string, Service*> currentServices = m_serviceManagementService.getServices();
util::Map<std::string, const Service*> readOnlyServices;
for (int iterator = 0; iterator < currentServices.getSize(); iterator++)
{
readOnlyServices.insert(currentServices.getValueAt(iterator)->getId(), currentServices.getValueAt(iterator));
}
return readOnlyServices;
return util::Map<std::string, const Service*>();
}
util::Map<std::string, const ComboPackage*> Controller::getComboPackages()
@@ -58,18 +102,37 @@ util::Map<std::string, const ComboPackage*> Controller::getComboPackages()
return util::Map<std::string, const ComboPackage*>();
}
/*
Function: purchaseService
Description: Purchases one or more services for a vehicle by delegating to the service management service.
Parameter: const util::Vector<std::string>& 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<std::string>& 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);
}
util::Map<std::string, const InventoryItem*> Controller::getInventoryItems()
{
util::Map<std::string, const InventoryItem*> dummyMap;
return dummyMap;
return util::Map<std::string, const InventoryItem*>();
}
const InventoryItem* Controller::getInventoryItem(const std::string& inventoryItemID)
@@ -85,42 +148,14 @@ void Controller::removeInventoryItem(const std::string& inventoryItemID)
{
}
/*
Function: getServiceBookings
Description: Retrieves all service bookings in read-only form.
Parameters:
- None
Returns:
- util::Map<std::string, const ServiceBooking*> containing service bookings
*/
util::Map<std::string, const ServiceBooking*> Controller::getServiceBookings()
{
auto serviceBookings = m_serviceManagementService.getServiceBookings();
util::Map<std::string, const ServiceBooking*> readOnlyServiceBookings;
for (int iterator = 0; iterator < serviceBookings.getSize(); iterator++)
{
readOnlyServiceBookings.insert(serviceBookings.getKeyAt(iterator), serviceBookings.getValueAt(iterator));
}
return readOnlyServiceBookings;
return util::Map<std::string, const ServiceBooking*>();
}
/*
Function: getServiceBookingsByUser
Description: Retrieves all service bookings for a specific user.
Parameters:
- userID: std::string, the user ID
Returns:
- util::Map<std::string, const ServiceBooking*> containing bookings for the user
*/
util::Map<std::string, const ServiceBooking*> Controller::getServiceBookingsByUser(const std::string userID)
{
util::Map<std::string, const ServiceBooking*> readOnlyServiceBookingsByUserMap;
util::Map<std::string, ServiceBooking*> currentServiceBookingsByUser = m_serviceManagementService.getServiceBookings(userID);
for (int iterator = 0; iterator < currentServiceBookingsByUser.getSize(); iterator++)
{
readOnlyServiceBookingsByUserMap.insert(currentServiceBookingsByUser.getValueAt(iterator)->getId(), currentServiceBookingsByUser.getValueAt(iterator));
}
return readOnlyServiceBookingsByUserMap;
return util::Map<std::string, const ServiceBooking*>();
}
util::Map<std::string, const User*> Controller::getUsers()
@@ -128,100 +163,30 @@ util::Map<std::string, const User*> Controller::getUsers()
return util::Map<std::string, const User*>();
}
/*
Function: getUsers
Description: Retrieves users filtered by user type.
Parameters:
- userType: util::UserType, type of user (CUSTOMER, TECHNICIAN, ADMIN)
Returns:
- util::Map<std::string, const User*> containing users of the specified type
*/
util::Map<std::string, const User*> Controller::getUsers(util::UserType userType)
{
auto userMap = m_userManagementService.getUsers(userType);
util::Map<std::string, const User*> readOnlyUserMap;
for (int iterator = 0; iterator < userMap.getSize(); iterator++)
{
readOnlyUserMap.insert(userMap.getKeyAt(iterator), userMap.getValueAt(iterator));
}
return readOnlyUserMap;
return util::Map<std::string, const User*>();
}
/*
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<std::string>& 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<std::string, const JobCard*> containing job cards
*/
util::Map<std::string, const JobCard*> Controller::getJobCardsByUser()
{
const User* currentUser = getAuthenticatedUser();
auto jobCardsAssignedToTechnician = m_serviceManagementService.getJobCards(currentUser->getId());
util::Map<std::string, const JobCard*> readOnlyJobCardMap;
for (int iterator = 0; iterator < jobCardsAssignedToTechnician.getSize(); iterator++)
{
JobCard* currentJobCard = jobCardsAssignedToTechnician.getValueAt(iterator);
readOnlyJobCardMap.insert(currentJobCard->getId(), currentJobCard);
}
return readOnlyJobCardMap;
return util::Map<std::string, const JobCard*>();
}
/*
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);
}
void Controller::removeUser(const std::string& userID)
@@ -258,7 +223,14 @@ void Controller::configureNotifications(const std::string& userID, bool paymentN
{
}
/*
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();
}
@@ -1,10 +1,18 @@
/*
File: Controller.h
Description: Header file declaring the Controller class, which coordinates
authentication, user management, service management, inventory,
and notifications across the Vehicle Service System.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include "Map.h"
#include <string>
#include "Enums.h"
#include "ServiceManagementService.h"
#include "AuthenticationManagementService.h"
#include "UserManagementService.h"
#include "InventoryManagementService.h"
#include "ServiceManagementService.h"
class Service;
class ComboPackage;
@@ -18,13 +26,14 @@ class Notification;
class Controller
{
private:
ServiceManagementService m_serviceManagementService;
AuthenticationManagementService m_authenticationManagementService;
UserManagementService m_userManagementService;
ServiceManagementService m_serviceManagementService;
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 updateUserDetails(const std::string& email, const std::string& phone);
@@ -7,7 +7,7 @@ JobCard::JobCard()
m_booking(nullptr),
m_service(nullptr),
m_technician(nullptr),
m_status(util::ServiceJobStatus()) {}
m_status(ServiceJobStatus()) {}
JobCard::JobCard(const std::string& bookingId,
ServiceBooking* booking,
@@ -16,7 +16,7 @@ JobCard::JobCard(const std::string& bookingId,
const std::string& technicianId,
User* technician,
const util::Timestamp& assignedDate,
util::ServiceJobStatus status,
ServiceJobStatus status,
const util::Timestamp& completionDate
)
: m_id("JC" + std::to_string(++m_uid)),
@@ -70,7 +70,7 @@ const util::Timestamp& JobCard::getAssignedDate() const
return m_assignedDate;
}
util::ServiceJobStatus JobCard::getStatus() const
ServiceJobStatus JobCard::getStatus() const
{
return m_status;
}
@@ -120,7 +120,7 @@ void JobCard::setAssignedDate(const util::Timestamp& assignedDate)
m_assignedDate = assignedDate;
}
void JobCard::setStatus(util::ServiceJobStatus status)
void JobCard::setStatus(ServiceJobStatus status)
{
m_status = status;
}
@@ -1,12 +1,13 @@
#pragma once
#include <string>
#include "Timestamp.h"
#include "Enums.h"
class ServiceBooking;
class Service;
class User;
enum class ServiceJobStatus : int;
class JobCard
{
private:
@@ -19,7 +20,7 @@ private:
std::string m_technicianId;
User* m_technician;
util::Timestamp m_assignedDate;
util::ServiceJobStatus m_status;
ServiceJobStatus m_status;
util::Timestamp m_completionDate;
public:
@@ -31,7 +32,7 @@ public:
const std::string& technicianId,
User* technician,
const util::Timestamp& assignedDate,
util::ServiceJobStatus status,
ServiceJobStatus status,
const util::Timestamp& completionDate
);
const std::string& getId() const;
@@ -42,7 +43,7 @@ public:
const std::string& getTechnicianId() const;
User* getTechnician() const;
const util::Timestamp& getAssignedDate() const;
util::ServiceJobStatus getStatus() const;
ServiceJobStatus getStatus() const;
const util::Timestamp& getCompletionDate() const;
void setId(const std::string& id);
void setBookingId(const std::string& bookingId);
@@ -52,6 +53,6 @@ public:
void setTechnicianId(const std::string& technicianId);
void setTechnician(User* technician);
void setAssignedDate(const util::Timestamp& assignedDate);
void setStatus(util::ServiceJobStatus status);
void setStatus(ServiceJobStatus status);
void setCompletionDate(const util::Timestamp& completionDate);
};
@@ -1,14 +1,43 @@
/*
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 "ServiceBooking.h"
int ServiceBooking::m_uid = 0;
/*
Function: ServiceBooking
Description: Default constructor that initializes a new service booking
with a unique ID, no customer or technician, and zero discount.
Parameter: None
Return type: Constructor
*/
ServiceBooking::ServiceBooking()
: m_id("SRV" + std::to_string(++m_uid)),
m_customer(nullptr),
m_assignedTechnician(nullptr),
m_discountPercentage(0.0) {}
/*
Function: ServiceBooking
Description: Parameterized constructor that initializes a service booking
with customer, vehicle, services, and discount details.
Parameter: util::ServiceJobStatus status - current booking status
const util::Map<std::string, Service*>& services - map of services
const std::string& customerId - ID of the customer
User* customer - pointer to the customer object
const std::string& vehicleNumber - vehicle registration number
const std::string& vehicleBrand - brand of the vehicle
const std::string& vehicleModel - model of the vehicle
double discountPercentage - discount applied to the booking
Return type: Constructor
*/
ServiceBooking::ServiceBooking(
const std::string& id,
util::ServiceJobStatus status,
const util::Map<std::string,
Service*>& services,
@@ -17,8 +46,6 @@ ServiceBooking::ServiceBooking(
const std::string& vehicleNumber,
const std::string& vehicleBrand,
const std::string& vehicleModel,
const std::string& assignedTechnicianId,
const User* assignedTechnician,
double discountPercentage
)
: m_id("SRV" + std::to_string(++m_uid)),
@@ -29,117 +56,248 @@ 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)
{
}
/*
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: getServices
Description: Retrieves the services associated with the booking.
Parameter: None
Return type: const util::Map<std::string, Service*>&
*/
const util::Map<std::string, Service*>& 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 User* 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<std::string, Service*>& services - new services map
Return type: void
*/
void ServiceBooking::setServices(const util::Map<std::string, Service*>& services)
{
m_services = services;
}
/*
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 User* 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;
@@ -1,3 +1,11 @@
/*
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 <string>
#include "Map.h"
@@ -19,12 +27,11 @@ private:
std::string m_vehicleBrand;
std::string m_vehicleModel;
std::string m_assignedTechnicianId;
const User* m_assignedTechnician;
User* m_assignedTechnician;
double m_discountPercentage;
public:
ServiceBooking();
ServiceBooking(
const std::string& id,
util::ServiceJobStatus status,
const util::Map<std::string,
Service*>& services,
@@ -33,8 +40,6 @@ public:
const std::string& vehicleNumber,
const std::string& vehicleBrand,
const std::string& vehicleModel,
const std::string& assignedTechnicianId,
const User* assignedTechnician,
double discountPercentage
);
const std::string& getId() const;
@@ -46,7 +51,7 @@ public:
const std::string& getVehicleBrand() const;
const std::string& getVehicleModel() const;
const std::string& getAssignedTechnicianId() const;
const User* getAssignedTechnician() const;
User* getAssignedTechnician() const;
double getDiscountPercentage() const;
void setId(const std::string& id);
void setStatus(const util::ServiceJobStatus& status);
@@ -57,6 +62,6 @@ public:
void setVehicleBrand(const std::string& vehicleBrand);
void setVehicleModel(const std::string& vehicleModel);
void setAssignedTechnicianId(const std::string& assignedTechnicianId);
void setAssignedTechnician(const User* assignedTechnician);
void setAssignedTechnician(User* assignedTechnician);
void setDiscountPercentage(double discountPercentage);
};
@@ -1,3 +1,81 @@
/*
File: AuthenticationManagementService.cpp
Description: Implementation file containing the method definitions of the
AuthenticationManagementService class, including login, logout,
password change, and retrieval of the authenticated user.
Author: Trenser
Date:19-May-2026
*/
#include <stdexcept>
#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 - users username
const std::string& password - users password
Return type: bool - true if login successful, false otherwise
*/
bool AuthenticationManagementService::login(const std::string& username, const std::string& password)
{
util::Map<std::string, User*> 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);
}
@@ -1,3 +1,11 @@
/*
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 <string>
#include "DataStore.h"
@@ -1,324 +1,98 @@
/*
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 <stdexcept>
#include "ServiceManagementService.h"
#include "UserManagementService.h"
#include "ServiceBooking.h"
#include "Factory.h"
#include "JobCard.h"
#include "Timestamp.h"
#include "Service.h"
#include "Enums.h"
#include "InventoryItem.h"
#include "AuthenticationManagementService.h"
#include "PaymentManagementService.h"
#include "NotificationManagementService.h"
#include "User.h"
#include "Service.h"
#include "ServiceBooking.h"
#include "ComboPackage.h"
#include "Factory.h"
/*
Function: getServiceBookings
Description: Retrieves all service bookings from the datastore.
Parameters:
- None
Returns:
- util::Map<std::string, ServiceBooking*> containing all service bookings
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<std::string>& 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
*/
util::Map<std::string, ServiceBooking*> ServiceManagementService::getServiceBookings()
void ServiceManagementService::purchaseService(const util::Vector<std::string>& serviceIDs, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel)
{
return m_dataStore.getServiceBookings();
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<std::string, Service*> 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<ServiceBooking>(util::ServiceJobStatus::STARTED, selectedServices, authenticatedUser->getId(), authenticatedUser, vehicleNumber, vehicleBrand, vehicleModel, 0);
if (serviceBooking == nullptr)
{
throw std::runtime_error("Failed to create service booking");
}
serviceBookingMap[serviceBooking->getId()] = serviceBooking;
sendNotification(authenticatedUser,
"Service Booking succeeded",
"Your service booking has been successfully placed with ID " + serviceBooking->getId());
}
/*
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
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
*/
ServiceBooking* ServiceManagementService::getServiceBooking(const std::string& serviceID)
void ServiceManagementService::purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel)
{
auto currentServiceBookings = getServiceBookings();
for (int iterator = 0; iterator < currentServiceBookings.getSize(); iterator++)
AuthenticationManagementService m_authenticationManagementService;
auto authenticatedUser = m_authenticationManagementService.getAuthenticatedUser();
if (authenticatedUser == nullptr)
{
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->getQuantity() == 0)
{
std::string errorMessage = "Failed to create job card, " + currentInventoryItem->getPartName() + " is out of stock.";
throw std::runtime_error(errorMessage);
}
else
{
int currentStockQuantity = currentInventoryItem->getQuantity();
currentInventoryItem->setQuantity(currentStockQuantity - 1);
}
}
currentBooking->setAssignedTechnician(selectedTechnician);
currentBooking->setAssignedTechnicianId(selectedTechnician->getId());
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<JobCard>(bookingID, currentBooking, currentService, serviceID, technicianID, selectedTechnician, util::Timestamp(), util::ServiceJobStatus::STARTED, util::Timestamp());
currentJobCards.insert(jobCard->getId(), jobCard);
sendNotification(selectedTechnician,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<std::string>, 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<std::string>& inventoryItemIDs, double laborCost)
{
util::Map<std::string, InventoryItem*> 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<Service>(name, currentServiceInventoryItems, laborCost);
if (newService == nullptr)
{
throw std::runtime_error("Unable to create new service.");
}
util::Map<std::string, Service*>& 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<std::string, Service*> containing all services
*/
util::Map<std::string, Service*> 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<std::string, Service*> currentServices = getServices();
if (currentServices.find(serviceID) != -1)
{
currentServices.getValueAt(currentServices.find(serviceID))->setState(util::State::INACTIVE);
}
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<std::string, ServiceBooking*> containing bookings for the customer
*/
util::Map<std::string, ServiceBooking*> ServiceManagementService::getServiceBookings(const std::string& customerID)
{
util::Map<std::string, ServiceBooking*> currentServiceBookings = getServiceBookings();
util::Map<std::string, ServiceBooking*> 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<std::string, JobCard*> containing job cards assigned to the technician
*/
util::Map<std::string, JobCard*> ServiceManagementService::getJobCards(const std::string& technicianID)
{
util::Map<std::string, JobCard*> jobCards = m_dataStore.getJobCards();
util::Map<std::string, JobCard*> 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: hasAllJobCardsinServiceBookingCompleted (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<std::string, JobCard*>&, map of assigned job cards
Returns:
- bool: True if all job cards are completed, False otherwise
*/
static bool hasAllJobCardsinServiceBookingCompleted(std::string bookingId, util::Map<std::string, JobCard*>& 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<std::string, JobCard*> 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 occured or job already completed.");
}
if (!jobStatusUpdated)
{
throw std::runtime_error("Failed to complete the job, some error occured or job already completed.");
}
serviceBookingCompleted = hasAllJobCardsinServiceBookingCompleted(currentJob->getBookingId(), currentAssignedJobs);
if (serviceBookingCompleted)
{
currentJob->getBooking()->setStatus(util::ServiceJobStatus::COMPLETED);
paymentManagementService.generateInvoice(currentJob->getBooking());
std::string title = "Service Booking completed,Invoice Generated.\n";
std::string message = "Services completed for the booking and invoice generated.\n";
sendNotification(currentJob->getBooking()->getCustomer(), title, message);
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<std::string, Service*> selectedServices = comboPackage->getServices();
ServiceBooking* serviceBooking = Factory::getObject<ServiceBooking>(util::ServiceJobStatus::STARTED, 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;
sendNotification(authenticatedUser,
"Combo Package Service Booking succeeded",
"Your service booking for the combo package has been successfully placed with ID " + serviceBooking->getId());
}
@@ -1,3 +1,11 @@
/*
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 <string>
#include "Map.h"
@@ -22,7 +30,6 @@ public:
void purchaseComboPackage(const std::string& comboPackageID, const std::string& vehicleNumber, const std::string& vehicleBrand, const std::string& vehicleModel);
util::Map<std::string, ServiceBooking*> getServiceBookings();
util::Map<std::string, ServiceBooking*> 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<std::string>& inventoryItemIDs, double laborCost);
void removeService(const std::string& serviceID);
@@ -1,31 +1,112 @@
#include "UserManagementService.h"
/*
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 <stdexcept>
#include "User.h"
#include "Enums.h"
#include "Config.h"
#include "UserManagementService.h"
#include "ServiceManagementService.h"
#include "PaymentManagementService.h"
#include "InventoryManagementService.h"
#include "Factory.h"
util::Map<std::string, User*> UserManagementService::getUsers(util::UserType type)
/*
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()
{
util::Map<std::string, User*>& currentUsers = m_dataStore.getUsers();
util::Map<std::string, User*> filteredUsersMap;
for (int iterator = 0; iterator < currentUsers.getSize(); iterator++)
auto& usersMap = m_dataStore.getUsers();
int usersMapSize = usersMap.getSize();
bool isAdminFound = false;
for (int index = 0; index < usersMapSize; index++)
{
User* currentUser = currentUsers.getValueAt(iterator);
if (currentUser->getUserType() == type)
User* user = usersMap.getValueAt(index);
if (user && user->getUserType() == util::UserType::ADMIN)
{
filteredUsersMap.insert(currentUser->getId(), currentUser);
isAdminFound = true;
break;
}
}
return filteredUsersMap;
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);
}
}
User* UserManagementService::getUser(const std::string& userID)
/*
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 - users username
const std::string& name - users name
const std::string& password - users password
const std::string& email - users email address
const std::string& phone - users 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)
{
util::Map<std::string, User*>& currentUsers = m_dataStore.getUsers();
for (int iterator = 0; iterator < currentUsers.getSize(); iterator++)
{
User* currentUser = currentUsers.getValueAt(iterator);
if (currentUser->getId() == userID)
InventoryManagementService inventoryManagementService;
PaymentManagementService paymentManagementService;
ServiceManagementService serviceManagementService;
auto& usersMap = m_dataStore.getUsers();
int index = usersMap.findIf(
[&](const std::string&, User* user)
{
return currentUser;
return user->getUserName() == username;
}
);
if (index != -1)
{
throw std::runtime_error("Username already exists");
}
User* newUser = Factory::getObject<User>(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);
}
return nullptr;
}
/*
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!");
}
User* user = usersMap.getValueAt(index);
user->setEmail(email);
user->setPhone(phone);
}
@@ -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 <string>
#include "Map.h"
@@ -13,7 +21,7 @@ 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<std::string, User*> getUsers();
util::Map<std::string, User*> getUsers(util::UserType type);
@@ -21,4 +29,5 @@ public:
void removeUser(const std::string& userID);
util::Vector<Notification*> getUserNotifications(const std::string& userID);
void deleteNotification(const std::string& notificationID, const std::string& userID);
void ensureAdminExists();
};
@@ -0,0 +1,21 @@
/*
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:19-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 = "";
constexpr const char* DEFAULT_ADMIN_EMAIL = "admin@vss";
constexpr const char* DEFAULT_ADMIN_PHONE = "0000000000";
}
}
@@ -24,7 +24,6 @@ namespace util
enum class ServiceJobStatus
{
PENDING,
STARTED,
COMPLETED
};
@@ -126,8 +125,6 @@ namespace util
return "STARTED";
case ServiceJobStatus::COMPLETED:
return "COMPLETED";
case ServiceJobStatus::PENDING:
return "STARTED";
}
throw std::invalid_argument("Invalid ServiceJobStatus");
}
@@ -0,0 +1,49 @@
/*
File: Utility.h
Description: Header file declaring utility functions used across the system,
including cost calculation for services and combo packages.
Author: Trenser
Date:19-May-2026
*/
#pragma once
#include "Service.h"
#include "InventoryItem.h"
/*
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;
}
@@ -1,12 +1,6 @@
#include <iomanip>
#include "AdminMenu.h"
#include "Service.h"
#include "InputHelper.h"
#include "OutputHelper.h"
#include "ServiceBooking.h"
#include "Enums.h"
#include "Service.h"
#include "InventoryItem.h"
void AdminMenu::showMenu()
{
@@ -62,368 +56,16 @@ void AdminMenu::checkStockAvailability()
{
}
/*
Function: listServiceBookings (static helper)
Description: Lists all pending service bookings and maps them to indices for selection.
Parameters:
- currentBookings: util::Map<std::string, const ServiceBooking*>&, current bookings
- bookingsSize: int&, number of bookings
- serviceBookingsMap: util::Map<int, const ServiceBooking*>&, map of indexed bookings
Returns:
- bool: True if pending services exist, False otherwise
*/
static bool listServiceBookings(util::Map<std::string, const ServiceBooking*>& currentBookings, int& bookingsSize, util::Map<int, const ServiceBooking*>& serviceBookingsMap)
{
int currentIndex = 1;
bool hasPendingService = false;
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::setw(20) << "Technician"
<< std::setw(15) << "TechID"
<< std::endl;
for (int iterator = 0; iterator < bookingsSize; iterator++)
{
const ServiceBooking* currentBooking = currentBookings.getValueAt(iterator);
if (currentBooking && currentBooking->getStatus() == util::ServiceJobStatus::PENDING)
{
hasPendingService = true;
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::setw(20) << (currentBooking->getAssignedTechnician() == nullptr ? "Null" : currentBooking->getAssignedTechnician()->getName())
<< std::setw(15) << (currentBooking->getAssignedTechnicianId().empty() ? "Null" : currentBooking->getAssignedTechnicianId())
<< std::endl;
serviceBookingsMap.insert(currentIndex++, currentBooking);
}
}
if (!hasPendingService)
{
std::cout << "No pending service available." << std::endl;
return false;
}
return true;
}
/*
Function: selectPendingServiceBookings (static helper)
Description: Allows selection of a pending service booking by index.
Parameters:
- serviceBookingsMap: util::Map<int, const ServiceBooking*>&, map of indexed bookings
Returns:
- const ServiceBooking*: Pointer to the selected booking, or nullptr if invalid
*/
static const ServiceBooking* selectPendingServiceBookings(util::Map<int, const ServiceBooking*>& serviceBookingsMap)
{
int userInputIndex;
std::cout << "Enter a valid service index: ";
util::read(userInputIndex);
if (serviceBookingsMap.find(userInputIndex) != -1)
{
return serviceBookingsMap.getValueAt(userInputIndex);
}
else
{
std::cout << "Enter a valid index.";
return nullptr;
}
}
/*
Function: listAvailableTechnicians (static helper)
Description: Lists all available technicians and maps them to indices for selection.
Parameters:
- currentAvailableTechnicians: util::Map<std::string, const User*>, available technicians
- numberOfTechnicians: int, number of technicians
- currentAvailableTechniciansMap: util::Map<int, const User*>&, map of indexed technicians
Returns:
- void
*/
static void listAvailableTechnicians( util::Map<std::string, const User*> currentAvailableTechnicians, int numberOfTechnicians, util::Map<int, const User*>& currentAvailableTechniciansMap)
{
bool hasTechnicians = false;
int currentIndex = 1;
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.";
}
}
/*
Function: selectTechnician (static helper)
Description: Allows selection of a technician by index.
Parameters:
- currentAvailableTechniciansMap: util::Map<int, const User*>&, map of indexed technicians
Returns:
- const User*: Pointer to the selected technician, or nullptr if invalid
*/
static const User* selectTechnician(util::Map<int, const User*>& currentAvailableTechniciansMap)
{
int userInputIndex;
util::read(userInputIndex);
if (currentAvailableTechniciansMap.find(userInputIndex) != -1)
{
return currentAvailableTechniciansMap.getValueAt(userInputIndex);
}
else
{
std::cout << "Enter a valid index.";
return nullptr;
}
}
/*
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::string selectedService;
bool hasPendingService = false;
auto currentBookings = m_controller.getServiceBookings();
auto availableTechnicians = m_controller.getUsers(util::UserType::TECHNICIAN);
int bookingsSize = currentBookings.getSize();
util::Map<int, const ServiceBooking*> serviceBookingsMap;
util::Map<int, const User*> currentAvailableTechniciansMap;
if (listServiceBookings(currentBookings, 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());
}
}
}
else
{
std::cout << "No technicians are currently available.";
}
}
}
}
/*
Function: selectInventoryItems (static helper)
Description: Allows selection of inventory items by index for creating a service.
Parameters:
- currentInventoryItems: util::Map<std::string, const InventoryItem*>&, available inventory items
- selectedInventoryItems: util::Vector<std::string>&, vector to store selected item IDs
Returns:
- void
*/
static void selectInventoryItems(util::Map<std::string, const InventoryItem*>& currentInventoryItems, util::Vector<std::string>& selectedInventoryItems)
{
bool doRun = true, hasInventoryItems = false;
util::Map<int, const InventoryItem*> currentInventoryMap;
int currentIndex = 1;
int choice;
if (currentInventoryItems.getSize() == 0)
{
std::cout << "Inventory empty.";
}
while (doRun)
{
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->getState() == util::State::INACTIVE)
{
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;
hasInventoryItems = true;
currentInventoryMap.insert(currentIndex++, currentInventoryItem);
}
if (!hasInventoryItems)
{
std::cout << "No items present in the inventory." << std::endl;
doRun = false;
break;
}
std::cout << "Select the item (Index) or enter -1 to exit: ";
util::read(choice);
if (choice == -1)
{
doRun = false;
}
else if (currentInventoryMap.find(choice) != -1)
{
selectedInventoryItems.push_back(currentInventoryMap.getValueAt(choice)->getId());
std::cout << "Item added successfully." << std::endl;
}
else
{
std::cout << "Enter a valid integer." << std::endl;
}
}
}
/*
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::string serviceName;
double labourCost;
std::cout << "Enter the service name: ";
util::read(serviceName);
util::Map<std::string, const InventoryItem*> currentInventoryItems = m_controller.getInventoryItems();
util::Vector<std::string> selectedInventoryItems;
selectInventoryItems(currentInventoryItems,selectedInventoryItems);
std::cout << "Enter the labour cost: ";
util::read(labourCost);
m_controller.createService(serviceName, selectedInventoryItems, labourCost);
std::cout << "Service created sucessfully.\n";
}
/*
Function: selectServicesToRemove (static helper)
Description: Allows selection of a service to remove by index.
Parameters:
- currentServices: util::Map<std::string, const Service*>, available services
Returns:
- std::string: ID of the selected service, or empty string if invalid
*/
static std::string selectServicesToRemove(util::Map<std::string, const Service*> currentServices)
{
util::Map<int, const Service*> currentServicesMap;
bool hasServices = false;
int currentIndex = 1, choice;
std::cout << std::left
<< std::setw(6) << "Index"
<< std::setw(12) << "Service ID"
<< std::setw(20) << "Name"
<< std::setw(10) << "Labor Cost"
<< std::endl;
for (int iterator = 0; iterator < currentServices.getSize(); iterator++)
{
const Service* currentService = currentServices.getValueAt(iterator);
if (currentService->getState() == util::State::INACTIVE)
{
continue;
}
std::cout << std::left
<< std::setw(6) << currentIndex
<< std::setw(12) << currentService->getId()
<< std::setw(20) << currentService->getName()
<< std::setw(10) << currentService->getLaborCost()
<< std::endl;
hasServices = true;
currentServicesMap.insert(currentIndex++, currentService);
}
if (!hasServices)
{
std::cout << "No services currently available." << std::endl;
return "";
}
std::cout << "Enter your choice: ";
util::read(choice);
if (currentServicesMap.find(choice) != -1)
{
return currentServicesMap.getValueAt(currentServicesMap.find(choice))->getId();
}
else
{
std::cout << "Invalid choice." << std::endl;
return "";
}
}
/*
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::string selectedServiceID;
util::Map<std::string, const Service*> currentServices = m_controller.getServices();
selectedServiceID = selectServicesToRemove(currentServices);
if (selectedServiceID != "")
{
m_controller.removeService(selectedServiceID);
std::cout << "Service removed sucessfully.";
}
else
{
std::cout << "Failed to remove service.";
}
}
void AdminMenu::addTechnician()
@@ -1,109 +1,339 @@
/*
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 <iomanip>
#include "CustomerMenu.h"
#include "Service.h"
#include "InventoryItem.h"
#include "ComboPackage.h"
#include "Service.h"
#include "InputHelper.h"
#include "OutputHelper.h"
#include "User.h"
#include "ServiceBooking.h"
#include "Enums.h"
#include "Validator.h"
#include "Vector.h"
#include "Utility.h"
#include "Map.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();
}
}
}
bool CustomerMenu::handleOperation(int choice)
{
return false;
}
void CustomerMenu::logout()
{
}
void CustomerMenu::changePassword()
{
}
void CustomerMenu::updateDetails()
{
}
void CustomerMenu::selectService()
{
}
void CustomerMenu::selectComboPackage()
{
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: viewServiceHistory
Description: Displays the customers past service bookings in tabular format,
including booking ID, technician, vehicle details, discount percentage, and status.
Parameters:
- None
Returns:
- void
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)
{
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()
{
std::string newPassword;
util::clear();
std::cout << "Enter new password: ";
util::read(newPassword);
m_controller.changePassword(newPassword);
if (!util::isPasswordValid(newPassword))
{
std::cout << "Error: Password is not strong enough!";
util::pressEnter();
return;
}
std::cout << "Password changed successfully";
util::pressEnter();
}
/*
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 << "Enter new email: ";
util::read(email);
if (!util::isEmailValid(email))
{
std::cout << "Error: Email is invalid!";
util::pressEnter();
return;
}
std::cout << "Enter new phone: ";
util::read(phone);
if (!util::isPhoneNumberValid(phone))
{
std::cout << "Error: Phone number is invalid!";
util::pressEnter();
return;
}
m_controller.updateUserDetails(email, phone);
std::cout << "Profile details updated successfully";
util::pressEnter();
}
/*
Function: selectServiceFromServices
Description: Displays active services and allows the customer to select one by index.
Parameter: const util::Map<std::string, const Service*>& services - list of services
Return type: const Service* - selected service
*/
static const Service* selectServiceFromServices(const util::Map<std::string, const Service*>& services)
{
util::Map<int, const Service*> 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->getState() != util::State::ACTIVE)
{
continue;
}
activeServicesMap.insert(currentIndex, currentService);
double partsCost = 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: 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;
auto services = m_controller.getServices();
util::Vector<std::string> selectedServices;
util::clear();
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 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: selectComboPackageFromPackages
Description: Displays active combo packages and allows the customer to select one by index.
Parameter: const util::Map<std::string, const ComboPackage*>& comboPackages - list of combo packages
Return type: const ComboPackage* - selected combo package
*/
static const ComboPackage* selectComboPackageFromPackages(const util::Map<std::string, const ComboPackage*>& comboPackages)
{
util::Map<int, const ComboPackage*> activeComboPackages;
int currentIndex = 1;
int userInputIndex;
std::cout << std::left
<< std::setw(10) << "Index"
<< std::setw(15) << "Combo Package ID"
<< std::setw(15) << "Combo Package Name"
<< std::setw(15) << "Estimate Cost"
<< std::endl;
for (int index = 0; index < comboPackages.getSize(); index++)
{
const ComboPackage* currentComboPackage = comboPackages.getValueAt(index);
if (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(25) << currentComboPackage->getPackageName()
<< std::setw(15) << 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: 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;
auto comboPackages = m_controller.getComboPackages();
util::clear();
const ComboPackage* selectedComboPackage = selectComboPackageFromPackages(comboPackages);
if (selectedComboPackage == nullptr)
{
std::cout << "Failed to book combo package!";
util::pressEnter();
return;
}
util::clear();
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";
util::pressEnter();
}
void CustomerMenu::viewServiceHistory()
{
util::clear();
bool hasServiceHistory = false;
const User* currentUser = m_controller.getAuthenticatedUser();
std::string currentUserID = currentUser->getId();
util::Map<std::string, const ServiceBooking*> serviceBookingsByCurrentUser = m_controller.getServiceBookingsByUser(currentUserID);
if (serviceBookingsByCurrentUser.getSize() != 0)
{
std::cout << std::left
<< std::setw(12) << "Booking ID"
<< std::setw(20) << "Technician"
<< std::setw(15) << "Vehicle Brand"
<< std::setw(15) << "Vehicle Number"
<< std::setw(15) << "Vehicle Model"
<< std::setw(10) << "Discount %"
<< std::setw(12) << "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(12) << currentBooking->getId()
<< std::setw(20) << technicianName
<< std::setw(15) << currentBooking->getVehicleBrand()
<< std::setw(15) << currentBooking->getVehicleNumber()
<< std::setw(15) << currentBooking->getVehicleModel()
<< std::setw(10) << currentBooking->getDiscountPercentage()
<< std::setw(12) << util::getServiceJobStatusString(currentBooking->getStatus())
<< std::endl;
hasServiceHistory = true;
}
}
if (!hasServiceHistory)
{
std::cout << "No history available." << std::endl;
}
}
void CustomerMenu::completePayments()
@@ -1,3 +1,12 @@
/*
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"
@@ -0,0 +1,62 @@
/*
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:19-May-2026
*/
#pragma once
#include <string>
#include <iomanip>
#include "Notification.h"
#include "Map.h"
#include "InputHelper.h"
#include "OutputHelper.h"
/*
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<const Notification*>& notifications - list of notifications
Return type: const Notification* - pointer to the selected notification
*/
inline const Notification* selectNotification(const util::Vector<const Notification*>& notifications)
{
if (notifications.getSize() == 0)
{
std::cout << "No notifications available." << std::endl;
return nullptr;
}
std::cout << std::left
<< std::setw(6) << "Index"
<< std::setw(15) << "ID"
<< std::setw(30) << "Title"
<< std::setw(25) << "Timestamp"
<< std::endl;
int currentIndex = 1;
for (int iterator = 0; iterator < notifications.getSize(); iterator++)
{
const Notification* currentNotification = notifications[iterator];
if (currentNotification)
{
std::cout << std::left
<< std::setw(6) << currentIndex
<< std::setw(15) << currentNotification->getId()
<< std::setw(30) << currentNotification->getTitle()
<< std::setw(25) << currentNotification->getCreatedAt().toString()
<< std::endl;
currentIndex++;
}
}
int selectedIndex;
std::cout << "Select notification: ";
util::read(selectedIndex);
if (selectedIndex < 1 || selectedIndex > notifications.getSize())
{
std::cout << "Invalid selection." << std::endl;
return nullptr;
}
return notifications[selectedIndex - 1];
}
@@ -1,10 +1,6 @@
#include <iomanip>
#include "TechnicianMenu.h"
#include "InputHelper.h"
#include "OutputHelper.h"
#include "JobCard.h"
#include "Enums.h"
#include "Service.h"
void TechnicianMenu::showMenu()
{
@@ -35,86 +31,8 @@ bool TechnicianMenu::handleOperation(int choice)
return false;
}
/*
Function: selectJobCardToComplete (static helper)
Description: Lists all incomplete job cards assigned to the technician and allows selection by index.
Parameters:
- 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:
- std::string: ID of the selected job card, or empty string if none selected
*/
static std::string selectJobCardToComplete(util::Map<std::string, const JobCard*>& assignedJobCards, util::Map<int, const JobCard*>& incompleteJobCards)
{
int currentIndex = 1;
int choice;
bool hasIncompleteJobCard = false;
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;
hasIncompleteJobCard = true;
incompleteJobCards.insert(currentIndex++, currentJobCard);
}
}
if (!hasIncompleteJobCard)
{
std::cout << "No pending jobs are present.\n";
return "";
}
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 choice.\n";
return "";
}
}
/*
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::Map<std::string, const JobCard*> assignedJobCards = m_controller.getJobCardsByUser();
util::Map<int, const JobCard*> incompleteJobCards;
std::cout << "Jobs to be completed.\n";
std::string selectedJobID = selectJobCardToComplete(assignedJobCards, incompleteJobCards);
if (selectedJobID == "")
{
std::cout << "Failed to complete the job.\n";
}
else
{
m_controller.completeJob(selectedJobID);
std::cout << "Job marked as completed.\n";
}
}
void TechnicianMenu::viewNotifications()
@@ -1,7 +1,25 @@
/*
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 "UserInterface.h"
#include "InputHelper.h"
#include "OutputHelper.h"
#include "Enums.h"
#include "User.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;
@@ -26,6 +44,12 @@ void UserInterface::run()
}
}
/*
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 +70,90 @@ 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 << "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 != nullptr)
{
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
{
std::cout << "\nError: Invalid Username or Password";
}
}
/*
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 << "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();
}
@@ -1,3 +1,12 @@
/*
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"